【问题标题】:Best practice to send a lot of data in background on iOS4 device?在 iOS4 设备上在后台发送大量数据的最佳做法?
【发布时间】:2011-04-25 03:19:59
【问题描述】:

我有一个需要向服务器发送数据(使用 POST)的应用。此功能必须在 NavigationController 子控制器之一上,并且用户应该能够离开此控制器和/或关闭应用程序(仅支持 iPhone4/iOS4)。 我应该使用线程/NSOperations 或/和使用现有的异步方法发送数据吗? 任何想法/最佳实践如何实施?

【问题讨论】:

    标签: iphone ios multithreading grand-central-dispatch nsoperation


    【解决方案1】:

    对于需要在用户执行其他操作时运行的任何长时间运行的进程,我肯定会建议使用第二个线程。

    您需要考虑的另一件事是,如果用户启动进程然后点击主页按钮会发生什么。服务端交互被打断会如何影响?当用户下次进入应用程序时,它可以继续吗?等等

    【讨论】:

    • 这些正是我需要调查的问题。如果在新线程中发送数据,是否需要使用异步或同步方法来发布数据?..
    【解决方案2】:

    使用 ASIHTTP 并设置队列。您需要的所有信息都可以在这里找到:

    http://allseeing-i.com/ASIHTTPRequest/

    这是完成您想要完成的任务的最简单方法。对于发送大量数据,最好在后台发送以保持 UI 响应。 ASIHTTPRequest 提供了启动多个查询所需的所有方法(即进度检查、回调等)。

    大量出色的 iPhone 应用都在使用它。

    【讨论】:

    • 因为好的网络代码不需要单独的线程。您是什么意思“设置异步队列”?一个NSOperationQueue?这是完全没有必要的。
    • 我的意思是让帖子在后台运行,以免占用 UI。
    • 我怎样才能让这个队列在后台执行(关闭应用程序后)?
    • 对于不在前台的应用程序,Apple 不允许后台处理,例如您想做的事情。请查看我上面提供的 ASIHTTPRequest 答案。这就是你所需要的。
    • ASIHttpRequest 有一个名为 shouldContinueWhenAppEntersBackground 的标志。将其设置为是,您就可以免费获得背景。
    【解决方案3】:

    我只会使用 NSURLConnection。如果要发送 multipart/form-data 有点棘手(参见 SimpleURLConnections/PostController.m 示例)。我会把它放在应用程序委托中,但我就是那样懒惰。

    你根本不应该担心线程,除非非阻塞 I/O(即 NSURLConnection)太慢。线程有自己的开销,线程间通信很痛苦,死锁很可怕。

    需要做的是启动一个后台任务以允许您的应用在后台继续执行(在 connectionDidFinishLoading: 和 connection:didFailWithError 中结束后台任务)。后台应用程序有大约 10 分钟的时间来完成执行后台任务。

    【讨论】:

    • 好的,问题来了:如何让已经启动的线程(这里:NSURLConnection)在应用关闭后继续在后台执行?
    【解决方案4】:

    好的,我会回答我自己的问题。 首先,就像tc说的,最好在应用程序委托上有这个调用,这样可以关闭NavigationController中的View。 其次,用beginBackgroundTaskWithExpirationHandler:标记后台处理的开始,用endBackgroundTask:结束它,如下所示:

    .h:

    UIBackgroundTaskIdentifier bgTask;

    .m:

    - (void)sendPhoto:(UIImage *)image
    {
      UIApplication *app = [UIApplication sharedApplication];
    
      bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ 
        [app endBackgroundTask:bgTask]; 
        bgTask = UIBackgroundTaskInvalid;
      }];
    
    
      NSLog(@"Sending picture...");
    
      // Init async NSURLConnection
    
      // ....
    }
    
    - (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    
      NSLog(@"Picture sent.");
      
      UIApplication *app = [UIApplication sharedApplication];
    
      if (bgTask != UIBackgroundTaskInvalid) {
        [app endBackgroundTask:bgTask]; 
        bgTask = UIBackgroundTaskInvalid;
      }
    }
    

    在 iOS 终止您的应用之前,您有 10 分钟的时间。你可以通过[app backgroundTimeRemaining]查看这个时间

    【讨论】:

    • 好吧,我确实在很多帖子中看到了 10 分钟的时间限制,但有人提到您可以通过调用 beginBackgroundTaskWithExpirationHandler 进一步延长时间限制:再次参考:stackoverflow.com/questions/3291840/…
    • @CocoaPriest 你超过了 10 分钟的时间限制吗?
    • 你需要在 applicationDidEnterBackground 中做些什么吗?
    • 声明 UIBackgroundTaskIdentifier bgTask 时出现错误;在我的标题中,它应该在“@interface”调用之外吗?当我将它发布到“@end”下面时,XCode 没有抱怨,但它仍然不起作用
    • 不调用 endBackgroundTask 方法会怎样。
    【解决方案5】:

    我想支持提到的帖子:

    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ 
          [app endBackgroundTask:bgTask]; 
    
          bgTask = UIBackgroundTaskInvalid;
    }];
    

    但也要指出,您可能还希望将工作单元封装在 NSOperation 子类中。这将使它具有极强的可重用性,并且当与 NSOperationQueue 结合使用时,会自动处理线程等等。稍后,当您想要更改代码,或将其显示在应用程序的不同位置时,移动或编辑将是微不足道的。

    关于使用操作队列的一个注意事项是,在这种情况下,您实际上希望从队列中发送一个同步 url 请求。这将使您不必担心并发操作。以下是您可能会发现有用的链接:

    http://www.cimgf.com/2008/02/16/cocoa-tutorial-nsoperation-and-nsoperationqueue/

    【讨论】:

    • 不建议使用同步连接。是的,您正在尝试解决队列的运行循环在您的连接有时间完成(并发送相关的委托回调消息)之前退出的问题,但同步连接并不是最好的方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多