应用程序滞后于巨大的核心数据映射,通过RestKit&神奇的记录

时间:2015-04-08 15:06:52

标签: ios multithreading core-data restkit

Im still trying找出加载UI线程的内容。在一个类(UITableView的一个孩子)中有一个FRC:

 NSFetchRequest *request = [DEPlace MR_requestAllWithPredicate:[NSPredicate predicateWithFormat:@"isWorking == YES"]];

 request.sortDescriptors = @[ [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES] ];
 self.placesController = [[NSFetchedResultsController alloc] initWithFetchRequest:request
                                                                managedObjectContext:[NSManagedObjectContext MR_rootSavingContext]
                                                                  sectionNameKeyPath:nil
                                                                           cacheName:nil];
 self.placesController.delegate = self;

它曾经附加到MR_contextForCurrentThread。将其更改为rootSavingContext会略微影响性能。然后我将根和默认上下文设置为相同的上下文:

[NSManagedObjectContext MR_setRootSavingContext:managedObjectStore.persistentStoreManagedObjectContext];
[NSManagedObjectContext MR_setDefaultContext:managedObjectStore.persistentStoreManagedObjectContext];

默认上下文曾经设置为mainQueueManagedObjectContext。我想简单地移动与背景相关的所有核心数据,让FRC负责与UI的交互。 FRC代表通过以下方式获取新数据:

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
  //self.places = [self sortPlaces:controller.fetchedObjects];

  self.places = controller.fetchedObjects;

  [self.delegate contentUpdatedInDatasource:self];
} 

我现在禁用排序,认为它可能影响主线程。我已经尝试弄清楚还有什么可以用Time Profiler加载主线程,但没有发现任何可疑的东西。 screenshot

当所有数据都加载完毕后,一切运行顺畅,只有在第一次启动时才会填充数据库。由于所有与装载相关的东西都由RestKit持有,我不认为它会导致问题。

我在考虑将请求延迟最多10次,但不知道如何实现它。基本上,在启动应用程序获取和ID数组(现在约250)然后通过数组循环并通过每个ID从服务器请求数据。到目前为止它并不是那么重要,但是当阵列长到1-2k时,这将是一个大问题。顺便说一句,单个数据对象在DB中有4个关系。减少依赖是一种可能的解决方案吗?

更新: 我试图将请求拆分为1比1,这引起了一种非常奇怪的行为。 由于某种原因,请求之间存在巨大延迟。 这就是我得到一系列ID

的方法
        AFJSONRequestOperation *op = [[AFJSONRequestOperation alloc] initWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[APIRoot stringByAppendingFormat:@"/venues/listId?%@=%@&%@=%@", TokenKey, [DEUser token], UDIDKey, [DEUser udid]]]]];

        // dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
        dispatch_queue_t backgroundQueue = dispatch_queue_create("com.name.bgqueue", NULL);
        op.successCallbackQueue = backgroundQueue;

        [op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
             //gettin an array of IDs
            NSArray *array = (NSArray*) responseObject;
            if(array.count)
            {
                _array = array;
                [self getVenuesFromSelfArrayWithCurrentIndex:0];
            }
        } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
            NSLog(@"3rr0r: %@", error);
        }];

        [[NSOperationQueue mainQueue] addOperation:op];

这是一个递归方法的代码:

- (void)getVenuesFromSelfArrayWithCurrentIndex: (NSUInteger)index
{
if(index >= _array.count){ NSLog(@"loading finished!"); return; }
//version of the app, location e.t.c.
NSMutableDictionary *options = [[self options] mutableCopy];
[options setObject:[_array objectAtIndex:index] forKey:@"venueId"];
//method below calls RKs getObjectsAtPath, and it's pretty much the only thing it does
[[DEAPIService sharedInstance] getObjectsOfClass:[DEPlace class]
                                     withOptions:options
                                         success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult){
                                             NSManagedObject *object = [mappingResult.array firstObject];
                                             if([object isKindOfClass:[DEPlace class]])
                                             {
                                                 [self getVenuesFromSelfArrayWithCurrentIndex:index+1];
                                             }
                                         } failure:^(RKObjectRequestOperation *operation, NSError *error){
                                            NSLog(@"Failed to load the place with options: %@", options.description);
                                             [self getVenuesFromSelfArrayWithCurrentIndex:index+1];
                                         }];
}

奇怪的是,启动下一个请求需要~1-2秒(!),并且cpu使用日志和线程看起来很奇怪。

Screenshot 1

Screenshot 2

有什么建议吗?

1 个答案:

答案 0 :(得分:0)

此时我只能建议大约250个请求。您不能在不浪费网络的情况下制作超过4或5个并发网络请求,并在移动设备上停止播放。实际上,您应该更改Web服务设计,以便发送批处理请求,因为这对客户端和服务器都更有效。

无论如何,您可以通过设置对象管理器的maxConcurrentOperationCount的{​​{1}}来限制并发请求。建议将其设置为4。