我在我的课程中定义了以下setter,它扩展了UICollectionView
:
// @interface ClipsDataSource : NSObject <UICollectionViewDataSource>
- (void)setProject:(Project *)project
{
_project = project;
ClipsDataSource *dataSource = [[ClipsDataSource alloc] initWithCollectionView:self];
dataSource.delegate = self;
dataSource.fetchedResultsController = project.clipsResultsController;
self.dataSource = dataSource;
}
当我运行我的应用程序时,我得到以下异常:
-[CALayerArray numberOfSectionsInCollectionView:]: unrecognized selector sent to instance 0x174245490
我意识到实例指针是我在setter中使用的局部变量的地址;班级名称显然是随机的。从这个“发现”我推断该对象在分配后被释放。
通常,Xcode会通过以下方式警告我这些问题:
将保留对象分配给不安全的属性;对象将在转让后释放。
当然,如果我将代码更改为此,我会看到警告:
self.dataSource = [[ClipsDataSource alloc] initWithCollectionView:self];
我有两个问题:
.dataSource
被认为是不安全的财产?它被定义为(nonatomic, assign)
。答案 0 :(得分:1)
1)为什么Xcode没有显示警告?
因为clang不够智能,无法确定您的数据源实例不会保留在其他位置;只会报告这个明显的案例:
self.dataSource = [[ClipsDataSource alloc] initWithCollectionView:self];
2)为什么.dataSource被认为是不安全的财产?它定义为(非原子,分配)。
这样做是为了防止使用自引用构造的保留周期,这在ViewController
代码中经常发生。
想象一下,您的CollectionViewController
是CollectionView
的数据源,
self.collectionView.dataSource = self;
这意味着:
CollectionViewController
保留.collectionView
,因为默认情况下,视图控制器会保留其视图。 CollectionView
保留了它的数据源(CollectionViewController
)。这将导致保留周期,因此Apple决定对.datasource
使用不安全的未保留指针。
请注意,assign
和weak
指针都不会保留它们指向的对象。它们之间的区别在于,当引用的对象被释放时,weak
将自动无效。
但assign
指针不会无效,因此它将继续指向内存地址。进一步取消引用该指针(在重新分配之后)可能会导致EXC_BAD_ACCESS
,或者您将获得另一个对象(因为在解除分配后可以在该地址中写入另一个对象)。