0

我有一个关于在像我这样的情况下使用异步块的最佳实践的问题。

例如,我有两个控制器:(让它成为控制器 1 和控制器 2)

我将控制器 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)

  • 也许我应该在块之前保留我的实例变量并在块中释放它?(我认为那很愚蠢)

那么,使用这些块的最佳实践是什么?也许我不应该在这种情况下使用块来使我的代码更好?

ps:我尝试这样做:将 NSOperationQueue 作为实例变量,并停止 dealloc 中的所有任务。但这会扼杀这个块的优势 :( 在这种情况下最好将我的下载器类与委托一起使用 ;( 反正有太多代码。

pps:我知道我应该在弹出控制器后停止下载;但我不介意。让它成为任何任务(例如,转换视频等,任何“繁重的”后台线程),无论如何都应该完成,即使用户离开了这个控制器,但如果它们还活着,它将使用一些实例变量。

谢谢你

4

3 回答 3

1

你应该声明你的变量:

    __block UIImageView*imageView;
于 2012-10-13T19:54:03.473 回答
0
[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

似乎块保留“自我”并在最后释放它,所以“自我”(我的实例)不能在块结束之前释放

这就是答案,嗯?希望如此 ...

谢谢

于 2012-10-15T17:40:00.663 回答
0

我认为你的块方法很好。我认为是内存管理让你:为什么 controller2 在它的 dealloc 方法中释放 imageView。那应该是

[imageView release];

不解除分配。controller2 是否保留该 imageView?

这将起作用的原因是 NSURLConnection 块将捕获 imageView,因此即使在 controller2 消失后它也会挂起。在您按下回的情况下,控制器消失,imageView 获取一个新图像,然后它也消失了。一切都应该没问题。

我同意你的观点,积木很棒。另一件很棒的事情是 ARC,两者配合得很好。你可以在这个项目中使用 ARC 吗?

于 2012-10-13T19:45:41.933 回答