首页 » iOS编程(第4版) » iOS编程(第4版)全文在线阅读

《iOS编程(第4版)》19.4 捕获变量

关灯直达底部

Block对象可以使用其封闭作用域(enclosing scope)内的所有变量。对声明了某个Block对象的方法,该方法的作用域就是这个Block对象的封闭作用域。因此,这个Block对象可以访问该方法的所有局部变量、传入该方法的实参以及所属对象的实例变量。在上述代码中,BNRItem对象(item)和BNRItemCell对象(cell)都是actionBlock封闭作用域中的捕获变量。

如果捕获变量是Objective-C对象,那么Block对象对捕获变量具有强引用。如果捕获变量也对Block对象具有强引用,就会导致强引用循环。之前在actionBlock中创建rect时,Xcode会提示警告信息:“Capturing 'cell' strongly in this block is likely to lead to a strong reference cycle(在Block对象中捕获‘cell’很可能导致强引用循环)”——BNRItemCell对actionBlock具有强引用,actionBlock对BNRItemCell也具有强引用,如图19-14所示。

图19-14 cell和Block对象之间存在强引用循环

解决问题的方法是:将actionBlock对cell的引用改为弱引用。

在BNRItemsViewController.m中修改actionBlock中的代码,使其对cell具有弱引用,代码如下:

__weak *weakCell = cell;

cell.actionBlock = ^{

NSLog(@“Going to show the image for %@”, item);

BNRItemCell *strongCell = weakCell;

if ([UIDevice currentDevice] userInterfaceIdiom == UIUserInterfaceIdiomPad) {

NSString *itemKey = item.itemKey;

// 如果BNRItem对象没有图片,就直接返回

UIImage *img = [[BNRImageStore sharedStore] imageForKey:imageKey];

if (!img)

return;

}

// 根据UITableView对象的坐标系获取UIImageView对象的位置和大小

// 注意:这里也许会出现警告信息,下面很快就会讨论到

CGRect rect = [self.viewconvertRect:cell.thumbnailView.bounds

fromView:cell.thumbnailView];

CGRect rect = [self.viewconvertRect:strongCell.thumbnailView.bounds

fromView:strongCell.thumbnailView];

// 创建BNRImageViewController对象并为image属性赋值

BNRImageViewController *ivc = [[BNRImageViewController alloc] init];

ivc.image = img;

// 根据UIImageView对象的位置和大小

// 显示一个大小为600x600点的UIPopoverController对象

self.imagePopover = [[UIPopoverController alloc]

initWithContentViewController:ivc];

self.imagePopover.delegate = self;

self.imagePopover.PopoverContentSize = CGSizeMake(600, 600)];

[self.imagePopover presentPopoverFromRect:rect

inView:self.view

permittedArrowDirections:UIPopoverArrowDirectionAny

animated:YES];

}

};

在Block对象执行过程中,必须保证Block对象始终可以访问cell。因此,以上代码在actionBlock内部创建了strongCell,以保持对cell的强引用。这与Block对象对捕获变量的强引用不同,strongCell只是在Block对象执行过程中对cell保持强引用。

构建并运行应用,运行结果与之前相同,但是现在应用不会由于强引用循环导致内存泄露。