2

我最近一直在学习 Apple SDK(用于 iPhone 等)并且遇到了一些我无法理解的东西。在http://developer.apple.com/documentation/Cocoa/Conceptual/URLLoadingSystem/Tasks/UsingNSURLConnection.html的“使用 NSURLConnection”的文档中

我发现了一段奇怪的解释和示例代码。首先,它说:

收到 initWithRequest:delegate: 消息后立即开始下载。它可以在委托接收到 connectionDidFinishLoading: 或 connection:didFailWithError: 消息之前的任何时间通过向连接发送取消消息来取消。

接下来,它显示以下代码:

  NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];

  如果(连接){

    // 创建将保存的 NSMutableData

    //接收到的数据

    // receivedData 在别处被声明为方法实例

    receivedData=[[NSMutableData 数据] 保留];

  } 别的 {

    // 通知用户无法下载

  }

因此,在我看来,一旦连接初始化,下载必须立即在不同的线程中开始。这很清楚,因为代码是非阻塞的,并将消息发送回委托,在本例中为 self。然而,receivedData 的(自动释放风格)分配发生另一个线程启动之后。这不是不安全的比赛条件吗?如果服务器响应非常快(例如通过环回设备)或线程调度不顺利,这不会导致崩溃、内存泄漏或数据丢失吗?在初始化theConnection之前分配receivedData,然后在上面的else情况下释放它不是更有意义吗?

我被这段代码弄糊涂了,希望有人能为我解释一下。感谢您提供任何信息,

鲁迪·奇里布拉西

4

2 回答 2

6

没有竞争条件。下载在单独的线程上在后台启动,但发送给代理以通知您下载进度的消息始终在启动下载的线程上调用。

如果您更清楚的话,您当然可以在创建连接之前分配 NSData 。您甚至可以在 connection:didReceiveData: 方法中分配它,如果您想确保除非有数据要存储,否则不会分配 NSData。

我认为该示例的编写方式是使其尽可能短,以免将演示文稿与许多不相关的代码混淆。

NSURLConnection 的文档中

NSURLConnection 的委托方法允许对象接收有关 URL 请求的异步加载的信息回调。其他委托方法提供允许委托自定义执行异步 URL 加载过程的工具。

请注意,这些委托方法将在为关联的 NSURLConnection 对象启动异步加载操作的线程上调用。

于 2009-05-07T03:21:22.120 回答
2

这里没有竞争条件。NSURLConnection使用NSRunLoop来调度其事件。因此,在下一个事件循环开始之前,没有数据可以到达您的手中。

这意味着在下一个事件循环之前不会发生调用connection:didReceiveData:,无论数据何时实际返回,并且connection:didReceiveData:将在开始加载的线程上调用。所以你有这个运行循环的其余部分来让一切井井有条。“立即”在这里的意思是“你不需要做任何事情来启动它”。

这不是推测或可变的实现细节;它基于 Cocoa 的设计原则。为了更好地理解 Cocoa,假设几乎所有事情都发生在主线程上。虽然框架可能偶尔会产生线程作为实现细节,但它们总是会提供一种错觉,即它们没有。因此,就其性质而言,异步操作将始终出现在稍后的事件循环中。合作的,而不是抢占式的,多任务处理是 Cocoa 的方式。

于 2009-05-07T14:54:19.100 回答