(iOS) 离线同步数据库 - 服务器

8

尝试实现一个应用程序,当连接到互联网时将存储在本地数据库中的离线数据发送到Web服务器。我使用下面显示的代码。据我测试,它运行良好,但不确定对于大量记录是否有效。我想知道是否有任何调整此代码可以提高性能?

注意

  • I know this would be a worst code for offline sync purpose, so trying to tweak it better.
  • Its a single way synchronization, from app to server.

    -(void)FormatAnswersInJSON {
    
      DMInternetReachability *checkInternet = [[DMInternetReachability alloc] init];
      if ([checkInternet isInternetReachable]) {
         if ([checkInternet isHostReachable:@"www.apple.com"]) {//Change to domain
            responseArray = [[NSMutableArray alloc] init];
    
            dispatch_async(backgroundQueue, ^(void) {
    
                NSArray *auditIDArray = [[NSArray alloc] initWithArray: [self getUnuploadedIDs]];
                for (int temp = 0; temp < [auditIDArray count]; temp ++) {
    
                    // Code to post JSON to server
    
                    NSURLResponse *response;
                    NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
                    if (!error) {
                        NSString *responseID = [[NSString alloc]initWithData:urlData encoding:NSUTF8StringEncoding];
                        if ([responseID isEqualToString:@"ERROR"]) {
                            //Error uploading records
                        } else {
                           [responseArray addObject:responseID];
                        }
                    } else {
                       //Error
                       return;
                    }
                }
                dispatch_async( backgroundQueue, ^{
    
                    /* Based on return code update local DB */
                    for (int temp = 0; temp < [responseArray count]; temp ++) {
                       [self updateRecordsForID:[auditIDArray objectAtIndex:temp] withID:[responseArray objectAtIndex:temp]];
                    }
                });
            });
         }
      }
    }
    
    - (void)upload { //Called when internet connection available
    
        if(backgroundQueue){
            dispatch_suspend(backgroundQueue);
            dispatch_release(backgroundQueue);
            backgroundQueue = nil;
        }
        backgroundQueue = dispatch_queue_create("com.XXXX.TestApp.bgqueue", NULL);
        dispatch_async(backgroundQueue, ^(void) {
            [self FormatAnswersInJSON];
        });    
    }
    

1
如果您上传x个项目时,服务器会出错,那么您将无法更新本地数据库。我理解得对吗?也许不要使用return而使用break,这样您就可以将本地数据库更新为已成功的内容。 - 7usam
是的,你说得对。我会改变那个!! - Nina
1
@7usam,如果在失败发生时回滚更改很重要的话,则为真;否则采用“全有或全无”的方法。 - StoriKnow
2个回答

1
如果这段代码在我面前,我的做法是:
  • 查看使用情况并定义“大量记录”的范围:每次会定期更新50条记录吗?还是只有1或2条?我的用户是否有wifi连接,还是通过付费网络连接?等等。
  • 如果可能,在实际环境中进行测试。如果我的用户群体足够小,收集真实数据并根据数据指导我的决策,或者仅将该功能发布给一部分用户/测试版并进行测量。
  • 如果数据告诉你需要,那么优化这段代码以使其更有效率。
我的优化方法是进行分组处理。粗略算法大致如下:
for records in groups of X
  collect
  post to server {
    on return:
      gather records that updated successfully
      update locally
  }

假设您可以修改服务器代码。您可以分组为10、20、50等,这取决于发送的数据类型和大小。
分组算法意味着需要在客户端进行更多的预处理,但它的好处是减少HTTP请求。如果您只会收到少量更新,则此操作YAGNI并且是过早的优化。 不要让此决定阻止您的发货!

非常感谢您提供的有价值的观点。我会先检查它们。目前我正在做的不是类似于批处理吗?我有点修改了我的代码来使用“队列”! - Nina
@Nina 对不起,我的批处理使用方法不正确。我已经相应地更新了我的答案。 - Gavin Miller
现在我正在将帖子对象添加到队列中,并逐个处理...第二个帖子对象只有在第一个完成后才会处理..这样会更糟吗? - Nina
@Nina 所描述的是单项处理。如果有 100 条记录,那就需要 100 个 HTTP 请求(1 条记录,1 个请求)。我为你建议的是将它们分组。将 100 条记录分成每组 10 条。然后将这 10 条记录作为一个 HTTP 请求发送(10 条记录,1 个请求)。这样会使你的网络通信更加高效。这样做是否合理? - Gavin Miller
明白了你的意思。需要对记录进行分组和发布。需要更改服务器端代码。在此之前,我可能需要知道最大离线计数 :) 非常感谢。你解决了我的主要疑虑 :) - Nina

0
你的代码有几个问题。一个约定是在测试错误参数之前始终检查返回值。即使方法成功,错误参数可能已设置。
当使用NSURLConnection进行任何不是快速示例或测试的操作时,您还应始终使用异步风格并处理委托方法。由于正确使用NSURLConnection可能很快变得繁琐且容易出错,因此我建议使用第三方框架,该框架封装了NSURLConnection对象和所有连接相关的状态信息作为NSOperation的子类。您可以在Apple示例中找到一个示例实现:QHTTPOperation。另一个合适的第三方框架是AFNetworking(位于GitHub上)。
当您使用委托的异步样式或第三方子类时,您可以取消连接,检索详细的错误或进度信息,执行身份验证等等 - 这些都无法使用同步API完成。
我认为一旦您完成这个步骤并且您的方法能够正确运行,您可以测试性能是否可接受。但是,除非您有大量数据 - 例如大于2 MByte - 否则我不会过于担心。
如果您的数据变得非常大,比如>10 MByte,您需要考虑改进您的方法。例如,您可以将POST数据提供为文件流而不是NSData对象(请参见NSURLRequest的属性HTTPBodyStream)。使用流避免将所有POST数据加载到RAM中,这有助于缓解有限的RAM问题。
如果您有较小的POST数据,但可能有很多个,您可以考虑使用NSOperationQueue,在其中放置您的NSOperation连接子类。将最大并发操作数设置为2。这样,如果服务器支持HTTP pipelining,则可能利用它,从而减少延迟。
当然,您的应用程序中可能还有其他部分,例如创建或检索要发送的数据,这可能会影响整体性能。但是,如果您的代码正确且利用了调度队列或NSOperations,让事情并行执行,那么改进连接性能的选项就不多了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接