From a6c9b7c7a0eff81ae787794f847808a12d29d3ec Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Mon, 22 Oct 2018 12:28:45 -0700 Subject: [PATCH 1/3] Queue Storage Tasks on separate queue --- .../Integration/FIRStorageIntegrationTests.m | 89 +++++++ .../Tests/Unit/FIRStorageDeleteTests.m | 8 + .../Tests/Unit/FIRStorageGetMetadataTests.m | 9 + .../Unit/FIRStorageUpdateMetadataTests.m | 9 + Firebase/Storage/FIRStorage.m | 1 + Firebase/Storage/FIRStorageDeleteTask.m | 52 ++-- Firebase/Storage/FIRStorageDownloadTask.m | 214 +++++++-------- .../Storage/FIRStorageGetDownloadURLTask.m | 79 +++--- Firebase/Storage/FIRStorageGetMetadataTask.m | 70 ++--- Firebase/Storage/FIRStorageObservableTask.m | 5 +- Firebase/Storage/FIRStorageReference.m | 8 + Firebase/Storage/FIRStorageTask.m | 16 +- .../Storage/FIRStorageUpdateMetadataTask.m | 88 ++++--- Firebase/Storage/FIRStorageUploadTask.m | 245 +++++++++--------- .../Storage/Private/FIRStorageDeleteTask.h | 1 + .../Private/FIRStorageDownloadTask_Private.h | 2 + .../Private/FIRStorageGetDownloadURLTask.h | 1 + .../Private/FIRStorageGetMetadataTask.h | 1 + .../FIRStorageObservableTask_Private.h | 4 +- .../Storage/Private/FIRStorageTask_Private.h | 14 +- .../Private/FIRStorageUpdateMetadataTask.h | 1 + .../Private/FIRStorageUploadTask_Private.h | 4 + Firebase/Storage/Private/FIRStorage_Private.h | 2 + 23 files changed, 564 insertions(+), 359 deletions(-) diff --git a/Example/Storage/Tests/Integration/FIRStorageIntegrationTests.m b/Example/Storage/Tests/Integration/FIRStorageIntegrationTests.m index b20108a38ac..420b8d87919 100644 --- a/Example/Storage/Tests/Integration/FIRStorageIntegrationTests.m +++ b/Example/Storage/Tests/Integration/FIRStorageIntegrationTests.m @@ -198,6 +198,26 @@ - (void)testUnauthenticatedSimplePutData { [self waitForExpectations]; } +- (void)testUnauthenticatedSimplePutDataInBackgroundQueue { + XCTestExpectation *expectation = + [self expectationWithDescription:@"testUnauthenticatedSimplePutDataInBackgroundQueue"]; + FIRStorageReference *ref = [self.storage referenceWithPath:@"ios/public/testBytesUpload"]; + + NSData *data = [@"Hello World" dataUsingEncoding:NSUTF8StringEncoding]; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [ref putData:data + metadata:nil + completion:^(FIRStorageMetadata *metadata, NSError *error) { + XCTAssertNotNil(metadata, "Metadata should not be nil"); + XCTAssertNil(error, "Error should be nil"); + [expectation fulfill]; + }]; + }); + + [self waitForExpectations]; +} + - (void)testUnauthenticatedSimplePutEmptyData { XCTestExpectation *expectation = [self expectationWithDescription:@"testUnauthenticatedSimplePutEmptyData"]; @@ -369,6 +389,24 @@ - (void)testUnauthenticatedSimpleGetData { [self waitForExpectations]; } +- (void)testUnauthenticatedSimpleGetDataInBackgroundQueue { + XCTestExpectation *expectation = + [self expectationWithDescription:@"testUnauthenticatedSimpleGetDataInBackgroundQueue"]; + + FIRStorageReference *ref = [self.storage referenceWithPath:@"ios/public/1mb"]; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [ref dataWithMaxSize:1 * 1024 * 1024 + completion:^(NSData *data, NSError *error) { + XCTAssertNotNil(data, "Data should not be nil"); + XCTAssertNil(error, "Error should be nil"); + [expectation fulfill]; + }]; + }); + + [self waitForExpectations]; +} + - (void)testUnauthenticatedSimpleGetDataTooSmall { XCTestExpectation *expectation = [self expectationWithDescription:@"testUnauthenticatedSimpleGetDataTooSmall"]; @@ -615,6 +653,57 @@ - (void)testUnauthenticatedResumeGetFile { XCTAssertEqualWithAccuracy(sqrt(INT_MAX - 499), computationResult, 0.1); } +- (void)testUnauthenticatedResumeGetFileInBackgroundQueue { + XCTestExpectation *expectation = + [self expectationWithDescription:@"testUnauthenticatedResumeGetFileInBackgroundQueue"]; + + FIRStorageReference *ref = [self.storage referenceWithPath:@"ios/public/1mb"]; + + NSURL *tmpDirURL = [NSURL fileURLWithPath:NSTemporaryDirectory()]; + NSURL *fileURL = + [[tmpDirURL URLByAppendingPathComponent:@"hello"] URLByAppendingPathExtension:@"txt"]; + + __block long resumeAtBytes = 256 * 1024; + __block long downloadedBytes = 0; + __block double computationResult = 0; + + FIRStorageDownloadTask *task = [ref writeToFile:fileURL]; + + [task observeStatus:FIRStorageTaskStatusSuccess + handler:^(FIRStorageTaskSnapshot *snapshot) { + XCTAssertEqualObjects([snapshot description], @""); + [expectation fulfill]; + }]; + + [task observeStatus:FIRStorageTaskStatusProgress + handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) { + XCTAssertTrue([[snapshot description] containsString:@"State: Progress"] || + [[snapshot description] containsString:@"State: Resume"]); + NSProgress *progress = snapshot.progress; + XCTAssertGreaterThanOrEqual(progress.completedUnitCount, downloadedBytes); + downloadedBytes = progress.completedUnitCount; + if (progress.completedUnitCount > resumeAtBytes) { + NSLog(@"Pausing"); + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [task pause]; + }); + resumeAtBytes = INT_MAX; + } + }]; + + [task observeStatus:FIRStorageTaskStatusPause + handler:^(FIRStorageTaskSnapshot *snapshot) { + XCTAssertEqualObjects([snapshot description], @""); + NSLog(@"Resuming"); + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [task resume]; + }); + }]; + + [self waitForExpectations]; + XCTAssertEqual(INT_MAX, resumeAtBytes); +} + - (void)waitForExpectations { [self waitForExpectationsWithTimeout:kFIRStorageIntegrationTestTimeout handler:^(NSError *_Nullable error) { diff --git a/Example/Storage/Tests/Unit/FIRStorageDeleteTests.m b/Example/Storage/Tests/Unit/FIRStorageDeleteTests.m index 11034ffff8e..bae7657aaeb 100644 --- a/Example/Storage/Tests/Unit/FIRStorageDeleteTests.m +++ b/Example/Storage/Tests/Unit/FIRStorageDeleteTests.m @@ -18,6 +18,7 @@ @interface FIRStorageDeleteTests : XCTestCase @property(strong, nonatomic) GTMSessionFetcherService *fetcherService; +@property(nonatomic) dispatch_queue_t dispatchQueue; @property(strong, nonatomic) FIRStorageMetadata *metadata; @property(strong, nonatomic) FIRStorage *storage; @property(strong, nonatomic) id mockApp; @@ -45,6 +46,8 @@ - (void)setUp { fetcherService:self.fetcherService authProvider:nil]; + self.dispatchQueue = dispatch_queue_create("Test dispatch queue", DISPATCH_QUEUE_SERIAL); + self.storage = [FIRStorage storageForApp:self.mockApp]; } @@ -76,6 +79,7 @@ - (void)testFetcherConfiguration { FIRStorageReference *ref = [[FIRStorageReference alloc] initWithStorage:self.storage path:path]; FIRStorageDeleteTask *task = [[FIRStorageDeleteTask alloc] initWithReference:ref fetcherService:self.fetcherService + dispatchQueue:self.dispatchQueue completion:^(NSError *error) { [expectation fulfill]; }]; @@ -92,6 +96,7 @@ - (void)testSuccessfulFetch { FIRStorageReference *ref = [[FIRStorageReference alloc] initWithStorage:self.storage path:path]; FIRStorageDeleteTask *task = [[FIRStorageDeleteTask alloc] initWithReference:ref fetcherService:self.fetcherService + dispatchQueue:self.dispatchQueue completion:^(NSError *error) { XCTAssertEqual(error, nil); [expectation fulfill]; @@ -111,6 +116,7 @@ - (void)testUnsuccessfulFetchUnauthenticated { FIRStorageDeleteTask *task = [[FIRStorageDeleteTask alloc] initWithReference:ref fetcherService:self.fetcherService + dispatchQueue:self.dispatchQueue completion:^(NSError *error) { XCTAssertEqual(error.code, FIRStorageErrorCodeUnauthenticated); [expectation fulfill]; @@ -130,6 +136,7 @@ - (void)testUnsuccessfulFetchUnauthorized { FIRStorageDeleteTask *task = [[FIRStorageDeleteTask alloc] initWithReference:ref fetcherService:self.fetcherService + dispatchQueue:self.dispatchQueue completion:^(NSError *error) { XCTAssertEqual(error.code, FIRStorageErrorCodeUnauthorized); [expectation fulfill]; @@ -149,6 +156,7 @@ - (void)testUnsuccessfulFetchObjectDoesntExist { FIRStorageDeleteTask *task = [[FIRStorageDeleteTask alloc] initWithReference:ref fetcherService:self.fetcherService + dispatchQueue:self.dispatchQueue completion:^(NSError *error) { XCTAssertEqual(error.code, FIRStorageErrorCodeObjectNotFound); [expectation fulfill]; diff --git a/Example/Storage/Tests/Unit/FIRStorageGetMetadataTests.m b/Example/Storage/Tests/Unit/FIRStorageGetMetadataTests.m index b7d80a64ad4..775afe2e1e3 100644 --- a/Example/Storage/Tests/Unit/FIRStorageGetMetadataTests.m +++ b/Example/Storage/Tests/Unit/FIRStorageGetMetadataTests.m @@ -18,6 +18,7 @@ @interface FIRStorageGetMetadataTests : XCTestCase @property(strong, nonatomic) GTMSessionFetcherService *fetcherService; +@property(nonatomic) dispatch_queue_t dispatchQueue; @property(strong, nonatomic) FIRStorageMetadata *metadata; @property(strong, nonatomic) FIRStorage *storage; @property(strong, nonatomic) id mockApp; @@ -45,6 +46,8 @@ - (void)setUp { fetcherService:self.fetcherService authProvider:nil]; + self.dispatchQueue = dispatch_queue_create("Test dispatch queue", DISPATCH_QUEUE_SERIAL); + self.storage = [FIRStorage storageForApp:self.mockApp]; } @@ -77,6 +80,7 @@ - (void)testFetcherConfiguration { FIRStorageGetMetadataTask *task = [[FIRStorageGetMetadataTask alloc] initWithReference:ref fetcherService:self.fetcherService + dispatchQueue:self.dispatchQueue completion:^(FIRStorageMetadata *metadata, NSError *error) { [expectation fulfill]; }]; @@ -94,6 +98,7 @@ - (void)testSuccessfulFetch { FIRStorageGetMetadataTask *task = [[FIRStorageGetMetadataTask alloc] initWithReference:ref fetcherService:self.fetcherService + dispatchQueue:self.dispatchQueue completion:^(FIRStorageMetadata *metadata, NSError *error) { XCTAssertEqualObjects(self.metadata.bucket, metadata.bucket); XCTAssertEqualObjects(self.metadata.name, metadata.name); @@ -115,6 +120,7 @@ - (void)testUnsuccessfulFetchUnauthenticated { FIRStorageGetMetadataTask *task = [[FIRStorageGetMetadataTask alloc] initWithReference:ref fetcherService:self.fetcherService + dispatchQueue:self.dispatchQueue completion:^(FIRStorageMetadata *metadata, NSError *error) { XCTAssertEqual(metadata, nil); XCTAssertEqual(error.code, FIRStorageErrorCodeUnauthenticated); @@ -135,6 +141,7 @@ - (void)testUnsuccessfulFetchUnauthorized { FIRStorageGetMetadataTask *task = [[FIRStorageGetMetadataTask alloc] initWithReference:ref fetcherService:self.fetcherService + dispatchQueue:self.dispatchQueue completion:^(FIRStorageMetadata *metadata, NSError *error) { XCTAssertEqual(metadata, nil); XCTAssertEqual(error.code, FIRStorageErrorCodeUnauthorized); @@ -155,6 +162,7 @@ - (void)testUnsuccessfulFetchObjectDoesntExist { FIRStorageGetMetadataTask *task = [[FIRStorageGetMetadataTask alloc] initWithReference:ref fetcherService:self.fetcherService + dispatchQueue:self.dispatchQueue completion:^(FIRStorageMetadata *metadata, NSError *error) { XCTAssertEqual(metadata, nil); XCTAssertEqual(error.code, FIRStorageErrorCodeObjectNotFound); @@ -175,6 +183,7 @@ - (void)testUnsuccessfulFetchBadJSON { FIRStorageGetMetadataTask *task = [[FIRStorageGetMetadataTask alloc] initWithReference:ref fetcherService:self.fetcherService + dispatchQueue:self.dispatchQueue completion:^(FIRStorageMetadata *metadata, NSError *error) { XCTAssertEqual(metadata, nil); XCTAssertEqual(error.code, FIRStorageErrorCodeUnknown); diff --git a/Example/Storage/Tests/Unit/FIRStorageUpdateMetadataTests.m b/Example/Storage/Tests/Unit/FIRStorageUpdateMetadataTests.m index 9ddcf280498..d0bfa7986b8 100644 --- a/Example/Storage/Tests/Unit/FIRStorageUpdateMetadataTests.m +++ b/Example/Storage/Tests/Unit/FIRStorageUpdateMetadataTests.m @@ -19,6 +19,7 @@ @interface FIRStorageUpdateMetadataTests : XCTestCase @property(strong, nonatomic) GTMSessionFetcherService *fetcherService; +@property(nonatomic) dispatch_queue_t dispatchQueue; @property(strong, nonatomic) FIRStorageMetadata *metadata; @property(strong, nonatomic) FIRStorage *storage; @property(strong, nonatomic) id mockApp; @@ -46,6 +47,8 @@ - (void)setUp { fetcherService:self.fetcherService authProvider:nil]; + self.dispatchQueue = dispatch_queue_create("Test dispatch queue", DISPATCH_QUEUE_SERIAL); + self.storage = [FIRStorage storageForApp:self.mockApp]; } @@ -84,6 +87,7 @@ - (void)testFetcherConfiguration { FIRStorageUpdateMetadataTask *task = [[FIRStorageUpdateMetadataTask alloc] initWithReference:ref fetcherService:self.fetcherService + dispatchQueue:self.dispatchQueue metadata:self.metadata completion:^(FIRStorageMetadata *_Nullable metadata, NSError *_Nullable error) { [expectation fulfill]; @@ -102,6 +106,7 @@ - (void)testSuccessfulFetch { FIRStorageUpdateMetadataTask *task = [[FIRStorageUpdateMetadataTask alloc] initWithReference:ref fetcherService:self.fetcherService + dispatchQueue:self.dispatchQueue metadata:self.metadata completion:^(FIRStorageMetadata *_Nullable metadata, NSError *_Nullable error) { XCTAssertEqualObjects(self.metadata.bucket, metadata.bucket); @@ -124,6 +129,7 @@ - (void)testUnsuccessfulFetchUnauthenticated { FIRStorageUpdateMetadataTask *task = [[FIRStorageUpdateMetadataTask alloc] initWithReference:ref fetcherService:self.fetcherService + dispatchQueue:self.dispatchQueue metadata:self.metadata completion:^(FIRStorageMetadata *_Nullable metadata, NSError *_Nullable error) { XCTAssertNil(metadata); @@ -145,6 +151,7 @@ - (void)testUnsuccessfulFetchUnauthorized { FIRStorageUpdateMetadataTask *task = [[FIRStorageUpdateMetadataTask alloc] initWithReference:ref fetcherService:self.fetcherService + dispatchQueue:self.dispatchQueue metadata:self.metadata completion:^(FIRStorageMetadata *_Nullable metadata, NSError *_Nullable error) { XCTAssertNil(metadata); @@ -166,6 +173,7 @@ - (void)testUnsuccessfulFetchObjectDoesntExist { FIRStorageUpdateMetadataTask *task = [[FIRStorageUpdateMetadataTask alloc] initWithReference:ref fetcherService:self.fetcherService + dispatchQueue:self.dispatchQueue metadata:self.metadata completion:^(FIRStorageMetadata *_Nullable metadata, NSError *_Nullable error) { XCTAssertNil(metadata); @@ -187,6 +195,7 @@ - (void)testUnsuccessfulFetchBadJSON { FIRStorageUpdateMetadataTask *task = [[FIRStorageUpdateMetadataTask alloc] initWithReference:ref fetcherService:self.fetcherService + dispatchQueue:self.dispatchQueue metadata:self.metadata completion:^(FIRStorageMetadata *_Nullable metadata, NSError *_Nullable error) { XCTAssertNil(metadata); diff --git a/Firebase/Storage/FIRStorage.m b/Firebase/Storage/FIRStorage.m index 65613f876b6..82dcbfa4da4 100644 --- a/Firebase/Storage/FIRStorage.m +++ b/Firebase/Storage/FIRStorage.m @@ -149,6 +149,7 @@ - (instancetype)initWithApp:(FIRApp *)app _app = app; _auth = auth; _storageBucket = bucket; + _dispatchQueue = dispatch_queue_create("com.google.firebase.storage", DISPATCH_QUEUE_SERIAL); _fetcherServiceForApp = [FIRStorage fetcherServiceForApp:_app bucket:bucket auth:auth]; _maxDownloadRetryTime = 600.0; _maxOperationRetryTime = 120.0; diff --git a/Firebase/Storage/FIRStorageDeleteTask.m b/Firebase/Storage/FIRStorageDeleteTask.m index b41f06ed9d3..5617e48120d 100644 --- a/Firebase/Storage/FIRStorageDeleteTask.m +++ b/Firebase/Storage/FIRStorageDeleteTask.m @@ -30,8 +30,9 @@ - (void)dealloc { - (instancetype)initWithReference:(FIRStorageReference *)reference fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue completion:(FIRStorageVoidError)completion { - self = [super initWithReference:reference fetcherService:service]; + self = [super initWithReference:reference fetcherService:service dispatchQueue:queue]; if (self) { _completion = [completion copy]; } @@ -39,34 +40,43 @@ - (instancetype)initWithReference:(FIRStorageReference *)reference } - (void)enqueue { - NSMutableURLRequest *request = [self.baseRequest mutableCopy]; - request.HTTPMethod = @"DELETE"; - request.timeoutInterval = self.reference.storage.maxOperationRetryTime; + __weak FIRStorageDeleteTask *weakSelf = self; + + [self dispatchAsync:^() { + FIRStorageDeleteTask *strongSelf = weakSelf; + + if (!strongSelf) { + return; + } - FIRStorageVoidError callback = _completion; - _completion = nil; + NSMutableURLRequest *request = [strongSelf.baseRequest mutableCopy]; + request.HTTPMethod = @"DELETE"; + request.timeoutInterval = strongSelf.reference.storage.maxOperationRetryTime; - GTMSessionFetcher *fetcher = [self.fetcherService fetcherWithRequest:request]; - _fetcher = fetcher; + FIRStorageVoidError callback = strongSelf->_completion; + strongSelf->_completion = nil; - fetcher.comment = @"DeleteTask"; + GTMSessionFetcher *fetcher = [strongSelf.fetcherService fetcherWithRequest:request]; + strongSelf->_fetcher = fetcher; + + fetcher.comment = @"DeleteTask"; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-retain-cycles" - _fetcherCompletion = ^(NSData *_Nullable data, NSError *_Nullable error) { - if (!self.error) { - self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference]; - } - if (callback) { - callback(self.error); - } - self->_fetcherCompletion = nil; - }; + strongSelf->_fetcherCompletion = ^(NSData *_Nullable data, NSError *_Nullable error) { + if (!self.error) { + self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference]; + } + if (callback) { + callback(self.error); + } + self->_fetcherCompletion = nil; + }; #pragma clang diangostic pop - __weak FIRStorageDeleteTask *weakSelf = self; - [fetcher beginFetchWithCompletionHandler:^(NSData *_Nullable data, NSError *_Nullable error) { - weakSelf.fetcherCompletion(data, error); + [fetcher beginFetchWithCompletionHandler:^(NSData *_Nullable data, NSError *_Nullable error) { + weakSelf.fetcherCompletion(data, error); + }]; }]; } diff --git a/Firebase/Storage/FIRStorageDownloadTask.m b/Firebase/Storage/FIRStorageDownloadTask.m index 91da4b72700..bf7f6d7821b 100644 --- a/Firebase/Storage/FIRStorageDownloadTask.m +++ b/Firebase/Storage/FIRStorageDownloadTask.m @@ -27,8 +27,9 @@ @implementation FIRStorageDownloadTask - (instancetype)initWithReference:(FIRStorageReference *)reference fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue file:(nullable NSURL *)fileURL { - self = [super initWithReference:reference fetcherService:service]; + self = [super initWithReference:reference fetcherService:service dispatchQueue:queue]; if (self) { _fileURL = [fileURL copy]; _progress = [NSProgress progressWithTotalUnitCount:0]; @@ -45,97 +46,102 @@ - (void)enqueue { } - (void)enqueueWithData:(nullable NSData *)resumeData { - NSAssert([NSThread isMainThread], - @"Download attempting to execute on non main queue! Please " - @"only execute this method on the main queue."); - self.state = FIRStorageTaskStateQueueing; - NSMutableURLRequest *request = [self.baseRequest mutableCopy]; - request.HTTPMethod = @"GET"; - request.timeoutInterval = self.reference.storage.maxDownloadRetryTime; - NSURLComponents *components = - [NSURLComponents componentsWithURL:request.URL resolvingAgainstBaseURL:NO]; - [components setQuery:@"alt=media"]; - request.URL = components.URL; - - GTMSessionFetcher *fetcher; - if (resumeData) { - fetcher = [GTMSessionFetcher fetcherWithDownloadResumeData:resumeData]; - fetcher.comment = @"Resuming DownloadTask"; - } else { - fetcher = [self.fetcherService fetcherWithRequest:request]; - fetcher.comment = @"Starting DownloadTask"; - } - __weak FIRStorageDownloadTask *weakSelf = self; - [fetcher setResumeDataBlock:^(NSData *data) { - if (data) { - FIRStorageDownloadTask *strongSelf = weakSelf; - strongSelf->_downloadData = data; + [self dispatchAsync:^() { + FIRStorageDownloadTask *strongSelf = weakSelf; + + if (!strongSelf) { + return; } - }]; - fetcher.maxRetryInterval = self.reference.storage.maxDownloadRetryTime; - - if (_fileURL) { - // Handle file downloads - [fetcher setDestinationFileURL:_fileURL]; - [fetcher setDownloadProgressBlock:^(int64_t bytesWritten, int64_t totalBytesWritten, - int64_t totalBytesExpectedToWrite) { - weakSelf.state = FIRStorageTaskStateProgress; - weakSelf.progress.completedUnitCount = totalBytesWritten; - weakSelf.progress.totalUnitCount = totalBytesExpectedToWrite; - FIRStorageTaskSnapshot *snapshot = weakSelf.snapshot; - [weakSelf fireHandlersForStatus:FIRStorageTaskStatusProgress snapshot:snapshot]; - weakSelf.state = FIRStorageTaskStateRunning; - }]; - } else { - // Handle data downloads - [fetcher setReceivedProgressBlock:^(int64_t bytesWritten, int64_t totalBytesWritten) { - weakSelf.state = FIRStorageTaskStateProgress; - weakSelf.progress.completedUnitCount = totalBytesWritten; - int64_t totalLength = [[weakSelf.fetcher response] expectedContentLength]; - weakSelf.progress.totalUnitCount = totalLength; - FIRStorageTaskSnapshot *snapshot = weakSelf.snapshot; - [weakSelf fireHandlersForStatus:FIRStorageTaskStatusProgress snapshot:snapshot]; - weakSelf.state = FIRStorageTaskStateRunning; + strongSelf.state = FIRStorageTaskStateQueueing; + NSMutableURLRequest *request = [strongSelf.baseRequest mutableCopy]; + request.HTTPMethod = @"GET"; + request.timeoutInterval = strongSelf.reference.storage.maxDownloadRetryTime; + NSURLComponents *components = + [NSURLComponents componentsWithURL:request.URL resolvingAgainstBaseURL:NO]; + [components setQuery:@"alt=media"]; + request.URL = components.URL; + + GTMSessionFetcher *fetcher; + if (resumeData) { + fetcher = [GTMSessionFetcher fetcherWithDownloadResumeData:resumeData]; + fetcher.comment = @"Resuming DownloadTask"; + } else { + fetcher = [strongSelf.fetcherService fetcherWithRequest:request]; + fetcher.comment = @"Starting DownloadTask"; + } + + [fetcher setResumeDataBlock:^(NSData *data) { + if (data) { + FIRStorageDownloadTask *strong = weakSelf; + strong->_downloadData = data; + } }]; - } - _fetcher = fetcher; + fetcher.maxRetryInterval = strongSelf.reference.storage.maxDownloadRetryTime; + + if (strongSelf->_fileURL) { + // Handle file downloads + [fetcher setDestinationFileURL:strongSelf->_fileURL]; + [fetcher setDownloadProgressBlock:^(int64_t bytesWritten, int64_t totalBytesWritten, + int64_t totalBytesExpectedToWrite) { + weakSelf.state = FIRStorageTaskStateProgress; + weakSelf.progress.completedUnitCount = totalBytesWritten; + weakSelf.progress.totalUnitCount = totalBytesExpectedToWrite; + FIRStorageTaskSnapshot *snapshot = weakSelf.snapshot; + [weakSelf fireHandlersForStatus:FIRStorageTaskStatusProgress snapshot:snapshot]; + weakSelf.state = FIRStorageTaskStateRunning; + }]; + } else { + // Handle data downloads + [fetcher setReceivedProgressBlock:^(int64_t bytesWritten, int64_t totalBytesWritten) { + weakSelf.state = FIRStorageTaskStateProgress; + weakSelf.progress.completedUnitCount = totalBytesWritten; + int64_t totalLength = [[weakSelf.fetcher response] expectedContentLength]; + weakSelf.progress.totalUnitCount = totalLength; + FIRStorageTaskSnapshot *snapshot = weakSelf.snapshot; + [weakSelf fireHandlersForStatus:FIRStorageTaskStatusProgress snapshot:snapshot]; + weakSelf.state = FIRStorageTaskStateRunning; + }]; + } + + strongSelf->_fetcher = fetcher; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-retain-cycles" - _fetcherCompletion = ^(NSData *data, NSError *error) { - // Fire last progress updates - [self fireHandlersForStatus:FIRStorageTaskStatusProgress snapshot:self.snapshot]; - - // Handle potential issues with download - if (error) { - self.state = FIRStorageTaskStateFailed; - self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference]; - [self fireHandlersForStatus:FIRStorageTaskStatusFailure snapshot:self.snapshot]; + strongSelf->_fetcherCompletion = ^(NSData *data, NSError *error) { + // Fire last progress updates + [self fireHandlersForStatus:FIRStorageTaskStatusProgress snapshot:self.snapshot]; + + // Handle potential issues with download + if (error) { + self.state = FIRStorageTaskStateFailed; + self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference]; + [self fireHandlersForStatus:FIRStorageTaskStatusFailure snapshot:self.snapshot]; + [self removeAllObservers]; + self->_fetcherCompletion = nil; + return; + } + + // Download completed successfully, fire completion callbacks + self.state = FIRStorageTaskStateSuccess; + + if (data) { + self->_downloadData = data; + } + + [self fireHandlersForStatus:FIRStorageTaskStatusSuccess snapshot:self.snapshot]; [self removeAllObservers]; self->_fetcherCompletion = nil; - return; - } - - // Download completed successfully, fire completion callbacks - self.state = FIRStorageTaskStateSuccess; - - if (data) { - self->_downloadData = data; - } - - [self fireHandlersForStatus:FIRStorageTaskStatusSuccess snapshot:self.snapshot]; - [self removeAllObservers]; - self->_fetcherCompletion = nil; - }; + }; #pragma clang diagnostic pop - self.state = FIRStorageTaskStateRunning; - [self.fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { - weakSelf.fetcherCompletion(data, error); + strongSelf.state = FIRStorageTaskStateRunning; + [strongSelf.fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { + weakSelf.fetcherCompletion(data, error); + }]; }]; } @@ -147,37 +153,37 @@ - (void)cancel { } - (void)cancelWithError:(NSError *)error { - NSAssert([NSThread isMainThread], - @"Cancel attempting to execute on non main queue! Please only " - @"execute this method on the main queue."); - self.state = FIRStorageTaskStateCancelled; - [self.fetcher stopFetching]; - self.error = error; - [self fireHandlersForStatus:FIRStorageTaskStatusFailure snapshot:self.snapshot]; + __weak FIRStorageDownloadTask *weakSelf = self; + [self dispatchAsync:^() { + weakSelf.state = FIRStorageTaskStateCancelled; + [weakSelf.fetcher stopFetching]; + weakSelf.error = error; + [weakSelf fireHandlersForStatus:FIRStorageTaskStatusFailure snapshot:weakSelf.snapshot]; + }]; } - (void)pause { - NSAssert([NSThread isMainThread], - @"Pause attempting to execute on non main queue! Please only " - @"execute this method on the main queue."); - self.state = FIRStorageTaskStatePausing; - [self.fetcher stopFetching]; - // Give the resume callback a chance to run (if scheduled) - [self.fetcher waitForCompletionWithTimeout:0.001]; - self.state = FIRStorageTaskStatePaused; - FIRStorageTaskSnapshot *snapshot = self.snapshot; - [self fireHandlersForStatus:FIRStorageTaskStatusPause snapshot:snapshot]; + __weak FIRStorageDownloadTask *weakSelf = self; + [self dispatchAsync:^() { + weakSelf.state = FIRStorageTaskStatePausing; + [weakSelf.fetcher stopFetching]; + // Give the resume callback a chance to run (if scheduled) + [weakSelf.fetcher waitForCompletionWithTimeout:0.001]; + weakSelf.state = FIRStorageTaskStatePaused; + FIRStorageTaskSnapshot *snapshot = weakSelf.snapshot; + [weakSelf fireHandlersForStatus:FIRStorageTaskStatusPause snapshot:snapshot]; + }]; } - (void)resume { - NSAssert([NSThread isMainThread], - @"Resume attempting to execute on non main queue! Please only " - @"execute this method on the main queue."); - self.state = FIRStorageTaskStateResuming; - FIRStorageTaskSnapshot *snapshot = self.snapshot; - [self fireHandlersForStatus:FIRStorageTaskStatusResume snapshot:snapshot]; - self.state = FIRStorageTaskStateRunning; - [self enqueueWithData:_downloadData]; + __weak FIRStorageDownloadTask *weakSelf = self; + [self dispatchAsync:^() { + weakSelf.state = FIRStorageTaskStateResuming; + FIRStorageTaskSnapshot *snapshot = weakSelf.snapshot; + [weakSelf fireHandlersForStatus:FIRStorageTaskStatusResume snapshot:snapshot]; + weakSelf.state = FIRStorageTaskStateRunning; + [weakSelf enqueueWithData:weakSelf.downloadData]; + }]; } @end diff --git a/Firebase/Storage/FIRStorageGetDownloadURLTask.m b/Firebase/Storage/FIRStorageGetDownloadURLTask.m index 02d202e8ea3..f5f7a7ad382 100644 --- a/Firebase/Storage/FIRStorageGetDownloadURLTask.m +++ b/Firebase/Storage/FIRStorageGetDownloadURLTask.m @@ -26,8 +26,9 @@ @implementation FIRStorageGetDownloadURLTask { - (instancetype)initWithReference:(FIRStorageReference *)reference fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue completion:(FIRStorageVoidURLError)completion { - self = [super initWithReference:reference fetcherService:service]; + self = [super initWithReference:reference fetcherService:service dispatchQueue:queue]; if (self) { _completion = [completion copy]; } @@ -67,51 +68,59 @@ + (NSURL *)downloadURLFromMetadataDictionary:(NSDictionary *)dictionary { } - (void)enqueue { - NSMutableURLRequest *request = [self.baseRequest mutableCopy]; - request.HTTPMethod = @"GET"; - request.timeoutInterval = self.reference.storage.maxOperationRetryTime; + __weak FIRStorageGetDownloadURLTask *weakSelf = self; + + [self dispatchAsync:^() { + FIRStorageGetDownloadURLTask *strongSelf = weakSelf; + + if (!strongSelf) { + return; + } - FIRStorageVoidURLError callback = _completion; - _completion = nil; + NSMutableURLRequest *request = [strongSelf.baseRequest mutableCopy]; + request.HTTPMethod = @"GET"; + request.timeoutInterval = strongSelf.reference.storage.maxOperationRetryTime; - GTMSessionFetcher *fetcher = [self.fetcherService fetcherWithRequest:request]; - _fetcher = fetcher; - fetcher.comment = @"GetDownloadURLTask"; + FIRStorageVoidURLError callback = strongSelf->_completion; + strongSelf->_completion = nil; + + GTMSessionFetcher *fetcher = [strongSelf.fetcherService fetcherWithRequest:request]; + strongSelf->_fetcher = fetcher; + fetcher.comment = @"GetDownloadURLTask"; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-retain-cycles" - _fetcherCompletion = ^(NSData *data, NSError *error) { - NSURL *downloadURL; - if (error) { - if (!self.error) { - self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference]; - } - } else { - NSDictionary *responseDictionary = [NSDictionary frs_dictionaryFromJSONData:data]; - if (responseDictionary != nil) { - downloadURL = - [FIRStorageGetDownloadURLTask downloadURLFromMetadataDictionary:responseDictionary]; - if (!downloadURL) { - self.error = - [FIRStorageErrors errorWithCustomMessage:@"Failed to retrieve a download URL."]; + strongSelf->_fetcherCompletion = ^(NSData *data, NSError *error) { + NSURL *downloadURL; + if (error) { + if (!self.error) { + self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference]; } } else { - self.error = [FIRStorageErrors errorWithInvalidRequest:data]; + NSDictionary *responseDictionary = [NSDictionary frs_dictionaryFromJSONData:data]; + if (responseDictionary != nil) { + downloadURL = + [FIRStorageGetDownloadURLTask downloadURLFromMetadataDictionary:responseDictionary]; + if (!downloadURL) { + self.error = + [FIRStorageErrors errorWithCustomMessage:@"Failed to retrieve a download URL."]; + } + } else { + self.error = [FIRStorageErrors errorWithInvalidRequest:data]; + } } - } - if (callback) { - callback(downloadURL, self.error); - } + if (callback) { + callback(downloadURL, self.error); + } - self->_fetcherCompletion = nil; - }; + self->_fetcherCompletion = nil; + }; #pragma clang diagnostic pop - - __weak FIRStorageGetDownloadURLTask *weakSelf = self; - [fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { - weakSelf.fetcherCompletion(data, error); + [fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { + weakSelf.fetcherCompletion(data, error); + }]; }]; -} +}; @end diff --git a/Firebase/Storage/FIRStorageGetMetadataTask.m b/Firebase/Storage/FIRStorageGetMetadataTask.m index 752c4102640..561d769c95c 100644 --- a/Firebase/Storage/FIRStorageGetMetadataTask.m +++ b/Firebase/Storage/FIRStorageGetMetadataTask.m @@ -31,8 +31,9 @@ @implementation FIRStorageGetMetadataTask { - (instancetype)initWithReference:(FIRStorageReference *)reference fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue completion:(FIRStorageVoidMetadataError)completion { - self = [super initWithReference:reference fetcherService:service]; + self = [super initWithReference:reference fetcherService:service dispatchQueue:queue]; if (self) { _completion = [completion copy]; } @@ -44,45 +45,54 @@ - (void)dealloc { } - (void)enqueue { - NSMutableURLRequest *request = [self.baseRequest mutableCopy]; - request.HTTPMethod = @"GET"; - request.timeoutInterval = self.reference.storage.maxOperationRetryTime; + __weak FIRStorageGetMetadataTask *weakSelf = self; + + [self dispatchAsync:^() { + FIRStorageGetMetadataTask* strongSelf = weakSelf; + + if (!strongSelf) { + return; + } + + NSMutableURLRequest *request = [strongSelf.baseRequest mutableCopy]; + request.HTTPMethod = @"GET"; + request.timeoutInterval = strongSelf.reference.storage.maxOperationRetryTime; - FIRStorageVoidMetadataError callback = _completion; - _completion = nil; + FIRStorageVoidMetadataError callback = strongSelf->_completion; + strongSelf->_completion = nil; - GTMSessionFetcher *fetcher = [self.fetcherService fetcherWithRequest:request]; - _fetcher = fetcher; - fetcher.comment = @"GetMetadataTask"; + GTMSessionFetcher *fetcher = [strongSelf.fetcherService fetcherWithRequest:request]; + strongSelf->_fetcher = fetcher; + fetcher.comment = @"GetMetadataTask"; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-retain-cycles" - _fetcherCompletion = ^(NSData *data, NSError *error) { - FIRStorageMetadata *metadata; - if (error) { - if (!self.error) { - self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference]; - } - } else { - NSDictionary *responseDictionary = [NSDictionary frs_dictionaryFromJSONData:data]; - if (responseDictionary != nil) { - metadata = [[FIRStorageMetadata alloc] initWithDictionary:responseDictionary]; - [metadata setType:FIRStorageMetadataTypeFile]; + strongSelf->_fetcherCompletion = ^(NSData *data, NSError *error) { + FIRStorageMetadata *metadata; + if (error) { + if (!self.error) { + self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference]; + } } else { - self.error = [FIRStorageErrors errorWithInvalidRequest:data]; + NSDictionary *responseDictionary = [NSDictionary frs_dictionaryFromJSONData:data]; + if (responseDictionary != nil) { + metadata = [[FIRStorageMetadata alloc] initWithDictionary:responseDictionary]; + [metadata setType:FIRStorageMetadataTypeFile]; + } else { + self.error = [FIRStorageErrors errorWithInvalidRequest:data]; + } } - } - if (callback) { - callback(metadata, self.error); - } - self->_fetcherCompletion = nil; - }; + if (callback) { + callback(metadata, self.error); + } + self->_fetcherCompletion = nil; + }; #pragma clang diagnostic pop - __weak FIRStorageGetMetadataTask *weakSelf = self; - [fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { - weakSelf.fetcherCompletion(data, error); + [fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { + weakSelf.fetcherCompletion(data, error); + }]; }]; } diff --git a/Firebase/Storage/FIRStorageObservableTask.m b/Firebase/Storage/FIRStorageObservableTask.m index 4650b17f4e7..2f35e53ff12 100644 --- a/Firebase/Storage/FIRStorageObservableTask.m +++ b/Firebase/Storage/FIRStorageObservableTask.m @@ -31,8 +31,9 @@ @implementation FIRStorageObservableTask { @synthesize state = _state; - (instancetype)initWithReference:(FIRStorageReference *)reference - fetcherService:(GTMSessionFetcherService *)service { - self = [super initWithReference:reference fetcherService:service]; + fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue { + self = [super initWithReference:reference fetcherService:service dispatchQueue:queue]; if (self) { _pauseHandlers = [[NSMutableDictionary alloc] init]; _resumeHandlers = [[NSMutableDictionary alloc] init]; diff --git a/Firebase/Storage/FIRStorageReference.m b/Firebase/Storage/FIRStorageReference.m index 51eefa5ea85..99f00992473 100644 --- a/Firebase/Storage/FIRStorageReference.m +++ b/Firebase/Storage/FIRStorageReference.m @@ -167,6 +167,7 @@ - (FIRStorageUploadTask *)putData:(NSData *)uploadData FIRStorageUploadTask *task = [[FIRStorageUploadTask alloc] initWithReference:self fetcherService:_storage.fetcherServiceForApp + dispatchQueue:_storage.dispatchQueue data:uploadData metadata:metadata]; @@ -214,6 +215,7 @@ - (FIRStorageUploadTask *)putFile:(NSURL *)fileURL FIRStorageUploadTask *task = [[FIRStorageUploadTask alloc] initWithReference:self fetcherService:_storage.fetcherServiceForApp + dispatchQueue:_storage.dispatchQueue file:fileURL metadata:metadata]; @@ -247,6 +249,7 @@ - (FIRStorageDownloadTask *)dataWithMaxSize:(int64_t)size FIRStorageDownloadTask *task = [[FIRStorageDownloadTask alloc] initWithReference:self fetcherService:_storage.fetcherServiceForApp + dispatchQueue:_storage.dispatchQueue file:nil]; dispatch_queue_t callbackQueue = _storage.fetcherServiceForApp.callbackQueue; @@ -294,6 +297,7 @@ - (FIRStorageDownloadTask *)writeToFile:(NSURL *)fileURL FIRStorageDownloadTask *task = [[FIRStorageDownloadTask alloc] initWithReference:self fetcherService:_storage.fetcherServiceForApp + dispatchQueue:_storage.dispatchQueue file:fileURL]; if (completion) { dispatch_queue_t callbackQueue = _storage.fetcherServiceForApp.callbackQueue; @@ -322,6 +326,7 @@ - (void)downloadURLWithCompletion:(FIRStorageVoidURLError)completion { FIRStorageGetDownloadURLTask *task = [[FIRStorageGetDownloadURLTask alloc] initWithReference:self fetcherService:_storage.fetcherServiceForApp + dispatchQueue:_storage.dispatchQueue completion:completion]; [task enqueue]; } @@ -332,6 +337,7 @@ - (void)metadataWithCompletion:(FIRStorageVoidMetadataError)completion { FIRStorageGetMetadataTask *task = [[FIRStorageGetMetadataTask alloc] initWithReference:self fetcherService:_storage.fetcherServiceForApp + dispatchQueue:_storage.dispatchQueue completion:completion]; [task enqueue]; } @@ -341,6 +347,7 @@ - (void)updateMetadata:(FIRStorageMetadata *)metadata FIRStorageUpdateMetadataTask *task = [[FIRStorageUpdateMetadataTask alloc] initWithReference:self fetcherService:_storage.fetcherServiceForApp + dispatchQueue:_storage.dispatchQueue metadata:metadata completion:completion]; [task enqueue]; @@ -352,6 +359,7 @@ - (void)deleteWithCompletion:(nullable FIRStorageVoidError)completion { FIRStorageDeleteTask *task = [[FIRStorageDeleteTask alloc] initWithReference:self fetcherService:_storage.fetcherServiceForApp + dispatchQueue:_storage.dispatchQueue completion:completion]; [task enqueue]; } diff --git a/Firebase/Storage/FIRStorageTask.m b/Firebase/Storage/FIRStorageTask.m index 0305a39c327..a7cdefbcf89 100644 --- a/Firebase/Storage/FIRStorageTask.m +++ b/Firebase/Storage/FIRStorageTask.m @@ -26,22 +26,16 @@ @implementation FIRStorageTask -- (instancetype)init { - FIRStorage *storage = [FIRStorage storage]; - FIRStorageReference *reference = [storage reference]; - FIRStorageTask *task = - [self initWithReference:reference fetcherService:storage.fetcherServiceForApp]; - return task; -} - - (instancetype)initWithReference:(FIRStorageReference *)reference - fetcherService:(GTMSessionFetcherService *)service { + fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue { self = [super init]; if (self) { _reference = reference; _baseRequest = [FIRStorageUtils defaultRequestForPath:reference.path]; _fetcherService = service; _fetcherService.maxRetryInterval = _reference.storage.maxOperationRetryTime; + _dispatchQueue = queue; } return self; } @@ -61,4 +55,8 @@ - (FIRStorageTaskSnapshot *)snapshot { } } +- (void)dispatchAsync:(void (^)(void))block { + dispatch_async(self.dispatchQueue, block); +} + @end diff --git a/Firebase/Storage/FIRStorageUpdateMetadataTask.m b/Firebase/Storage/FIRStorageUpdateMetadataTask.m index cea4e7d8ced..cb8f6abf4ec 100644 --- a/Firebase/Storage/FIRStorageUpdateMetadataTask.m +++ b/Firebase/Storage/FIRStorageUpdateMetadataTask.m @@ -29,9 +29,10 @@ @implementation FIRStorageUpdateMetadataTask { - (instancetype)initWithReference:(FIRStorageReference *)reference fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue metadata:(FIRStorageMetadata *)metadata completion:(FIRStorageVoidMetadataError)completion { - self = [super initWithReference:reference fetcherService:service]; + self = [super initWithReference:reference fetcherService:service dispatchQueue:queue]; if (self) { _updateMetadata = [metadata copy]; _completion = [completion copy]; @@ -44,53 +45,62 @@ - (void)dealloc { } - (void)enqueue { - NSMutableURLRequest *request = [self.baseRequest mutableCopy]; - NSDictionary *updateDictionary = [_updateMetadata updatedMetadata]; - NSData *updateData = [NSData frs_dataFromJSONDictionary:updateDictionary]; - request.HTTPMethod = @"PATCH"; - request.timeoutInterval = self.reference.storage.maxOperationRetryTime; - request.HTTPBody = updateData; - NSString *typeString = @"application/json; charset=UTF-8"; - [request setValue:typeString forHTTPHeaderField:@"Content-Type"]; - NSString *lengthString = [NSString stringWithFormat:@"%zu", (unsigned long)[updateData length]]; - [request setValue:lengthString forHTTPHeaderField:@"Content-Length"]; - - FIRStorageVoidMetadataError callback = _completion; - _completion = nil; - - GTMSessionFetcher *fetcher = [self.fetcherService fetcherWithRequest:request]; - _fetcher = fetcher; + __weak FIRStorageUpdateMetadataTask *weakSelf = self; + + [self dispatchAsync:^() { + FIRStorageUpdateMetadataTask* strongSelf = weakSelf; + + if (!strongSelf) { + return; + } + + NSMutableURLRequest *request = [strongSelf.baseRequest mutableCopy]; + NSDictionary *updateDictionary = [strongSelf->_updateMetadata updatedMetadata]; + NSData *updateData = [NSData frs_dataFromJSONDictionary:updateDictionary]; + request.HTTPMethod = @"PATCH"; + request.timeoutInterval = strongSelf.reference.storage.maxOperationRetryTime; + request.HTTPBody = updateData; + NSString *typeString = @"application/json; charset=UTF-8"; + [request setValue:typeString forHTTPHeaderField:@"Content-Type"]; + NSString *lengthString = [NSString stringWithFormat:@"%zu", (unsigned long)[updateData length]]; + [request setValue:lengthString forHTTPHeaderField:@"Content-Length"]; + + FIRStorageVoidMetadataError callback = strongSelf->_completion; + strongSelf->_completion = nil; + + GTMSessionFetcher *fetcher = [strongSelf.fetcherService fetcherWithRequest:request]; + strongSelf->_fetcher = fetcher; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-retain-cycles" - _fetcherCompletion = ^(NSData *data, NSError *error) { - FIRStorageMetadata *metadata; - if (error) { - if (!self.error) { - self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference]; - } - } else { - NSDictionary *responseDictionary = [NSDictionary frs_dictionaryFromJSONData:data]; - if (responseDictionary) { - metadata = [[FIRStorageMetadata alloc] initWithDictionary:responseDictionary]; - [metadata setType:FIRStorageMetadataTypeFile]; + strongSelf->_fetcherCompletion = ^(NSData *data, NSError *error) { + FIRStorageMetadata *metadata; + if (error) { + if (!self.error) { + self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference]; + } } else { - self.error = [FIRStorageErrors errorWithInvalidRequest:data]; + NSDictionary *responseDictionary = [NSDictionary frs_dictionaryFromJSONData:data]; + if (responseDictionary) { + metadata = [[FIRStorageMetadata alloc] initWithDictionary:responseDictionary]; + [metadata setType:FIRStorageMetadataTypeFile]; + } else { + self.error = [FIRStorageErrors errorWithInvalidRequest:data]; + } } - } - if (callback) { - callback(metadata, self.error); - } - self->_fetcherCompletion = nil; - }; + if (callback) { + callback(metadata, self.error); + } + self->_fetcherCompletion = nil; + }; #pragma clang diagnostic pop - fetcher.comment = @"UpdateMetadataTask"; + fetcher.comment = @"UpdateMetadataTask"; - __weak FIRStorageUpdateMetadataTask *weakSelf = self; - [fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { - weakSelf.fetcherCompletion(data, error); + [fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { + weakSelf.fetcherCompletion(data, error); + }]; }]; } diff --git a/Firebase/Storage/FIRStorageUploadTask.m b/Firebase/Storage/FIRStorageUploadTask.m index 2c4daa962e0..8c299e79edc 100644 --- a/Firebase/Storage/FIRStorageUploadTask.m +++ b/Firebase/Storage/FIRStorageUploadTask.m @@ -29,9 +29,10 @@ @implementation FIRStorageUploadTask - (instancetype)initWithReference:(FIRStorageReference *)reference fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue data:(NSData *)uploadData metadata:(FIRStorageMetadata *)metadata { - self = [super initWithReference:reference fetcherService:service]; + self = [super initWithReference:reference fetcherService:service dispatchQueue:queue]; if (self) { _uploadMetadata = [metadata copy]; _uploadData = [uploadData copy]; @@ -46,9 +47,10 @@ - (instancetype)initWithReference:(FIRStorageReference *)reference - (instancetype)initWithReference:(FIRStorageReference *)reference fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue file:(NSURL *)fileURL metadata:(FIRStorageMetadata *)metadata { - self = [super initWithReference:reference fetcherService:service]; + self = [super initWithReference:reference fetcherService:service dispatchQueue:queue]; if (self) { _uploadMetadata = [metadata copy]; _fileURL = [fileURL copy]; @@ -68,145 +70,154 @@ - (void)dealloc { } - (void)enqueue { - NSAssert([NSThread isMainThread], - @"Upload attempting to execute on non main queue! Please only " - @"execute this method on the main queue."); - self.state = FIRStorageTaskStateQueueing; - - NSMutableURLRequest *request = [self.baseRequest mutableCopy]; - request.HTTPMethod = @"POST"; - request.timeoutInterval = self.reference.storage.maxUploadRetryTime; - NSData *bodyData = [NSData frs_dataFromJSONDictionary:[_uploadMetadata dictionaryRepresentation]]; - request.HTTPBody = bodyData; - [request setValue:@"application/json; charset=UTF-8" forHTTPHeaderField:@"Content-Type"]; - NSString *contentLengthString = - [NSString stringWithFormat:@"%zu", (unsigned long)[bodyData length]]; - [request setValue:contentLengthString forHTTPHeaderField:@"Content-Length"]; - - NSURLComponents *components = - [NSURLComponents componentsWithURL:request.URL resolvingAgainstBaseURL:NO]; - - if ([components.host isEqual:kGCSHost]) { - [components setPercentEncodedPath:[@"/upload" stringByAppendingString:components.path]]; - } + __weak FIRStorageUploadTask *weakSelf = self; - NSDictionary *queryParams = @{@"uploadType" : @"resumable", @"name" : self.uploadMetadata.path}; - [components setPercentEncodedQuery:[FIRStorageUtils queryStringForDictionary:queryParams]]; - request.URL = components.URL; - - GTMSessionUploadFetcher *uploadFetcher = - [GTMSessionUploadFetcher uploadFetcherWithRequest:request - uploadMIMEType:_uploadMetadata.contentType - chunkSize:kGTMSessionUploadFetcherStandardChunkSize - fetcherService:self.fetcherService]; - - if (_uploadData) { - [uploadFetcher setUploadData:_uploadData]; - uploadFetcher.comment = @"Data UploadTask"; - } else if (_fileURL) { - [uploadFetcher setUploadFileURL:_fileURL]; - uploadFetcher.comment = @"File UploadTask"; - } + [self dispatchAsync:^() { + FIRStorageUploadTask *strongSelf = weakSelf; - uploadFetcher.maxRetryInterval = self.reference.storage.maxUploadRetryTime; + if (!strongSelf) { + return; + } - __weak FIRStorageUploadTask *weakSelf = self; + strongSelf.state = FIRStorageTaskStateQueueing; - [uploadFetcher setSendProgressBlock:^(int64_t bytesSent, int64_t totalBytesSent, - int64_t totalBytesExpectedToSend) { - weakSelf.state = FIRStorageTaskStateProgress; - weakSelf.progress.completedUnitCount = totalBytesSent; - weakSelf.progress.totalUnitCount = totalBytesExpectedToSend; - weakSelf.metadata = self->_uploadMetadata; - [weakSelf fireHandlersForStatus:FIRStorageTaskStatusProgress snapshot:weakSelf.snapshot]; - weakSelf.state = FIRStorageTaskStateRunning; - }]; + NSMutableURLRequest *request = [strongSelf.baseRequest mutableCopy]; + request.HTTPMethod = @"POST"; + request.timeoutInterval = strongSelf.reference.storage.maxUploadRetryTime; + NSData *bodyData = + [NSData frs_dataFromJSONDictionary:[strongSelf->_uploadMetadata dictionaryRepresentation]]; + request.HTTPBody = bodyData; + [request setValue:@"application/json; charset=UTF-8" forHTTPHeaderField:@"Content-Type"]; + NSString *contentLengthString = + [NSString stringWithFormat:@"%zu", (unsigned long)[bodyData length]]; + [request setValue:contentLengthString forHTTPHeaderField:@"Content-Length"]; - _uploadFetcher = uploadFetcher; + NSURLComponents *components = + [NSURLComponents componentsWithURL:request.URL resolvingAgainstBaseURL:NO]; - // Process fetches - self.state = FIRStorageTaskStateRunning; + if ([components.host isEqual:kGCSHost]) { + [components setPercentEncodedPath:[@"/upload" stringByAppendingString:components.path]]; + } + + NSDictionary *queryParams = @{@"uploadType" : @"resumable", @"name" : self.uploadMetadata.path}; + [components setPercentEncodedQuery:[FIRStorageUtils queryStringForDictionary:queryParams]]; + request.URL = components.URL; + + GTMSessionUploadFetcher *uploadFetcher = + [GTMSessionUploadFetcher uploadFetcherWithRequest:request + uploadMIMEType:strongSelf->_uploadMetadata.contentType + chunkSize:kGTMSessionUploadFetcherStandardChunkSize + fetcherService:self.fetcherService]; + + if (strongSelf->_uploadData) { + [uploadFetcher setUploadData:strongSelf->_uploadData]; + uploadFetcher.comment = @"Data UploadTask"; + } else if (strongSelf->_fileURL) { + [uploadFetcher setUploadFileURL:strongSelf->_fileURL]; + uploadFetcher.comment = @"File UploadTask"; + } + + uploadFetcher.maxRetryInterval = self.reference.storage.maxUploadRetryTime; + + [uploadFetcher setSendProgressBlock:^(int64_t bytesSent, int64_t totalBytesSent, + int64_t totalBytesExpectedToSend) { + weakSelf.state = FIRStorageTaskStateProgress; + weakSelf.progress.completedUnitCount = totalBytesSent; + weakSelf.progress.totalUnitCount = totalBytesExpectedToSend; + weakSelf.metadata = self->_uploadMetadata; + [weakSelf fireHandlersForStatus:FIRStorageTaskStatusProgress snapshot:weakSelf.snapshot]; + weakSelf.state = FIRStorageTaskStateRunning; + }]; + + strongSelf->_uploadFetcher = uploadFetcher; + + // Process fetches + strongSelf.state = FIRStorageTaskStateRunning; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-retain-cycles" - _fetcherCompletion = ^(NSData *_Nullable data, NSError *_Nullable error) { - // Fire last progress updates - [self fireHandlersForStatus:FIRStorageTaskStatusProgress snapshot:self.snapshot]; - - // Handle potential issues with upload - if (error) { - self.state = FIRStorageTaskStateFailed; - self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference]; - self.metadata = self->_uploadMetadata; - [self fireHandlersForStatus:FIRStorageTaskStatusFailure snapshot:self.snapshot]; + strongSelf->_fetcherCompletion = ^(NSData *_Nullable data, NSError *_Nullable error) { + // Fire last progress updates + [self fireHandlersForStatus:FIRStorageTaskStatusProgress snapshot:self.snapshot]; + + // Handle potential issues with upload + if (error) { + self.state = FIRStorageTaskStateFailed; + self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference]; + self.metadata = self->_uploadMetadata; + [self fireHandlersForStatus:FIRStorageTaskStatusFailure snapshot:self.snapshot]; + [self removeAllObservers]; + self->_fetcherCompletion = nil; + return; + } + + // Upload completed successfully, fire completion callbacks + self.state = FIRStorageTaskStateSuccess; + + NSDictionary *responseDictionary = [NSDictionary frs_dictionaryFromJSONData:data]; + if (responseDictionary) { + FIRStorageMetadata *metadata = + [[FIRStorageMetadata alloc] initWithDictionary:responseDictionary]; + [metadata setType:FIRStorageMetadataTypeFile]; + self.metadata = metadata; + } else { + self.error = [FIRStorageErrors errorWithInvalidRequest:data]; + } + + [self fireHandlersForStatus:FIRStorageTaskStatusSuccess snapshot:self.snapshot]; [self removeAllObservers]; self->_fetcherCompletion = nil; - return; - } - - // Upload completed successfully, fire completion callbacks - self.state = FIRStorageTaskStateSuccess; - - NSDictionary *responseDictionary = [NSDictionary frs_dictionaryFromJSONData:data]; - if (responseDictionary) { - FIRStorageMetadata *metadata = - [[FIRStorageMetadata alloc] initWithDictionary:responseDictionary]; - [metadata setType:FIRStorageMetadataTypeFile]; - self.metadata = metadata; - } else { - self.error = [FIRStorageErrors errorWithInvalidRequest:data]; - } - - [self fireHandlersForStatus:FIRStorageTaskStatusSuccess snapshot:self.snapshot]; - [self removeAllObservers]; - self->_fetcherCompletion = nil; - }; + }; #pragma clang diagnostic pop - [_uploadFetcher - beginFetchWithCompletionHandler:^(NSData *_Nullable data, NSError *_Nullable error) { - weakSelf.fetcherCompletion(data, error); - }]; + [strongSelf->_uploadFetcher + beginFetchWithCompletionHandler:^(NSData *_Nullable data, NSError *_Nullable error) { + weakSelf.fetcherCompletion(data, error); + }]; + }]; } #pragma mark - Upload Management - (void)cancel { - NSAssert([NSThread isMainThread], - @"Cancel attempting to execute on non main queue! Please only " - @"execute this method on the main queue."); - self.state = FIRStorageTaskStateCancelled; - [_uploadFetcher stopFetching]; - if (self.state != FIRStorageTaskStateSuccess) { - self.metadata = _uploadMetadata; - } - self.error = [FIRStorageErrors errorWithCode:FIRStorageErrorCodeCancelled]; - [self fireHandlersForStatus:FIRStorageTaskStatusFailure snapshot:self.snapshot]; + __weak FIRStorageUploadTask *weakSelf = self; + + [self dispatchAsync:^() { + weakSelf.state = FIRStorageTaskStateCancelled; + [weakSelf.uploadFetcher stopFetching]; + if (weakSelf.state != FIRStorageTaskStateSuccess) { + weakSelf.metadata = weakSelf.uploadMetadata; + } + weakSelf.error = [FIRStorageErrors errorWithCode:FIRStorageErrorCodeCancelled]; + [weakSelf fireHandlersForStatus:FIRStorageTaskStatusFailure snapshot:weakSelf.snapshot]; + }]; } - (void)pause { - NSAssert([NSThread isMainThread], - @"Pause attempting to execute on non main queue! Please only " - @"execute this method on the main queue."); - self.state = FIRStorageTaskStatePaused; - [_uploadFetcher pauseFetching]; - if (self.state != FIRStorageTaskStateSuccess) { - self.metadata = _uploadMetadata; - } - [self fireHandlersForStatus:FIRStorageTaskStatusPause snapshot:self.snapshot]; + __weak FIRStorageUploadTask *weakSelf = self; + + [self dispatchAsync:^() { + weakSelf.state = FIRStorageTaskStatePaused; + [weakSelf.uploadFetcher pauseFetching]; + if (weakSelf.state != FIRStorageTaskStateSuccess) { + weakSelf.metadata = weakSelf.uploadMetadata; + } + [weakSelf fireHandlersForStatus:FIRStorageTaskStatusPause snapshot:weakSelf.snapshot]; + }]; } - (void)resume { - NSAssert([NSThread isMainThread], - @"Resume attempting to execute on non main queue! Please only " - @"execute this method on the main queue."); - self.state = FIRStorageTaskStateResuming; - [_uploadFetcher resumeFetching]; - if (self.state != FIRStorageTaskStateSuccess) { - self.metadata = _uploadMetadata; - } - [self fireHandlersForStatus:FIRStorageTaskStatusResume snapshot:self.snapshot]; - self.state = FIRStorageTaskStateRunning; + __weak FIRStorageUploadTask *weakSelf = self; + + [self dispatchAsync:^() { + weakSelf.state = FIRStorageTaskStateResuming; + [weakSelf.uploadFetcher resumeFetching]; + if (weakSelf.state != FIRStorageTaskStateSuccess) { + weakSelf.metadata = weakSelf.uploadMetadata; + } + [weakSelf fireHandlersForStatus:FIRStorageTaskStatusResume snapshot:weakSelf.snapshot]; + weakSelf.state = FIRStorageTaskStateRunning; + }]; } @end diff --git a/Firebase/Storage/Private/FIRStorageDeleteTask.h b/Firebase/Storage/Private/FIRStorageDeleteTask.h index 4c93de2886d..5eeaa889e9c 100644 --- a/Firebase/Storage/Private/FIRStorageDeleteTask.h +++ b/Firebase/Storage/Private/FIRStorageDeleteTask.h @@ -27,6 +27,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithReference:(FIRStorageReference *)reference fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue completion:(FIRStorageVoidError)completion; @end diff --git a/Firebase/Storage/Private/FIRStorageDownloadTask_Private.h b/Firebase/Storage/Private/FIRStorageDownloadTask_Private.h index 293d1d5b438..8b5a0d86d2f 100644 --- a/Firebase/Storage/Private/FIRStorageDownloadTask_Private.h +++ b/Firebase/Storage/Private/FIRStorageDownloadTask_Private.h @@ -34,11 +34,13 @@ NS_ASSUME_NONNULL_BEGIN * Initializes a download task with a base FIRStorageReference and GTMSessionFetcherService. * @param reference The base FIRStorageReference which fetchers use for configuration. * @param service The GTMSessionFetcherService which will create fetchers. + * @param queue The shared queue to use for all Storage operations. * @param fileURL The system URL to download to. If nil, download in memory as bytes. * @return Returns an instance of FIRStorageDownloadTask */ - (instancetype)initWithReference:(FIRStorageReference *)reference fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue file:(nullable NSURL *)fileURL; /** diff --git a/Firebase/Storage/Private/FIRStorageGetDownloadURLTask.h b/Firebase/Storage/Private/FIRStorageGetDownloadURLTask.h index 8cd9eb31930..0dc81791a57 100644 --- a/Firebase/Storage/Private/FIRStorageGetDownloadURLTask.h +++ b/Firebase/Storage/Private/FIRStorageGetDownloadURLTask.h @@ -27,6 +27,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithReference:(FIRStorageReference *)reference fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue completion:(FIRStorageVoidURLError)completion; @end diff --git a/Firebase/Storage/Private/FIRStorageGetMetadataTask.h b/Firebase/Storage/Private/FIRStorageGetMetadataTask.h index e5ba37e7065..e98d6d1ef76 100644 --- a/Firebase/Storage/Private/FIRStorageGetMetadataTask.h +++ b/Firebase/Storage/Private/FIRStorageGetMetadataTask.h @@ -27,6 +27,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithReference:(FIRStorageReference *)reference fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue completion:(FIRStorageVoidMetadataError)completion; @end diff --git a/Firebase/Storage/Private/FIRStorageObservableTask_Private.h b/Firebase/Storage/Private/FIRStorageObservableTask_Private.h index e37b63fa645..404ec9e328f 100644 --- a/Firebase/Storage/Private/FIRStorageObservableTask_Private.h +++ b/Firebase/Storage/Private/FIRStorageObservableTask_Private.h @@ -27,10 +27,12 @@ NS_ASSUME_NONNULL_BEGIN * @param reference A FIRStorageReference the task will be performed on. * @param service A GTMSessionFetcherService which provides the fetchers and configuration for * requests. + * @param queue The shared queue to use for all Storage operations. * @return A new FIRStorageTask representing the current task. */ - (instancetype)initWithReference:(FIRStorageReference *)reference - fetcherService:(GTMSessionFetcherService *)service; + fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue; /** * Raise events for a given task status by passing along a snapshot of existing task state. diff --git a/Firebase/Storage/Private/FIRStorageTask_Private.h b/Firebase/Storage/Private/FIRStorageTask_Private.h index 382f27febfb..582043e4b25 100644 --- a/Firebase/Storage/Private/FIRStorageTask_Private.h +++ b/Firebase/Storage/Private/FIRStorageTask_Private.h @@ -54,6 +54,11 @@ NS_ASSUME_NONNULL_BEGIN */ @property(strong, nonatomic) FIRStorageReference *reference; +/** + * A serial queue for all storage operations. + */ +@property(nonatomic, readonly) dispatch_queue_t dispatchQueue; + @property(strong, readwrite, nonatomic, nonnull) FIRStorageTaskSnapshot *snapshot; @property(readonly, copy, nonatomic) NSURLRequest *baseRequest; @@ -64,15 +69,22 @@ NS_ASSUME_NONNULL_BEGIN @property(readonly, copy) GTMSessionFetcherCompletionHandler fetcherCompletion; +- (instancetype)init NS_UNAVAILABLE; + /** * Creates a new FIRStorageTask initialized with a FIRStorageReference and GTMSessionFetcherService. * @param reference A FIRStorageReference the task will be performed on. * @param service A GTMSessionFetcherService which provides the fetchers and configuration for * requests. + * @param queue The shared queue to use for all Storage operations. * @return A new FIRStorageTask representing the current task. */ - (instancetype)initWithReference:(FIRStorageReference *)reference - fetcherService:(GTMSessionFetcherService *)service NS_DESIGNATED_INITIALIZER; + fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue NS_DESIGNATED_INITIALIZER; + +/** Dispatches a block on the shared Storage queue. */ +- (void)dispatchAsync:(void (^)(void))block; @end diff --git a/Firebase/Storage/Private/FIRStorageUpdateMetadataTask.h b/Firebase/Storage/Private/FIRStorageUpdateMetadataTask.h index 46bd65a8232..23c6c34b7a0 100644 --- a/Firebase/Storage/Private/FIRStorageUpdateMetadataTask.h +++ b/Firebase/Storage/Private/FIRStorageUpdateMetadataTask.h @@ -27,6 +27,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithReference:(FIRStorageReference *)reference fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue metadata:(FIRStorageMetadata *)metadata completion:(FIRStorageVoidMetadataError)completion; diff --git a/Firebase/Storage/Private/FIRStorageUploadTask_Private.h b/Firebase/Storage/Private/FIRStorageUploadTask_Private.h index 468d9d39a14..8d37a8b62eb 100644 --- a/Firebase/Storage/Private/FIRStorageUploadTask_Private.h +++ b/Firebase/Storage/Private/FIRStorageUploadTask_Private.h @@ -44,11 +44,13 @@ NS_ASSUME_NONNULL_BEGIN * Initializes an upload task with a base FIRStorageReference and GTMSessionFetcherService. * @param reference The base FIRStorageReference which fetchers use for configuration. * @param service The GTMSessionFetcherService which will create fetchers. + * @param queue The shared queue to use for all Storage operations. * @param uploadData The NSData object to be uploaded. * @return Returns an instance of FIRStorageUploadTask. */ - (instancetype)initWithReference:(FIRStorageReference *)reference fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue data:(NSData *)uploadData metadata:(FIRStorageMetadata *)metadata; @@ -56,11 +58,13 @@ NS_ASSUME_NONNULL_BEGIN * Initializes an upload task with a base FIRStorageReference and GTMSessionFetcherService. * @param reference The base FIRStorageReference which fetchers use for configuration. * @param service The GTMSessionFetcherService which will create fetchers. + * @param queue The shared queue to use for all Storage operations. * @param fileURL The system file URL to upload from. * @return Returns an instance of FIRStorageUploadTask. */ - (instancetype)initWithReference:(FIRStorageReference *)reference fetcherService:(GTMSessionFetcherService *)service + dispatchQueue:(dispatch_queue_t)queue file:(NSURL *)fileURL metadata:(FIRStorageMetadata *)metadata; diff --git a/Firebase/Storage/Private/FIRStorage_Private.h b/Firebase/Storage/Private/FIRStorage_Private.h index aefe808baa6..04cecc14494 100644 --- a/Firebase/Storage/Private/FIRStorage_Private.h +++ b/Firebase/Storage/Private/FIRStorage_Private.h @@ -25,6 +25,8 @@ NS_ASSUME_NONNULL_BEGIN @property(strong, nonatomic) GTMSessionFetcherService *fetcherServiceForApp; +@property(nonatomic, readonly) dispatch_queue_t dispatchQueue; + @property(strong, nonatomic) NSString *storageBucket; /** From 3e1143a3634739661c000332eedce00ac10e83c8 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Mon, 22 Oct 2018 16:17:59 -0700 Subject: [PATCH 2/3] Checking strongSelf --- Firebase/Storage/FIRStorageDownloadTask.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Firebase/Storage/FIRStorageDownloadTask.m b/Firebase/Storage/FIRStorageDownloadTask.m index bf7f6d7821b..0752df73538 100644 --- a/Firebase/Storage/FIRStorageDownloadTask.m +++ b/Firebase/Storage/FIRStorageDownloadTask.m @@ -74,8 +74,8 @@ - (void)enqueueWithData:(nullable NSData *)resumeData { } [fetcher setResumeDataBlock:^(NSData *data) { - if (data) { - FIRStorageDownloadTask *strong = weakSelf; + FIRStorageDownloadTask *strong = weakSelf; + if (strong && data) { strong->_downloadData = data; } }]; From 897f9d4edd2620e775ff29faf5a1c845b8af0aed Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Tue, 23 Oct 2018 09:35:11 -0700 Subject: [PATCH 3/3] Addressing warnings --- .../Storage/Tests/Integration/FIRStorageIntegrationTests.m | 1 - Firebase/Storage/FIRStorageGetMetadataTask.m | 2 +- Firebase/Storage/FIRStorageTask.m | 6 ++++++ Firebase/Storage/FIRStorageUpdateMetadataTask.m | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Example/Storage/Tests/Integration/FIRStorageIntegrationTests.m b/Example/Storage/Tests/Integration/FIRStorageIntegrationTests.m index 420b8d87919..94729c92505 100644 --- a/Example/Storage/Tests/Integration/FIRStorageIntegrationTests.m +++ b/Example/Storage/Tests/Integration/FIRStorageIntegrationTests.m @@ -665,7 +665,6 @@ - (void)testUnauthenticatedResumeGetFileInBackgroundQueue { __block long resumeAtBytes = 256 * 1024; __block long downloadedBytes = 0; - __block double computationResult = 0; FIRStorageDownloadTask *task = [ref writeToFile:fileURL]; diff --git a/Firebase/Storage/FIRStorageGetMetadataTask.m b/Firebase/Storage/FIRStorageGetMetadataTask.m index 561d769c95c..efa637b9436 100644 --- a/Firebase/Storage/FIRStorageGetMetadataTask.m +++ b/Firebase/Storage/FIRStorageGetMetadataTask.m @@ -48,7 +48,7 @@ - (void)enqueue { __weak FIRStorageGetMetadataTask *weakSelf = self; [self dispatchAsync:^() { - FIRStorageGetMetadataTask* strongSelf = weakSelf; + FIRStorageGetMetadataTask *strongSelf = weakSelf; if (!strongSelf) { return; diff --git a/Firebase/Storage/FIRStorageTask.m b/Firebase/Storage/FIRStorageTask.m index a7cdefbcf89..c0848df259d 100644 --- a/Firebase/Storage/FIRStorageTask.m +++ b/Firebase/Storage/FIRStorageTask.m @@ -26,6 +26,12 @@ @implementation FIRStorageTask +- (instancetype)init { + @throw [NSException exceptionWithName:@"Attempt to call unavailable initializer." + reason:@"init unavailable, use designated initializer" + userInfo:nil]; +} + - (instancetype)initWithReference:(FIRStorageReference *)reference fetcherService:(GTMSessionFetcherService *)service dispatchQueue:(dispatch_queue_t)queue { diff --git a/Firebase/Storage/FIRStorageUpdateMetadataTask.m b/Firebase/Storage/FIRStorageUpdateMetadataTask.m index cb8f6abf4ec..70665b1e434 100644 --- a/Firebase/Storage/FIRStorageUpdateMetadataTask.m +++ b/Firebase/Storage/FIRStorageUpdateMetadataTask.m @@ -48,7 +48,7 @@ - (void)enqueue { __weak FIRStorageUpdateMetadataTask *weakSelf = self; [self dispatchAsync:^() { - FIRStorageUpdateMetadataTask* strongSelf = weakSelf; + FIRStorageUpdateMetadataTask *strongSelf = weakSelf; if (!strongSelf) { return;