【问题标题】:(iOS) Offline Sync DB - Server(iOS) 离线同步数据库 - 服务器
【发布时间】:2013-02-28 00:36:36
【问题描述】:

尝试实现一个应用程序,该应用程序在连接到 Internet 时将存储在本地数据库中的离线数据发送到 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];
        });    
    }
    

【问题讨论】:

  • 如果您上传 x 个项目,则服务器会抛出错误,您将不会更新本地数据库。我做对了吗?也许从那个中打破而不是返回,所以你可以将你的本地数据库更新到成功的地方。
  • 是的。你说对了。我会改变的!
  • @7usam true,除非在发生故障时回滚更改很重要; “全有或全无”的方法。

标签: ios objective-c sqlite synchronization


【解决方案1】:

如果这段代码摆在我面前,我的做法是:

  • 查看用例并定义“大量记录”:一次会定期更新 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 请求的优点。如果您只想获得少量更新,这是YAGNI 和未成熟的优化。

不要让这个决定阻止您发货!

【讨论】:

  • 非常感谢您的有效积分。我会先检查一下。目前我在做什么是不是类似于批处理?我修改了我的代码以使用 Queue!
  • @Nina 抱歉,我对批处理的使用不正确。我已经相应地更新了我的答案。
  • 现在我正在将帖子对象添加到队列中并一个一个地处理..第二个帖子对象只有在第一个完成后才处理..那也是最糟糕的吗?
  • @Nina 所以你描述的是单项处理。如果您有 100 条记录,那就是 100 个 http 请求(1 条记录,1 个请求)。我对你的建议是将它们组合在一起。将 100 条记录分成 10 条一组。然后将该组 10 条作为单个 http 请求(10 条记录,1 条请求)发送。这将使您的网络通信更加高效。这有意义吗?
  • 明白你的意思。分组记录和发布。需要更改服务器端代码。在此之前,我可能需要知道最大离线数 :) 非常感谢。你澄清了我的主要疑虑:)
【解决方案2】:

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

在将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 管道 - 如果服务器支持这一点,这实际上减少了延迟。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多