访问块内的实例变量

时间:2012-10-13 19:27:56

标签: iphone objective-c ios ipad ios5

我对在像我这样的情况下使用异步块的最佳做法有疑问。

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

我在控制器1内推送controller2:

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 =图片原因(?)EXC_BAD_ACCESS(因为imageView已发布)

那么,我应该做些什么来让我的代码变得很酷? 我喜欢积木!与NSURLConnection代表相比,这么多的乐趣和更少的代码/类。

  • 块可能保留实例变量吗? (:OOO)

  • 也许我应该在阻止之前保留我的实例变量并在块中释放它? (我觉得这很傻)

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

p.s。:我试图这样做:将NSOperationQueue作为实例变量,并停止dealloc中的所有任务..但这会杀死此块的优势:( 在这种情况下,最好将我的下载器类与委托一起使用;(无论如何代码太多了。

p.p.s .: 我知道我应该在弹出控制器后停止下载;但我不是这样的。 让它成为任何任务(例如,转换视频等,任何“沉重的”后台线程),即使用户离开了这个控制器也应该这样做,但如果它们还活着,它会使用一些实例变量。

谢谢

3 个答案:

答案 0 :(得分:1)

您应该使用以下内容声明您的变量:

    __block UIImageView*imageView;

答案 1 :(得分:0)

我认为您的阻止方法很好。我认为这是内存管理让你:为什么controller2在它的dealloc方法中取消了imageView。那应该是

[imageView release];

不是dealloc。 controller2是否保留了imageView?

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

我同意你的看法,块很棒。另一件很棒的事情是ARC,两者相处得很好。你能在这个项目中使用ARC吗?

答案 2 :(得分: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

似乎阻止了“自我”并在最后释放它 所以“自我”(我的实例)不能在块结束之前解除分配

答案就是答案,对吧? 希望如此......

谢谢