iOS CoreData后台线程抓取在cellForRowAtIndexPath



我的应用程序中有一个tableview,它包含一个NSFetchedResultsController来加载一些CoreData对象。

当表在cellForRowAtIndexPath:中构建时,对于每个单元格,我必须执行fetch以从另一个对象获取一些其他信息。

表中填充了UserTasks,我必须从UserSite (UserTask包含siteID属性)获取一些信息

我正在后台线程中获取UserSite信息,并使用临时上下文。它工作得很好,但是当滚动时它仍然想要延迟UI。

        Site *site = [_scannedSites objectForKey:task.siteID];
        if(!site)
        {   
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
                AppDelegate *ad = [AppDelegate sharedAppDelegate];
                NSManagedObjectContext *temporaryContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
                temporaryContext.persistentStoreCoordinator = ad.persistentStoreCoordinator;
                Site *site2 = [task getSiteWithContext:temporaryContext];
                if(site2)
                {
                    [ad.managedObjectContext performBlock:^{
                        Site *mainContextObject = (Site *)[ad.managedObjectContext objectWithID:site2.objectID];
                        [_scannedSites mainContextObject forKey:task.siteID];
                    }];
                    dispatch_async(dispatch_get_main_queue(), ^{
                        Site *newSite = [_scannedSites objectForKey:task.siteID];
                        cell.lblCustName.text = newSite.siteName;
                        cell.lblAddr.text = [NSString stringWithFormat:@"%@ %@, %@", newSite.siteAddressLine1, newSite.siteCity, newSite.siteState];
                        cell.lblPhone.text = [self formatPhoneNum:newSite.phone];
                    });
                }
                else
                {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        cell.lblCustName.text = @"";
                        cell.lblAddr.text = @"";
                        cell.lblPhone.text = @"";
                    });
                }
            });
        }
        else
        {
            cell.lblCustName.text = site.siteName;
            cell.lblAddr.text = [NSString stringWithFormat:@"%@ %@, %@", site.siteAddressLine1, site.siteCity, site.siteState];
            cell.lblPhone.text = [self formatPhoneNum:site.phone];
        }    

正如你所看到的,如果你在_scannedSites中还没有一个任务的UserSite信息,一个后台线程被启动,它获取该任务的UserSite信息,存储它,然后在主线程中填充详细信息。

就像我说的,滚动时有一个非常烦人的延迟…我希望通过在后台工作来避免这种情况。

我是不是走错路了?

谢谢,任何建议都很感激。


编辑我在CoreData中创建了一个关系,我现在在cellForRowAtIndexPath中使用它。如果还不存在,我就创建它。

    Site *site = task.site;
    if(!site)
    {
        AppDelegate *ad = [AppDelegate sharedAppDelegate];
        NSManagedObjectContext *temporaryContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        temporaryContext.persistentStoreCoordinator = ad.persistentStoreCoordinator;
        [temporaryContext performBlock:^{
            Site *tempContextSite = [task getSiteWithContext:temporaryContext];
            [ad.managedObjectContext performBlock:^{
                Site *mainManagedObject = (Site *)[ad.managedObjectContext objectWithID:tempContextSite.objectID];
                task.site = mainManagedObject;
                NSError *error;
                if (![temporaryContext save:&error])
                {
                }
                [ad.managedObjectContext performBlock:^{
                    NSError *e = nil;
                    if (![ad.managedObjectContext save:&e])
                    {
                    }
                    dispatch_async(dispatch_get_main_queue(), ^{
                        cell.lblCustName.text = mainManagedObject.siteName;
                        cell.lblAddr.text = [NSString stringWithFormat:@"%@ %@, %@", mainManagedObject.siteAddressLine1, mainManagedObject.siteCity, mainManagedObject.siteState];
                        cell.lblPhone.text = [self formatPhoneNum:mainManagedObject.phone];
                    });
                }];
            }];
        }];
    }
    else
    {
        cell.lblCustName.text = site.siteName;
        cell.lblAddr.text = [NSString stringWithFormat:@"%@ %@, %@", site.siteAddressLine1, site.siteCity, site.siteState];
        cell.lblPhone.text = [self formatPhoneNum:site.phone];
    }

如果UserTaskUserSite相关,通常的Core Data方法是在两者之间创建一个关系,然后在运行时使用该关系。因此,UserTask将有一个名为site的属性,并且您只需向特定实例询问该属性的值。ID属性可能仍然存在,但只在与某些外部数据存储(如服务器API)同步时使用。

像这样存储id和查找对象从根本上来说是一种尴尬的方法,它在运行时做了很多不必要的工作。它避免了Core Data试图提供的所有便利,而是以困难的方式做事。当表滚动时执行工作也是最糟糕的时间,因为此时性能问题将最为明显。

如果出于某种原因必须这样做,您可以通过提前查找所有UserSite实例而不是在表滚动时进行优化。如果您知道所有的UserTask实例,那么当视图加载时,在一次调用中获取所有站点。

cellForRowAtIndexPath:中发送异步任务是一个坏主意。如果用户滚动,将会创建一大堆线程,这些线程甚至可能是不必要的。

如果有一个后台进程来获取你想要的信息,然后通知UI在需要时更新自己,那就好得多了。这是非常标准的东西,您将很容易找到许多可靠实现的示例。

相关内容

  • 没有找到相关文章

最新更新