如何确定何时使用AFNetworking下载文件

时间:2013-01-06 04:53:50

标签: iphone ios ipad

我已经阅读了大部分与AFNetworking的异步性质有关的帖子。但是,我的问题有点独特,我可以使用一些帮助。

我正在从模态视图控制器启动一个新的异步线程,它应该告诉用户我正在从Web服务器下载内容。这个想法是下载一堆文件(超过100个),它的工作效果很好。我甚至将重试计数放入下载中,以便在失败时重新下载任何文件(最多)。一切都下载很棒。问题是我不知道什么时候完成。

这就是原因: 我下载了一个JSON文件列表。这些JSON文件定义了包含PDF和其他类型文件列表的其他JSON文件的列表。由于我正在下载的性质,我必须按顺序下载它。例如:

  1. 下载file1.json
  2. 从file1.json下载后获取JSON文件列表
  3. 加载每个辅助JSON文件(subFile1.json,subFile2.json等)
  4. 下载次要JSON文件(subFile1.json)后,我会从该JSON文件(subFile1.json)获取要下载的文件列表
  5. 下载JSON子文件中指定的每个文件(例如subFile1.json)
  6. 所以我的进程看起来是分层的,以确保在子文件之前下载父文件: 1.初始下载方法调用SubDownloadMethod2 ON SUCCESS(在成功块内) 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];
    }
    

3 个答案:

答案 0 :(得分:0)

如果你正在进行AFHTTPRequestOperation,你可以使用它的setCompletionBlockWithSuccess方法来设置一个块,一旦下载(甚至上传)完成就会被调用。

示例:

AFHTTPRequestOperation *httpreq = [[AFHTTPRequestOperation alloc] initWithRequest:[NSURLRequest requestWithURL:downloadURL]];
[httpreq setCompetionBlockWithSuccess^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"%@",@"Done!");
}];

此外,您不需要在异步运行的其他线程中启动操作。

答案 1 :(得分:0)

你在NSOperationQueue中添加所有操作,如下所示:

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation: operation]; //your operation here
[operation start] 
[operation waitUntilFinish]

如何维护NSOperationQueue,请参阅以下链接:

参考ios-how-to-know-when-nsoperationqueue-finish-processing-a-few-operations链接。

参考ios-how-to-check-if-an-nsoperation-is-in-an-nsoperationqueue链接。

参考ios-nsoperationqueue-operations-all-run-when-added-and-dont-queue链接。

答案 2 :(得分:0)

我会考虑使用AFHTTPClient来处理您的下载,尤其是因为您想要管理多个下载。初始化客户端后,您需要创建所有操作,然后使用方法-[AFHTTPClient enqueueBatchOfHTTPRequestOperations: progressBlock: completionBlock:]将它们添加到客户端操作队列中。这样,您还可以使用进度块确定下载进度。此外,完成块将允许您在完成时执行自己的自定义代码。

所以你要从初始化你的客户开始:

AFHTTPClient *client =[AFHTTPClient clientWithBaseURL:baseURL];

然后,您要创建HTTP请求操作:

NSMutableURLRequest *request = [client requestWithMethod:@"GET" path:@"/" parameters:nil];
AFHTTPRequestOperation *firstOperation = [client HTTPRequestOperationWithRequest:request success:nil failure:nil];
AFHTTPRequestOperation *secondOperation = [client HTTPRequestOperationWithRequest:request success:nil failure:nil];

然后,您只需将这些操作添加到客户端操作队列:

[client enqueueBatchOfHTTPRequestOperations:@[firstOperation, secondOperation, thirdImageRequestOperation] 
                              progressBlock:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations) {
                              //Handle progress here
                              } 
                            completionBlock:^(NSArray *operations) {
                             //Handle completion of all downloads here
}];

希望这会有所帮助:)