我在我的类中定义了以下扩展 UICollectionView
的 setter:
// @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 会通过以下方式警告我这些问题:
Assigning retained object to unsafe property; object will be released after assignment.
果然,如果我将代码更改为以下内容,我会看到警告:
self.dataSource = [[ClipsDataSource alloc] initWithCollectionView:self];
我有两个问题:
- 为什么 Xcode 不显示警告?
- 为什么
.dataSource
被认为是不安全的属性?它被定义为(nonatomic, assign)
。
最佳答案
1) 为什么 Xcode 不显示警告?
因为 clang 不够智能,无法判断你的数据源实例不会保留在别处;只会报告这种明显的情况:
self.dataSource = [[ClipsDataSource alloc] initWithCollectionView:self];
2) 为什么 .dataSource 被认为是不安全的属性?它被定义为(非原子,分配)。
这样做是为了防止自引用结构的保留循环,这在 ViewController
代码中经常发生。
假设您的 CollectionViewController
是 CollectionView
的数据源,
self.collectionView.dataSource = self;
这意味着:
CollectionViewController
保留.collectionView
,因为 View Controller 默认保留它们的 View 。CollectionView
保留其数据源(即CollectionViewController
)。
这将导致保留循环,因此 Apple 决定对 .datasource
使用不安全的未保留指针。
请注意,assign
和weak
指针都不会保留它们指向的对象。它们的区别在于weak
会在被引用的对象被释放时自动失效。
但是 assign
指针不会被取消,所以它会继续指向内存地址。对该指针的进一步取消引用(在解除分配后)可能会导致 EXC_BAD_ACCESS
,或者您将获得另一个对象(因为在解除分配后可以在该地址中写入另一个对象)。
关于ios - 将本地对象分配给 UICollectionView 的数据源时崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27400734/