我已經經歷最具有與AFNetworking的異步性質做崗位的讀取文件。但是,我的問題有點獨特,我可以使用一些幫助。如何確定,當我完成下載與AFNetworking
我從模態視圖控制器開始一個新的異步線程,應該告訴用戶我正在從Web服務器上下載內容。這個想法是下載一堆文件(超過100),它的工作很好。我甚至會將重試計數放入下載中,以便在下載任何文件失敗時重試(最大)。一切都在下載很好。問題是我不知道什麼時候完成。
這是爲什麼: 我下載了一個JSON文件列表。這些JSON文件定義了其他具有PDF和其他類型文件列表的JSON文件的列表。由於我正在下載的內容,我必須按順序下載。例如:
- 下載file1.json 它的下載
- 負荷後從file1.json JSON文件
- 獲取列表這些二次JSON文件(subFile1.json,subFile2.json等)
- 二次JSON文件下載(subFile1.json)後,我得到的文件列表從該JSON文件下載(subFile1.json)將在JSON子文件中指定的文件
- 下載(subFile1.json爲例如)
所以我的過程看起來層次,以保證母文件子文件之前獲取下載: 1.初始下載方法調用SubDownloadMethod2成功(成功區塊內) 2. SubDownloadMethod2從下載的文件中獲取名單,並呼籲SubSubDownloadMethod3 3. SubSubDownloadMethod3下載PDF文件(及其他文件)成功(成功區塊內)
因此,大家可以看到,我有一個動態的數字文件的下載。因此我不知道我會在前面下載多少個文件。由於它可以在多個級別下來並且來自web服務器上的多個目錄,所以它變得更加困難。
如果下載失敗(達到最大重試次數),我也對每種方法進行遞歸回調,這也使得它更加困難。因爲每次下載都開始它自己的線程(我假設這就是AFNetworking正在做的事情),但我不確定什麼時候所有的下載都完成了。我不知道enqueueBatchOfHTTPRequestOperations是否有幫助。我不完全理解它,並且正在從Web服務器上的多個目錄下載。我還需要根據下載,因爲我不知道多遠我會去,直到我下載和分析定義的JSON文件中的每個級別的批量操作。
幫助!!!!
我認爲它可以幫助把代碼。這是一個很大的代碼來看看,但它是一個困難的問題(當然,有人用我的技能)。
如果你在看代碼,每次我需要下載另一個文件的時間,我調用該方法在最底層:
- (void)downloadLibraryFile:(NSString *)fileOnServer targetFile:(NSString *)targetFile retryCount:(int)retryCount completionBlock:(DownloadLibraryFileCompletionBlock)completionBlock
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:fileOnServer]];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:targetFile append:NO];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
//NSLog(@"Successfully downloaded file to %@", path);
completionBlock(fileOnServer, targetFile, retryCount, nil);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
completionBlock(fileOnServer, targetFile, retryCount, error);
}];
[operation start];
}
這將啓動AFNetorking並開始下載。它完成後會調用完成塊,但我怎麼知道它們什麼時候完成?
這裏是代碼的其餘部分(包括上述方法)
- (void)downloadLibraryOnReset
{
// Find and copy the page defintion file to the documents directoy
// TODO localize the call to get the appropriate file based on language
dispatch_queue_t queue = dispatch_queue_create("Library Download Queue", NULL);
dispatch_async(queue, ^{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *serverLibraryURL = [defaults objectForKey:kRootURL];
serverLibraryURL = [serverLibraryURL stringByAppendingPathComponent:kPageDefinitionsDirectory];
// Save server root URL
self.serverRootURL = serverLibraryURL;
// Add last component onto download path
serverLibraryURL = [serverLibraryURL stringByAppendingPathComponent:kPageDefinitions];
// Get target location
NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);;
NSString *targetFile = [dirPaths objectAtIndex:0];
targetFile = [targetFile stringByAppendingPathComponent:@"en"]; // TODO this needs to be localized based on language
targetFile = [targetFile stringByAppendingPathComponent:kPageDefinitionsDirectory];
self.pageDefintiionDirectoryURL = targetFile;
// Create the subdirectory off of the documents directory to contain the config files
NSFileManager *filemgr = [NSFileManager defaultManager];
if ([filemgr createDirectoryAtPath:targetFile withIntermediateDirectories:YES attributes:nil error: NULL] == NO)
{
// Failed to create directory
}
NSString *pageDefinitionsFileURL = [targetFile stringByAppendingPathComponent:kPageDefinitions];
[self downloadPageDefinitionsFile:serverLibraryURL targetFile:pageDefinitionsFileURL retryCount:kDownloadRetryCount];
// Reset the resetContent flag to false
[defaults setBool:NO forKey:kResetContent];
});
}
- (void)downloadPageDefinitionsFile:(NSString *)fileOnServer targetFile:(NSString *)targetFile retryCount:(int)retryCount
{
[self downloadLibraryFile:fileOnServer targetFile:targetFile retryCount:retryCount completionBlock:^(NSString *fileOnServer, NSString *targetFile, int retryCount, NSError *error) {
if(error)
{
retryCount--;
if(retryCount)
{
NSLog(@"RETRY DONWLOAD (Attempt: %d, Method: %@) > File: %@", kDownloadRetryCount - retryCount, NSStringFromSelector(_cmd), fileOnServer);
[self downloadPageDefinitionsFile:fileOnServer targetFile:targetFile retryCount:retryCount];
}
else
{
NSLog(@"RETRY COUNT EXCEEDED (Attempt: %d, Method: %@) > File: %@", kDownloadRetryCount, NSStringFromSelector(_cmd), fileOnServer);
}
}
else
{
// Check to see if this file was downloaded after an error
if(retryCount < kDownloadRetryCount)
{
NSLog(@">>RETRY SUCCESSFUL (Attempt: %d, Method: %@) > File: %@", kDownloadRetryCount - retryCount, NSStringFromSelector(_cmd), fileOnServer);
}
// Copy down all config files defined in the pagedefinitions.json file
//code from other library
NSError* err = nil;
NSString *path = self.pageDefintiionDirectoryURL;
path = [path stringByAppendingPathComponent:kPageDefinitions];
NSData *data = [NSData dataWithContentsOfFile:path];
if(data)
{
// Convert to JSON Directory
NSMutableDictionary *pageDefinitionsDict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&err];
//fileVersion = pageDefinitionsDict[kFileVersion];
NSMutableArray *pages = pageDefinitionsDict[kPages];
for (NSMutableDictionary *page in pages)
{
MINPageDefinition *pageDef = [[MINPageDefinition alloc] initWithDictionary:page];
NSString *targetDirectory = [targetFile stringByDeletingLastPathComponent];
pageDef.pageURL = [targetDirectory stringByAppendingPathComponent:pageDef.pageConfigFileName];
//NSString *imageURL = [pageDef.pageURL stringByDeletingLastPathComponent];
pageDef.pageImageURL = [self.pageDefintiionDirectoryURL stringByAppendingPathComponent:pageDef.pageImageName];
[[MINPageStore sharedInstance].pageArray addObject:pageDef];
}
// Write modified pagedefinitions.json to the appropriate directory in Documents
[[MINPageStore sharedInstance] writePageDefinitionFile:path];
// Continue downloading page images and other config files,
for (MINPageDefinition *currPage in [[MINPageStore sharedInstance] pageArray])
{
[self downloadPageDefinitionImageFile:currPage retryCount:kDownloadRetryCount];
[self downloadPageDefinitionJSONFile:currPage retryCount:kDownloadRetryCount];
}
}
}
}];
}
- (void)downloadPageDefinitionJSONFile:(MINPageDefinition *)pageDef retryCount:(int)retryCount
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *serverLibraryURL = [defaults objectForKey:kRootURL];
serverLibraryURL = [serverLibraryURL stringByAppendingPathComponent:kPageDefinitionsDirectory];
serverLibraryURL = [serverLibraryURL stringByAppendingPathComponent:pageDef.pageConfigFileName];
[self downloadLibraryFile:serverLibraryURL targetFile:pageDef.pageURL retryCount:retryCount completionBlock:^(NSString *fileOnServer, NSString *targetFile, int retryCount, NSError *error) {
if(error)
{
retryCount--;
if(retryCount)
{
NSLog(@"RETRY DONWLOAD (Attempt: %d, Method: %@) > File: %@", kDownloadRetryCount - retryCount, NSStringFromSelector(_cmd), serverLibraryURL);
[self downloadPageDefinitionJSONFile:pageDef retryCount:retryCount];
}
else
{
NSLog(@"RETRY COUNT EXCEEDED (Attempt: %d, Method: %@) > File: %@", kDownloadRetryCount, NSStringFromSelector(_cmd), serverLibraryURL);
}
}
else
{
// Check to see if this file was downloaded after an error
if(retryCount < kDownloadRetryCount)
{
NSLog(@">>RETRY SUCCESSFUL (Attempt: %d, Method: %@) > File: %@", kDownloadRetryCount - retryCount, NSStringFromSelector(_cmd), serverLibraryURL);
}
// Copy down all config files defined in the pagedefinitions.json file
if([pageDef.pageType isEqualToString:kGridView])
{
[self downloadGridViewContent:pageDef];
}
else
{
//NSLog(@">>>>FINISHED DOWNLOADING PAGE: %@", pageDef.pageName);
}
}
}];
}
- (void)downloadPageDefinitionImageFile:(MINPageDefinition *)pageDef retryCount:(int)retryCount
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *serverLibraryURL = [defaults objectForKey:kRootURL];
serverLibraryURL = [serverLibraryURL stringByAppendingPathComponent:kPageDefinitionsDirectory];
serverLibraryURL = [serverLibraryURL stringByAppendingPathComponent:pageDef.pageImageName];
[self downloadLibraryFile:serverLibraryURL targetFile:pageDef.pageImageURL retryCount:retryCount completionBlock:^(NSString *fileOnServer, NSString *targetFile, int retryCount, NSError *error) {
if(error)
{
retryCount--;
if(retryCount)
{
NSLog(@"RETRY DONWLOAD (Attempt: %d, Method: %@) > File: %@", kDownloadRetryCount - retryCount, NSStringFromSelector(_cmd), serverLibraryURL);
[self downloadPageDefinitionImageFile:pageDef retryCount:retryCount];
}
else
{
NSLog(@"RETRY COUNT EXCEEDED (Attempt: %d, Method: %@) > File: %@", kDownloadRetryCount, NSStringFromSelector(_cmd), serverLibraryURL);
}
}
else
{
// Check to see if this file was downloaded after an error
if(retryCount < kDownloadRetryCount)
{
NSLog(@">>RETRY SUCCESSFUL (Attempt: %d, Method: %@) > File: %@", kDownloadRetryCount - retryCount, NSStringFromSelector(_cmd), serverLibraryURL);
}
dispatch_async(dispatch_get_main_queue(), ^{
[self.masterViewController.tableView reloadData];
});
}
}];
}
- (void)downloadGridViewContent:(MINPageDefinition *)pageDef
{
// Parse off the json extension
// Use this to create a subdirectory under the pagedefinitions directoy
NSString *newDirectoryForGridView = [pageDef.pageURL stringByDeletingPathExtension];
newDirectoryForGridView = [newDirectoryForGridView lastPathComponent];
NSString *newGridViewDirectoryURL = [pageDef.pageURL stringByDeletingPathExtension];
// Create the subdirectory off of the documents directory to contain the config files
NSFileManager *filemgr = [NSFileManager defaultManager];
if ([filemgr createDirectoryAtPath:newGridViewDirectoryURL withIntermediateDirectories:YES attributes:nil error: NULL] == NO)
{
// Failed to create directory
}
// Load the grid view config file
[MINVolume loadAlbumItems:pageDef.pageURL completionBlock:^(NSString *fileName, MINVolume *newVolume, NSError *error) {
if(!error)
{
if(newVolume && [newVolume.albumsArray count] > 0)
{
// Iterate through the albums and create directories for each album
for(MINAlbum *album in newVolume.albumsArray)
{
NSString *localAlbumDirectory = [newGridViewDirectoryURL stringByAppendingPathComponent:album.albumURL];
if ([filemgr createDirectoryAtPath:localAlbumDirectory withIntermediateDirectories:YES attributes:nil error: NULL] == NO)
{
// Failed to create directory
}
// Copy down all album content
for(MINAlbumItem *albumItem in album.albumItemsArray)
{
// Create names for local file and thumbnail
NSString *localAlbumItemFileURL = [localAlbumDirectory stringByAppendingPathComponent:albumItem.itemFileName];
NSString *localAlbumItemFileThumbURL = [localAlbumDirectory stringByAppendingPathComponent:albumItem.itemThumbnailImageName];
// Define paths for file and thumbnail on server
NSString *serverAlbumItemFileURL = [self.serverRootURL stringByAppendingPathComponent:newDirectoryForGridView];
serverAlbumItemFileURL = [serverAlbumItemFileURL stringByAppendingPathComponent:album.albumURL];
serverAlbumItemFileURL = [serverAlbumItemFileURL stringByAppendingPathComponent:albumItem.itemFileName];
NSString *serverAlbumItemFileThumbURL = [self.serverRootURL stringByAppendingPathComponent:newDirectoryForGridView];
serverAlbumItemFileThumbURL = [serverAlbumItemFileThumbURL stringByAppendingPathComponent:album.albumURL];
serverAlbumItemFileThumbURL = [serverAlbumItemFileThumbURL stringByAppendingPathComponent:albumItem.itemThumbnailImageName];
// Copy album item file
BOOL bFileExists = [filemgr fileExistsAtPath:localAlbumItemFileURL];
if(!bFileExists)
{
[self downloadAlbumItem:albumItem isThumbnail:(BOOL)false fileOnServer:serverAlbumItemFileURL targetFile:localAlbumItemFileURL retryCount:kDownloadRetryCount];
}
else
{
albumItem.itemURL = localAlbumItemFileURL;
}
// Copy album item thumbnail
BOOL bFileThumbnailExists = [filemgr fileExistsAtPath:localAlbumItemFileThumbURL];
if(!bFileThumbnailExists)
{
[self downloadAlbumItem:albumItem isThumbnail:true fileOnServer:serverAlbumItemFileThumbURL targetFile:localAlbumItemFileThumbURL retryCount:kDownloadRetryCount];
}
else
{
albumItem.itemThumbnailURL = localAlbumItemFileThumbURL;
}
}
}
}
else
{
NSLog(@"No volume found for file: %@", pageDef.pageConfigFileName);
}
}
}];
}
- (void)downloadAlbumItem:(MINAlbumItem *)albumItem isThumbnail:(BOOL)isThumbnail fileOnServer:(NSString *)fileOnServer targetFile:(NSString *)targetFile retryCount:(int)retryCount
{
[self downloadLibraryFile:fileOnServer targetFile:targetFile retryCount:retryCount completionBlock:^(NSString *fileOnServer, NSString *targetFile, int retryCount, NSError *error) {
if(error)
{
retryCount--;
if(retryCount)
{
NSLog(@"RETRY DONWLOAD (Attempt: %d, Method: %@) > File: %@", kDownloadRetryCount - retryCount, NSStringFromSelector(_cmd), fileOnServer);
[self downloadAlbumItem:albumItem isThumbnail:isThumbnail fileOnServer:fileOnServer targetFile:targetFile retryCount:retryCount];
}
else
{
NSLog(@"RETRY COUNT EXCEEDED (Attempt: %d, Method: %@) > File: %@", kDownloadRetryCount, NSStringFromSelector(_cmd), fileOnServer);
}
}
else
{
// Check to see if this file was downloaded after an error
if(retryCount < kDownloadRetryCount)
{
NSLog(@">>RETRY SUCCESSFUL (Attempt: %d, Method: %@) > File: %@", kDownloadRetryCount - retryCount, NSStringFromSelector(_cmd), fileOnServer);
}
if(isThumbnail)
albumItem.itemThumbnailURL = targetFile;
else
albumItem.itemURL = targetFile;
}
}];
}
- (void)downloadLibraryFile:(NSString *)fileOnServer targetFile:(NSString *)targetFile retryCount:(int)retryCount completionBlock:(DownloadLibraryFileCompletionBlock)completionBlock
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:fileOnServer]];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:targetFile append:NO];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
//NSLog(@"Successfully downloaded file to %@", path);
completionBlock(fileOnServer, targetFile, retryCount, nil);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
completionBlock(fileOnServer, targetFile, retryCount, error);
}];
[operation start];
}
我發表了上面的代碼。正如你所看到的,我正在使用完成塊。問題是完成塊只告訴我什麼時候下載了一個特定的文件,而不是當我已經下載了所有的文件下載時。我希望這是有道理的。我完全沒有關於如何完成這項工作的想法。 – JustLearningAgain
我沒有足夠的代表直接評論@王子的答案,所以我會把它放在這裏。 [操作waitUntilFinish]不好。它會掛起你運行它的線程,如果它是你的應用程序看起來掛起的主線程。 – coolstar