在ipad应用程序中处理许多ASIHttpRequests和核心数据操作的最佳方法

nsx*_*241 3 iphone core-data objective-c asihttprequest ios

我正在为iPad开发的当前应用程序涉及处理许多网络请求并将处理后的结果保存在核心数据中.

方案如下 - 应用程序需要下载我在网格视图中显示的对象的图像,这可以显示总共30个对象.每个对象最多可包含15个png图像(也在网格中).由于服务器的实现方式(意味着我没有实现它并且无法轻松更改),每个映像必须单独请求,因此每个对象最多需要15个请求,而不是只需要下载1个请求15张图片.

对于每个对象,我目前正在使用ASINetworkQueue来排队15个图像请求.队列完成后,我创建对象的缩略图快照,其图像显示在网格中,然后将所有png文件保存到核心数据.

我目前正在主线程上运行除ASI异步处理的网络请求之外的所有内容,但由于请求太多,应用程序UI基本上处于锁定状态,直到处理完所有请求并将结果保存到核心数据.

我遇到的一个解决方案是执行核心数据操作并在单独的线程中写入或使用大型中央调度.另一种方法是仅下载可见对象的图像,并在用户向下滚动时下载其余图像.

我正在寻找其他建议,以帮助保持主要的ui响应,或更好的方式来构建网络和核心数据操作.谢谢.

Dan*_*rpe 5

首先,避免在Core Data中存储大blob,保存缩略图很好(尽管你应该为它优化你的模型),但是你应该在Documents文件夹中重建后存储完整的图像.

您绝对应该使用队列,NSOperationQueue或ASI网络队列.我在我的应用程序中做了类似的事情,它有多个依赖项.因此,对于30个对象中的每个对象,您需要在下载15个图像时调用块(或工作函数).理想情况下,您希望在主线程之外完成此工作.把所有这些要求放在一起,我会说你需要至少两个队列,一个用于网络请求,一个用于工作块,你应该使用NSBlockOperations,这使得整个事情变得更加容易.所以,代码将是这样的......

// Loop through the objects
for (NSArray *objectParts in objectsToDownload) {

    // Create our Object
    Object *obj = [Object insertIntoManagedObjectContext:self.moc];

    // This is the block which will do the post processing for the object
    NSBlockOperation *processBlock = [NSBlockOperation blockOperationWithBlock:^{

        // Do post processing here, be very careful with multi-threading CoreData
        // it's likely you'll need some class to dispatch you MOCs which have all
        // all the observers set up.

        // We're gonna assume that all the sub-images have been stored in a instance
        // variable:
        [obj performPostProcessing];

    }];

    // Given the list of 15 images which form each object
    for (NSURL *part in objectParts) {

        // Create the ASI request for this part
        ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:part];

        // Configure the request
        [request setDelegate:self];
        [request setDidFailSelector:@selector(partRequestDidFail:)];
        [request setDidFinishSelector:@selector(partRequestDidFinish:)];

        // Store the object in the UserInfo dictionary
        NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:obj, @"Object", nil];
        [request setUserInfo:userInfo];

        // Add it as a dependency
        [processBlock addDependency:request];

        // Add it to our network queue
        [networkQueue addOperation:request];
    }

    // Add the processBlock to our worker queue
    [workerQueue addOperation:processBlock];
}
Run Code Online (Sandbox Code Playgroud)

那么你还需要编写委托方法,didFinish会看起来像这样......

- (void)partRequestDidFinish:(ASIHTTPRequest *)request {
    // Remember this is one the main thread, so any heavy lifting should be 
    // put inside a block operation, and queued, which will complicate the 
    // dependencies somewhat, but is possible.

    // Get the result data
    NSData *data = [request responseData];

    // Get the object that it belongs to from the user info dic
    Object *obj = [[request userInfo] objectForKey:@"Object"];

    // Keep track of the partial data in the object
    [obj storePartialDataForPostProcessing:data];
}
Run Code Online (Sandbox Code Playgroud)

所有这些都将进入连接到服务器并创建对象的类,因此它不是视图控制器或任何东西,只是常规的NSObject子类.它需要有两个队列,一个托管对象上下文(很可能是一个返回另一个MOC的方法,供你在线程中使用,如下所示:

// Fends a MOC suitable for use in the NSBlockOperations
- (NSManagedObjectContext *)moc {
    // Get a blank managed object context
    NSManagedObjectContext *aContext = [[UIApplication sharedApplication] managedObjectContext;
[aContext setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy];
    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
    [nc addObserver:self selector:@selector(mergeChangesFromMOC:) name:NSManagedObjectContextDidSaveNotification object:aContext];
    return aContext;
Run Code Online (Sandbox Code Playgroud)

}

- (void)mergeChangesFromMOC:(NSNotification *)aNotification {
    @try {
        [self.managedObjectContext mergeChangesFromContextDidSaveNotification:aNotification];
        NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
        [nc removeObserver:self name:NSManagedObjectContextDidSaveNotification object:[aNotification object]];      
    }
    @catch (NSException * e) {
        NSLog(@"Stopping on exception: %@", [e description]);
    }
    @finally {}
}
Run Code Online (Sandbox Code Playgroud)

您还需要以某种方式挂钩监控进度,重新排队失败的下载,取消以及最后保存MOC.重新排队失败的下载非常棘手.无论如何,希望有所帮助.

因此,只是为了澄清,在您的委托方法中,您将下载的图像存储在Object上的临时实例变量中.然后,当所有15个依赖项完成后,您可以访问该实例变量并完成您的工作.