访问块内的实例变量
Posted
技术标签:
【中文标题】访问块内的实例变量【英文标题】:Accessing Instance variables inside blocks 【发布时间】:2012-10-13 19:27:55 【问题描述】:我有一个关于在像我这样的情况下使用异步块的最佳实践的问题。
例如,我有两个控制器:(假设是controller1和controller2)
我将控制器 2 推入控制器 1:
controller2 * c = [[controller2 alloc] init];
[self.navigationController pushViewController:c animated:YES];
[c release];
controller2 有一个实例变量:
@interface controller2 : UITableViewController
UIImageView * imageView;
分配和释放它:
- (id)init
...
imageView = [[UIImageView alloc] init];
...
- (void)dealloc
[imageView release];
[super dealloc];
controller2 为这个 imageView 下载一张图片:
- (void)viewDidLoad
...
[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:
^(NSURLResponse *response, NSData *data, NSError *error)
UIImage * image = [[UIImage alloc] initWithData:data scale:[[UIScreen mainScreen] scale]];
imageView.image = image;
[image release];
];
显然用户可以按下导航栏顶部的“返回”按钮,我们的controller2的对象将被这个imageView释放。
情况:
开始下载;
控制器弹出(用户按下“返回”按钮)
下载结束,imageView.image = image 导致(?)EXC_BAD_ACCESS(因为imageView被释放)
那么,我应该怎么做才能让它在我的代码中变得更酷呢? 我喜欢积木!与 NSURLConnection 委托相比,乐趣多多,代码/类少。
块可能保留实例变量? ( :OOO )
也许我应该在块之前保留我的实例变量并在块中释放它? (我认为这很愚蠢)
那么,使用此类块的最佳做法是什么? 也许我不应该在这种情况下使用块来使我的代码更好?
p.s.:我尝试这样做:将 NSOperationQueue 作为实例变量,并停止 dealloc 中的所有任务.. 但这会扼杀这个块的优势 :( 在这种情况下,最好将我的下载器类与委托一起使用;(无论如何代码太多。
p.p.s.: 我知道我应该在弹出控制器后停止下载;但我不介意。 让它成为任何任务(例如,转换视频等,任何“繁重”的后台线程),无论如何都应该完成,即使用户离开了这个控制器,但如果它们还活着,它将使用一些实例变量。
谢谢
【问题讨论】:
【参考方案1】:你应该声明你的变量:
__block UIImageView*imageView;
【讨论】:
【参考方案2】:我认为你的块方法很好。我认为是内存管理让你:为什么 controller2 在它的 dealloc 方法中释放 imageView。应该是这样的
[imageView release];
不解除分配。 controller2 是否保留该 imageView?
这会起作用的原因是 NSURLConnection 块将捕获 imageView,因此即使在 controller2 消失后它也会挂起。在您按下回的情况下,控制器消失,imageView 获取一个新图像,然后它也消失了。一切都应该没问题。
我同意你的观点,积木很棒。另一件很棒的是ARC,两者配合得很好。你可以在这个项目中使用 ARC 吗?
【讨论】:
啊抱歉,当然它的发布 :) 不是复制粘贴。更正了。 谢谢你的回答 :) 但是这个 dealloc 不是问题,这只是这个主题的一个错字。【参考方案3】:[NSURLConnection sendAsynchronousRequest:request queue:imageDownloadersQueue completionHandler:^(NSURLResponse *response, NSData *firstImageData, NSError *error)
NSLog(@"first block beginning [self retainCount] = %d, [imagesDictionary retainCount] = %d",[self retainCount], [imagesDictionary retainCount]);
NSURLRequest * request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
UIImage * first_image = [[[UIImage alloc] initWithData:firstImageData scale:[[UIScreen mainScreen] scale]] autorelease];
[NSURLConnection sendAsynchronousRequest:request queue:imageDownloadersQueue completionHandler:^(NSURLResponse *response, NSData *secondImageData, NSError *error)
NSLog(@"second block beginning [self retainCount] = %d, [imagesDictionary retainCount] = %d",[self retainCount], [imagesDictionary retainCount]);
UIImage * second_image = [[[UIImage alloc] initWithData:secondImageData scale:[[UIScreen mainScreen] scale]] autorelease];
if(first_image && second_image)
[imagesDictionary setObject:[NSArray arrayWithObjects:first_image, second_image, nil] forKey:match.match_id];
];
];
第一个块开始 [self retainCount] = 2, [imagesDictionary retainCount] = 1
第二个块开始 [self retainCount] = 2, [imagesDictionary retainCount] = 1
似乎块保留“自我”并在最后释放它 所以“自我”(我的实例)不能在块结束之前被释放
这就是答案,对吧? 希望如此...
谢谢
【讨论】:
以上是关于访问块内的实例变量的主要内容,如果未能解决你的问题,请参考以下文章