(iOS)脱机同步数据库-服务器

(iOS)脱机同步数据库-服务器,ios,objective-c,sqlite,synchronization,Ios,Objective C,Sqlite,Synchronization,正在尝试实现一个应用程序,该应用程序在连接到internet时将存储在本地db上的脱机数据发送到web服务器。我使用下面显示的代码。据我测试,它工作良好,不确定它是否能在大量记录中正常工作。我想知道这段代码上的任何调整是否会提高性能 注意 我知道这对于脱机同步来说是最糟糕的代码,所以请尝试 更好地调整它 这是一种从应用程序到服务器的单向同步 -(void)FormatAnswersInJSON { DMInternetReachability *checkInternet = [[DMI

正在尝试实现一个应用程序,该应用程序在连接到internet时将存储在本地db上的脱机数据发送到web服务器。我使用下面显示的代码。据我测试,它工作良好,不确定它是否能在大量记录中正常工作。我想知道这段代码上的任何调整是否会提高性能

注意

  • 我知道这对于脱机同步来说是最糟糕的代码,所以请尝试 更好地调整它
  • 这是一种从应用程序到服务器的单向同步

    -(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];
        });    
    }
    
    -(void)FormatAnswersInJSON{
    DMInternetReachability*checkInternet=[[DMInternetReachability alloc]init];
    如果([checkInternet IsInternetReach]){
    如果([checkInternet isHostReachable:@“www.apple.com”]){//更改为域
    responseArray=[[NSMutableArray alloc]init];
    调度异步(后台队列,^(无效){
    NSArray*auditIDArray=[[NSArray alloc]initWithArray:[self getUnuploadedIDs]];
    对于(int temp=0;temp<[darray count];temp++){
    //将JSON发布到服务器的代码
    NSURLResponse*响应;
    NSData*urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&响应错误:&错误];
    如果(!错误){
    NSString*responseID=[[NSString alloc]initWithData:urlData编码:NSUTF8StringEncoding];
    如果([responseID isEqualToString:@“ERROR”]){
    //上载记录时出错
    }否则{
    [responseArray addObject:responseID];
    }
    }否则{
    //错误
    返回;
    }
    }
    调度异步(后台队列^{
    /*基于返回码更新本地数据库*/
    对于(int-temp=0;temp<[responseArray count];temp++){
    [self-updateRecordsForID:[AuditorDarray objectAtIndex:temp]ID:[responseArray objectAtIndex:temp];
    }
    });
    });
    }
    }
    }
    -(void)上载{//在internet连接可用时调用
    if(背景队列){
    调度挂起(后台队列);
    调度发布(后台队列);
    backgroundQueue=nil;
    }
    backgroundQueue=dispatch\u queue\u create(“com.XXXX.TestApp.bgqueue”,NULL);
    调度异步(后台队列,^(无效){
    [自格式应答JSON];
    });    
    }
    

如果这个代码摆在我面前,我的方法是:

  • 查看用例并定义“大量记录”:一次会定期更新50条记录吗?还是在1s和2s内?我的用户是否有wifi连接,或者是通过付费网络连接?等等
  • 如果可能,在野外测试。如果我的用户群足够小,收集真实的数据并让这些数据指导我的决策,或者只向一部分用户发布该功能/beta测试和度量
  • 如果数据告诉您,则优化此代码以提高效率
我的优化途径是进行分组处理。粗略算法如下所示:

for records in groups of X
  collect
  post to server {
    on return:
      gather records that updated successfully
      update locally
  }
这假设您可以修改服务器代码。您可以进行10、20、50等分组。所有这些都取决于发送的数据类型和大小

组算法意味着更多的预处理客户端,但有减少HTTP请求的优点。如果你只打算得到少量的更新,那么这是一个简单的、预先成熟的优化


不要让这个决定妨碍您发货

您的代码有几个问题。一种约定是在测试错误参数之前始终检查返回值。可能会设置错误参数-即使方法成功

当使用
NSURLConnection
进行快速示例或测试以外的任何操作时,还应始终使用异步样式来处理委托方法。由于正确使用
NSURLConnection
可能会很快变得麻烦且容易出错,因此我建议使用第三方框架,将
NSURLConnection
对象和所有与连接相关的状态信息封装为
NSOperation
的子类。您可以在Apple示例中找到一个示例实现:
QHTTPOperation
。另一个合适的第三方框架是AFNetworking(在GitHub上)

当您对委托或第三方子类使用异步样式时,您可以取消连接、检索详细的错误或进度信息、执行身份验证等,而同步API无法做到这一点

我认为,一旦您完成了这一点,并且您的方法工作正常,您就可以测试性能是否可以接受。但是除非你有大数据,比如说大于2M字节,否则我不会太担心

如果你的数据变得非常大,比如说10兆字节,你需要考虑改进你的方法。例如,可以将POST数据作为文件流提供,而不是作为
NSData
对象提供(请参见
NSURLRequest
的属性
HTTPBodyStream
)。使用流可以避免将所有POST数据加载到RAM中,这有助于缓解有限的RAM问题

如果您有较小的POST数据,但可能有很多,可以考虑使用<代码> NSO操作队列> />代码>您放置< <代码> NStase< /Cord>连接子类。将最大并发操作数设置为2。然后,如果服务器支持HTTP管道,这可能会利用HTTP管道,从而有效地减少延迟

当然,应用程序中可能还有其他部分,例如您创建或检索必须发送的数据,这可能会影响整体性能。但是,如果您的代码是可靠的,并且使用了调度队列或NSO操作,从而使事情并行执行,那么就没有更多的选项来提高