调用NSURLConnectionDataDelegate方法来下载图像只偶尔工作

我目前在我的故事板中有两个UIImageView ,其中一个下载我自己的Facebook个人资料图片,另一个是朋友的个人资料图片。

故事板布局

然而,我的问题是, 只有60%的时间按预期工作 ,而另外40%的时间是我自己的个人资料图片出现在我的朋友的照片应显示在底部,而顶部框仍然是空的。 我不确定这是否是我下载或完成视图时调用NSURLConnectionDataDelegate方法的结果,或者是调用到Facebook的请求的性质。

我已经将我的两个请求的精简版本粘贴到了viewDidLoad ,一个获取我自己的个人资料图片,另一个获取我的朋友的图片:

 // ----- Gets my own profile picture, using requestForMe ----- FBRequest *request = [FBRequest requestForMe]; [request startWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) { //handle response if(!error){ //Some methods not included for breveity, includes facebookID used below NSURL *pictureURL = [NSURL URLWithString:[NSString stringWithFormat:@"https://graph.facebook.com/%@/picture?type=large&return_ssl_resources=1", facebookID]]; self.imageData = [[NSMutableData alloc] init]; switcher = 1; NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:pictureURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:2.0f]; NSURLConnection *urlConnection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self]; if (!urlConnection){ NSLog(@"Failed to download picture"); } } }]; // ----- Gets a profile picture of my friend, using requestForMyFriends ----- FBRequest *requestForFriends = [FBRequest requestForMyFriends]; [requestForFriends startWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) { if(!error){ //Other methods not included, including facebookFriendID NSURL *friendPictureURL = [NSURL URLWithString:[NSString stringWithFormat:@"https://graph.facebook.com/%@/picture?type=large&return_ssl_resources=1", facebookFriendID]]; self.supportImageData = [[NSMutableData alloc] init]; switcher = 2; NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:friendPictureURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:2.0f]; NSURLConnection *urlConnection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self]; if (!urlConnection){ NSLog(@"Failed to download picture"); } } }]; 

这两个请求都调用NSURLConnectionDataDelegate方法,并使用switcher决定何时加载哪个图片:

 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { // As chuncks of the image are received, we build our data file if (switcher == 1) [self.imageData appendData:data]; if (switcher == 2)[self.supportImageData appendData:data]; } - (void)connectionDidFinishLoading:(NSURLConnection *)connection { //When the entire image is finished downloading if (switcher == 1) { UIImage *image = [UIImage imageWithData:self.imageData]; //puts the completed picture into the UI self.titleImageView.image = image; [self.titleImageView setClipsToBounds:YES]; } if (switcher == 2) { UIImage *supportImage = [UIImage imageWithData:self.supportImageData]; self.supportImageView.image = supportImage; [self.titleImageView setClipsToBounds:YES]; } } 

你有两个asynchronous进程,这两个进程都可能导致自己的NSURLConnectionDataDelegate方法被调用。 但是,如果它们同时发生,它们将会彼此NSMutableData (大概是使用一个NSMutableDatavariables来引用正在下载的数据)。

要么创build专门的类,您可以为每个NSURLConnection请求实例化一次(基于NSOperation的方法,如AFNetworking ,是理想的),也可以使用sendAsynchronousRequest 。 但是不要同时使用单个对象作为两个并发NSURLConnection请求的delegate


如果你想看到一个简约的下载操作,它可能看起来像:

 // NetworkOperation.h #import <Foundation/Foundation.h> typedef void(^DownloadCompletion)(NSData *data, NSError *error); @interface NetworkOperation : NSOperation - (id)initWithURL:(NSURL *)url completion:(DownloadCompletion)completionBlock; @property (nonatomic, copy) NSURL *url; @property (nonatomic, copy) DownloadCompletion downloadCompletionBlock; @end 

 // NetworkOperation.m #import "NetworkOperation.h" @interface NetworkOperation () <NSURLConnectionDataDelegate> @property (nonatomic, readwrite, getter = isExecuting) BOOL executing; @property (nonatomic, readwrite, getter = isFinished) BOOL finished; @property (nonatomic, strong) NSMutableData *data; @end @implementation NetworkOperation @synthesize finished = _finished; @synthesize executing = _executing; - (id)initWithURL:(NSURL *)url completion:(DownloadCompletion)downloadCompletionBlock { self = [super init]; if (self) { self.url = url; self.downloadCompletionBlock = downloadCompletionBlock; _executing = NO; _finished = NO; } return self; } #pragma mark - NSOperation related stuff - (void)start { if ([self isCancelled]) { self.finished = YES; return; } self.executing = YES; NSURLRequest *request = [NSURLRequest requestWithURL:self.url]; NSAssert(request, @"%s: requestWithURL failed for URL '%@'", __FUNCTION__, [self.url absoluteString]); NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO]; [connection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; [connection start]; } - (void)setExecuting:(BOOL)executing { [self willChangeValueForKey:@"isExecuting"]; _executing = executing; [self didChangeValueForKey:@"isExecuting"]; } - (void)setFinished:(BOOL)finished { [self willChangeValueForKey:@"isFinished"]; _finished = finished; [self didChangeValueForKey:@"isFinished"]; } - (BOOL)isConcurrent { return YES; } #pragma mark NSURLConnectionDataDelegate methods - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { self.data = [NSMutableData data]; } - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { if ([self isCancelled]) { [connection cancel]; self.executing = NO; self.finished = YES; return; } [self.data appendData:data]; } - (void)connectionDidFinishLoading:(NSURLConnection *)connection { if (self.downloadCompletionBlock) { [[NSOperationQueue mainQueue] addOperationWithBlock:^{ self.downloadCompletionBlock(self.data, nil); self.downloadCompletionBlock = nil; }]; } self.executing = NO; self.finished = YES; } - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { if (self.downloadCompletionBlock) { [[NSOperationQueue mainQueue] addOperationWithBlock:^{ self.downloadCompletionBlock(nil, error); self.downloadCompletionBlock = nil; }]; } self.executing = NO; self.finished = YES; } @end 

然后,当你想使用它,它可能看起来像:

 NSOperationQueue *networkQueue = [[NSOperationQueue alloc] init]; queue.maxConcurrentOperationCount = 4; // ----- Gets my own profile picture, using requestForMe ----- FBRequest *request = [FBRequest requestForMe]; [request startWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) { //handle response if(!error) { //Some methods not included for breveity, includes facebookID used below NSURL *pictureURL = [NSURL URLWithString:[NSString stringWithFormat:@"https://graph.facebook.com/%@/picture?type=large&return_ssl_resources=1", facebookID]]; [networkQueue addOperation:[[NetworkOperation alloc] requestWithURL:pictureURL completion:^(NSData *data, NSError *error) { if (!error) { self.meImageView.image = [UIImage imageWithData:data]; } }]]; } }]; // ----- Gets a profile picture of my friend, using requestForMyFriends ----- FBRequest *requestForFriends = [FBRequest requestForMyFriends]; [requestForFriends startWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) { if(!error){ //Other methods not included, including facebookFriendID NSURL *friendPictureURL = [NSURL URLWithString:[NSString stringWithFormat:@"https://graph.facebook.com/%@/picture?type=large&return_ssl_resources=1", facebookFriendID]]; [networkQueue addOperation:[[NetworkOperation alloc] requestWithURL:friendPictureURL completion:^(NSData *data, NSError *error) { if (!error) { self.friendImageView.image = [UIImage imageWithData:data]; } }]]; } }];