ios - 将本地对象分配给 UICollectionView 的数据源时崩溃

标签 ios objective-c xcode

我在我的类中定义了以下扩展 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];

我有两个问题:

  1. 为什么 Xcode 不显示警告?
  2. 为什么 .dataSource 被认为是不安全的属性?它被定义为 (nonatomic, assign)

最佳答案

1) 为什么 Xcode 不显示警告?

因为 clang 不够智能,无法判断你的数据源实例不会保留在别处;只会报告这种明显的情况:

self.dataSource = [[ClipsDataSource alloc] initWithCollectionView:self];

2) 为什么 .dataSource 被认为是不安全的属性?它被定义为(非原子,分配)。

这样做是为了防止自引用结构的保留循环,这在 ViewController 代码中经常发生。

假设您的 CollectionViewControllerCollectionView 的数据源,

self.collectionView.dataSource = self;

这意味着:

  • CollectionViewController 保留 .collectionView,因为 View Controller 默认保留它们的 View 。
  • CollectionView 保留其数据源(即 CollectionViewController)。

这将导致保留循环,因此 Apple 决定对 .datasource 使用不安全的未保留指针。

请注意,assignweak 指针都不会保留它们指向的对象。它们的区别在于weak会在被引用的对象被释放时自动失效。

但是 assign 指针不会被取消,所以它会继续指向内存地址。对该指针的进一步取消引用(在解除分配后)可能会导致 EXC_BAD_ACCESS,或者您将获得另一个对象(因为在解除分配后可以在该地址中写入另一个对象)。

关于ios - 将本地对象分配给 UICollectionView 的数据源时崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27400734/

相关文章:

iphone - NSDateFormatter dateFromString 返回 nil

ios - 在项目选择上调用委托(delegate)方法

swift - 如何使用 sprite Kit 制作自动卷轴游戏?

ios - 在 ARKit 中映射 GPS 坐标

ios - 使用 ionic 创建 IPA 文件

ios - 如何在 Swift 中让按钮随背景滚动?

当应用程序未连接到 xcode 时,iOS 8 静默推送通知不会触发 didReceiveRemoteNotification 方法

ios - 带有关闭按钮的代币

objective-c - 返回可变大小字节数组并释放内存

ios - CALayer 位置包含 NaN : [nan -__]