网络请求被当作是比较耗时的操作,因此建议所有的网络操作都处理成异步的,并且在后台线程中来执行。在iOS开发中,实现异步的方法常见的有两种:
1、使用GCD的方式
2、使用NSOperation来做。
下面详细地介绍一下:
All your networking should be done asynchronously. However, with Grand Central Dispatch, you sometimes see code like this:
// Warning: please don't use this code.
dispatch_async(backgroundQueue, ^{
NSData *contents = [NSData dataWithContentsOfURL:url];
dispatch_async(dispatch_get_main_queue(), ^{
// do something with the data
});
});
以上方法最大的缺点就是不能执行取消操作
This might look quite smart, but there is a big problem with this code: there is no way to cancel this synchronous network call. It will block the thread until it's done. In case operation times out, this might take a very long time (e.g. dataWithContentsOfURL has a timeout of 30 seconds).
If the queue is a serial queue, then it will be blocked for the whole time. If the queue is concurrent, then GCD has to spin up a new thread in order to make up for the thread which you are blocking. Both cases are not good. Its best to avoid blocking altogether.
利用NSOperation,可以实现对并发任务数的控制,管理任务之间的依赖关系, 同时还可以取消一个任务。
To improve upon this situation, we will use the asynchronous methods of NSURLConnection and wrap everything up in an operation. This way we get the full power and convenience of operation queues; we can easily control the number of concurrent operations, add dependencies, and cancel operations.
However, there is something to watch out for when doing this: URL connections deliver their events in a run loop. It is easiest to just use the main run loop for this, as the data delivery doesn't take much time. Then we can dispatch the processing of the incoming data onto a background thread.
Another possibility is the approach that libraries like AFNetworking take: create a separate thread, set up a run loop on this thread, and schedule the url connection there. But you probably wouldn't want to do this yourself.
To kick off the URL connection, we override the start method in our custom operation subclass:
- (void)start {
NSURLRequest *request = [NSURLRequest requestWithURL:self.url];
self.isExecuting = YES;
self.isFinished = NO;
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.connection = [NSURLConnection connectionWithRequest:request delegate:self];
}];
}
Since we override the start method, we now must manage the operation's state properties, isExecuting and isFinished, ourselves. To cancel an operation, we need to cancel the connection and then set the right flags so the oepration queue knows the operation is done.
- (void)cancel {
[super cancel];
[self.connection calcel];
self.isFinished = YES;
self.isExecuting = NO;
}
When the connection finishes loading, it sends a delegate callback:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
self.data = self.buffer;
self.buffer = nil;
self.isExecuting = NO;
self.isFinished = YES;
}
And that's all there is to it.To conclude, we would like to recommend either taking your time to do this right, or to use a library like AFNetworking. They provide handy utilities like a category on UIImageView that asynchronously loads an p_w_picpath from a URL. Using this in your table view code will automatically take care of canceling p_w_picpath loading operations.
转载于:https://blog.51cto.com/1150596/1596202