异步请求和委派可能存在风险

时间:2010-10-28 19:22:54

标签: iphone objective-c ios

我想向UIImageView添加使用url设置图像的能力。结果我想做点什么。

[anImageView setImageWithContentAtUrl:[NSURL URLWithString:@"http://server.com/resource.png"]];

所以我创建了一个类别(下面的代码)。

NSString *kUserInfoImageViewKey = @"imageView";
NSString *kUserInfoActivityIndicatorKey = @"activityIndicator";

@implementation UIImageView (asynchronous)

#pragma mark -
- (void)setImageWithContentAtUrl:(NSURL *)imageUrl andActivityIndicator:(UIActivityIndicatorView *)activityIndicatorOrNil {
   [activityIndicatorOrNil startAnimating];

 NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
 [dict setValue:self forKey:kUserInfoImageViewKey];
 [dict setValue:activityIndicatorOrNil forKey:kUserInfoActivityIndicatorKey];

 ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:imageUrl];
 request.delegate = self;
 request.userInfo = dict;
   [dict release];
 [request startAsynchronous];
}

#pragma mark -
#pragma mark private

- (void)requestFinished:(ASIHTTPRequest *)aRequest {
 // get concerned view from user info
 NSDictionary *dictionary = aRequest.userInfo;
   UIImageView *imageView = (UIImageView *)[dictionary valueForKey:kUserInfoImageViewKey];
 UIActivityIndicatorView *activityIndicator = (UIActivityIndicatorView *) [dictionary valueForKey:kUserInfoActivityIndicatorKey];

   [activityIndicator stopAnimating];

   NSData *responseData = [aRequest responseData];
 UIImage * image = [[UIImage alloc] initWithData:responseData];

 imageView.image = image;
 [image release];
}

- (void)requestFailed:(ASIHTTPRequest *)request {
}

创建ASIHTTPRequest并以图像作为委托启动。我认为如果在ASIHTTPRequest返回结果之前取消分配图像会有风险。

所以,也许在setImageWithContentAtUrl中添加一个retain:并在requestFinished:和requestFailed中添加一个版本:但我不是很自信。

怎么可能做这些事情?

此致 昆汀

1 个答案:

答案 0 :(得分:1)

昆丁

我经常使用ASIHTTPRequest进行异步调用,所以我知道你来自哪里。此外,第一次设置是一件痛苦的事,但是你知道Three20库的TTImageView(我认为是这样)已经做了你想做的事情吗?它甚至会在本地缓存图像,因此您不必每次都加载它。反正。

您的担心是正确的:ASIHTTPRequest是NSOperation对象的包装器(它实际上是一个子类),因此只要请求处于活动状态,NSOperationQueue就会保留ASIHTTPRequest。

如果您的用户更改视图(例如,在导航栏控制器上),然后取消分配您的UIImageView,则代码可能会在尝试回拨给代理时崩溃。因此,当您取消分配图像视图时,最好保留对请求的引用,然后取消它。

而不是类别,这可能是子类化更好的时候之一 - 因为你想要覆盖dealloc方法(这就是我处理这个问题的方法)。

首先,将此属性添加到您的子类:

@property (nonatomic, retain) ASIHTTPRequest *request;

然后将此行添加到您的方法中,以便您可以继续:

self.request = request;

最后,在您的ASIHTTPRequest委托方法中,销毁引用:

self.request = nil;

然后你的dealloc看起来像这样:

- (void) dealloc
{
  if (self.request)
  {
    // Cancels the NSOperation so ASIHTTPRequest doesn't call back to this
    [self.request cancel];
  }
  [request release];
  [super dealloc]
}