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

标签 iphone objective-c ios core-data asihttprequest

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

场景如下 - 应用程序需要下载我在 GridView 中显示的对象的图像,总共可以显示 30 个对象。每个对象最多可以包含 15 个 png 图像(也在网格中)。由于服务器的实现方式(意味着我没有实现它并且不能轻易更改它),每个图像都必须单独请求,所以我需要为每个对象发出多达 15 个请求,而不是只需要 1 个请求来下载所有15 张图片。

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

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

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

我正在寻找其他建议来帮助保持主用户界面的响应性,或者更好的方法来构建网络和核心数据操作。谢谢。

最佳答案

首先,避免在 Core Data 中存储大的 blob,保存缩略图就可以了(尽管您应该为此优化您的模型),但是您应该在重建后将完整图像存储在 Documents 文件夹中。

你绝对应该使用队列,NSOperationQueue 或 ASI 网络队列。我在我的应用程序中做了类似的事情,它有多个依赖项。因此,对于 30 个对象中的每一个,您需要在 15 个图像下载后调用一个 block (或工作函数)。理想情况下,您希望在主线程之外完成这项工作。将所有这些要求放在一起,我会说您至少需要两个队列,一个用于网络请求,一个用于工作 block ,并且您应该使用 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];
}

然后你还需要编写委托(delegate)方法,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];
}

所有这些都将进入您的类,该类连接到您的服务器并创建您的对象,因此它不是 View Controller 或任何东西,只是一个常规的 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;

- (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 {}
}

您还需要以某种方式 Hook 以监控进度、重新排队失败的下载、取消并在最后保存 MOC。重新排队失败的下载非常棘手。不管怎样,希望对您有所帮助。

因此,澄清一下,在您的委托(delegate)方法中,您会将下载的图像存储在对象的临时实例变量中。然后,当所有 15 个依赖项完成时,您可以访问该实例变量并完成您的工作。

关于iphone - 在 ipad 应用程序中处理许多 ASIHttpRequests 和核心数据操作的最佳方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6068538/

相关文章:

iphone - 我们可以将应用提交到具有Debug模式的iOS自定义框架的appstore吗?

iphone - 如何在iPhone上制作聊天系统?

ios - 如何在没有 Apple Watch App 的情况下使用 cordova 在 Apple Watch 上获取 iPhone App 的推送通知?

iphone - 是什么原因导致 Objective-C 编译错误 : Stray '\235' in Program

iphone - 播放保存在相机胶卷中的视频

cocoa-touch - 使用 UISliders 值更改 UILabels 文本

iphone - 如何在顶部 viewForHeaderInSection 上添加一个 UIButton

iphone - 当其他UIImageView上已经有另一根手指时,不允许在UIImageView上轻击手势

objective-c - XCode 4 + 仪器 4 : False positive leaks?

ios - 模态视图 Controller 状态恢复 SceneDelegate