【问题标题】:Background network calls - iOS后台网络调用 - iOS
【发布时间】:2011-10-15 05:55:29
【问题描述】:

我需要在后台实现将一些数据发布到 Web 服务器。澄清一下,通过“在后台”,我并不是指使用AsyncTaskASIHTTPRequest[request startAsynchronous] 方法等显示旋转图标并将数据发布到Web 服务的正常方式。我需要维护一个数据队列,当用户在应用程序中工作时,线程可以异步开始处理和发布到 Web 服务。

我正在寻求一些帮助来设计这样的队列,尤其是在一些边缘情况下,例如用户接到电话、在发布帖子时注销应用程序、用户离开应用程序以转到另一个一个帖子正在发生之类的。你会如何处理这些案件?有没有可以推荐的源代码?

谢谢,
泰迦。

【问题讨论】:

标签: objective-c ios cocoa-touch asynchronous


【解决方案1】:

我最近开始在自己的工作中使用NSOperationQueue 来控制后台网络请求。 NSOperation 处理在后台(或前台,如果 UI 更新需要)的线程上异步运行任务(例如网络操作)所需的大部分样板代码。

它还允许跨队列依赖;例如,我在我的应用程序中使用了两个队列:

第一个计划在后台以一次最多 2 个并发的方式下载图像。每个图像下载都有一个对应的完成处理程序(作为NSBlockOperation),它依赖于图像下载完成。这些操作位于 [NSOperationQueue mainQueue] 上,它在主线程上运行,允许它们更新 UI(特别是对应的 UIImageView)。

注意NSOperationNSOperationQueue并不是只针对网络请求,而是可以划分为原子任务并发调度的任何操作。

Here 是 Apple 关于该主题的介绍文档。

【讨论】:

    【解决方案2】:

    我自己实现了类似的东西,我建议使用服务而不是线程来进行网络调用。这样,即使您的活动被终止,您也可以确定您的网络调用将被执行。

    然后为了实现队列我建议你看看 IntentService (http://developer.android.com/reference/android/app/IntentService.html)

    来自文档:

    IntentService 是处理异步的服务的基类 按需请求(表示为意图)。客户端发送请求 通过 startService(Intent) 调用;服务根据需要启动, 使用工作线程依次处理每个 Intent,并自行停止 当它耗尽工作时。

    这种“工作队列处理器”模式通常用于卸载任务 从应用程序的主线程。 IntentService 类的存在是为了 简化此模式并注意机制。要使用它, 扩展 IntentService 并实现 onHandleIntent(Intent)。 IntentService 将接收 Intent,启动一个工作线程,然后 酌情停止服务。

    所有请求都在单个工作线程上处理——它们可能被视为 只要有必要(并且不会阻塞应用程序的主循环), 但一次只会处理一个请求。

    如果您的应用程序足够简单,您可以使用 sendBroadCast() 在您的活动和 IntentService 之间共享信息和通知

    【讨论】:

    • 同意,但我需要在 iOS、Blackberry 和 Android 上实现这一点,所以我希望我可以避免服务..
    • 好的,我明白你的意思了,在我提交答案之前,我看到你的帖子标题只有 iOS。
    • Android 应用程序是用 Java 编写的,而 iOS 应用程序是用 Objective-C 编写的。我认为您将无法利用相同的代码。 (我知道,NDK 包支持 Android 中的本机代码。)。这可能是最好的 3 个单独的问题。
    • 不必是相同的代码,Android 支持通过服务后台执行代码,而 iOS 和 Blackberry 则没有这样的机制。所以我想知道是否有可能没有服务..
    • 实际上,如果我完全摆脱 Android,它可能会减少混乱。如果它适用于 iOS,我想我可以毫无问题地在 Android 上实现同样的功能。
    【解决方案3】:

    创建一个封装线程的单例:

    在你的对象初始化中:

    [NSThread detachNewThreadSelector:@selector(mainPosterThread) toTarget:self withObject:nil];
    
    - (void)mainDownloaderThread
    {
    
        if( [NSThread respondsToSelector:@selector(setThreadPriority:)] )
        {
            [NSThread setThreadPriority:0.1];
        }
        NSString *urlToDownload = nil;
        while(shouldRun)
        {
            // Take next data to post in a queue (lastObject of a NSArray for example)
            if( nextDataToPost )
            {
                 // Post
            }
            else
            {
                 // Sleep for some time.
            }
        }
    }
    

    您还可以在应用程序在支持多任务的设备上进入后台/前台时停止/启动线程。如果不支持多任务处理,则在停止时将发布数据保存在队列中(如果不是太长)并在开始时恢复它们。最大的挑战是管理能够在应用程序结束时取消当前上传。

    【讨论】:

      【解决方案4】:

      这是我在编写的每一个新应用程序中都在完善的问题。基本上我想要的是异步的网络功能,它是由我使用本机功能编写的。如果您有兴趣,我很乐意向您展示其中的一些代码。

      首先,我建议您使用委托在主线程上异步进行所有网络调用,而不是同步进行。这种方式序列化/同步/并发不是问题。由于类是网络委托,我只需将一个类设置为新连接具有新委托实例的位置。

      [[NSURLConnection alloc] initWithRequest:request delegate:del] autorelease];
      
      e.g.
          - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
      

      【讨论】:

        猜你喜欢
        • 2012-03-25
        • 1970-01-01
        • 1970-01-01
        • 2021-08-03
        • 1970-01-01
        • 1970-01-01
        • 2021-07-04
        • 1970-01-01
        • 2017-06-03
        相关资源
        最近更新 更多