iOS 10 个 NSNumber 枚举崩溃
iOS 10 NSNumber crash with enumerations
我有一个非常奇怪的问题,与 NSNumber
对象有关,我的枚举值和在设备 运行 iOS os 版本 10 上访问它们。
Just as a disclaimer - this issue does not happen in other iOS os versions.
我已经像这样声明了一个枚举:
typedef NS_ENUM(NSInteger, MYENUM) {
FIRST = 1500,
SECOND = 1700,
THIRD = 1900,
...
};
使用此枚举时,我以这种方式传递它:
[[MyObject alloc] initObjectWith:@(FIRST)];
排除内部逻辑,我在字典中使用枚举,因此需要将其转换为 NSNumber。
这样做时,应用程序崩溃了,因为枚举在某种程度上不是 NSNumber,而是 NSIndexPath。
为什么会这样?
当我删除盒装文字并更改方法签名以接受 NSInteger 时,此崩溃消失。
我曾尝试在网上搜索此类问题,但没有找到。
进一步说明(根据评论)
myObject 的 init 方法内部没有发生特殊逻辑,只是将定义为 NSNumber
的 属性 分配给传递的参数。
关于崩溃日志,Xcode 因提供不太有用的崩溃日志而臭名昭著,我所看到的只是 EXC_BAD_ACCESS
,这可能意味着访问已发布的对象或潜在的内存泄漏。
MyObjectclass定义如下:
头文件:
@interface ISNEvent : NSObject
@property(nonatomic, assign) NSNumber* number;
-(instancetype)initObjectWith:(NSNumber*)number;
@end
.m 文件:
- (instancetype)initObjectWith:(NSNumber*)number {
self = [super init];
if (self) {
_number = number;
}
return self;
}
您已使用 assign
内存语义定义了 属性:
@property(nonatomic, assign) NSNumber* number;
这意味着您将获得对您提供的任何内容的引用,但您不会保留强引用,并且在对象被释放时您不会 nil
您的引用。这是两全其美的情况,因为您保留了对允许释放的对象的悬空引用。正如您所说,这个特定错误“可能......意味着访问一个已被释放的对象”,而这正是这里发生的事情。
你可以考虑暂时开启僵尸(command+<) 或者“产品”»“方案”»“编辑方案”。 ..”然后转到“运行”设置的“诊断”部分,看看您的行为是否发生变化。您可能不会再看到 NSIndexPath
(或其他)引用,而是确认 NSNumber
实例已被释放。
无论如何,您无疑是想将此 NSNumber
属性 设为 strong
参考:
@property(nonatomic, strong) NSNumber *number;
另一个解决方案是使它成为 weak
,允许它被释放,但安全地将您的引用设置为 nil
。这比 assign
更安全,但我也怀疑这是你的意图。第三种选择是 copy
,这是我们有时使用的可变类型,在这里不适用。
归根结底,如今,我建议不要对任何对象类型使用 assign
内存语义。使用 strong
、copy
或 weak
。在这种情况下,strong
就是您想要的。仅将 assign
用于原始数据类型(例如 NSInteger
、CGFloat
等),而不是对象类型。
而且,请记住,当您完成对僵尸的测试后,请关闭该诊断功能。
我有一个非常奇怪的问题,与 NSNumber
对象有关,我的枚举值和在设备 运行 iOS os 版本 10 上访问它们。
Just as a disclaimer - this issue does not happen in other iOS os versions.
我已经像这样声明了一个枚举:
typedef NS_ENUM(NSInteger, MYENUM) {
FIRST = 1500,
SECOND = 1700,
THIRD = 1900,
...
};
使用此枚举时,我以这种方式传递它:
[[MyObject alloc] initObjectWith:@(FIRST)];
排除内部逻辑,我在字典中使用枚举,因此需要将其转换为 NSNumber。
这样做时,应用程序崩溃了,因为枚举在某种程度上不是 NSNumber,而是 NSIndexPath。
为什么会这样?
当我删除盒装文字并更改方法签名以接受 NSInteger 时,此崩溃消失。
我曾尝试在网上搜索此类问题,但没有找到。
进一步说明(根据评论)
myObject 的 init 方法内部没有发生特殊逻辑,只是将定义为 NSNumber
的 属性 分配给传递的参数。
关于崩溃日志,Xcode 因提供不太有用的崩溃日志而臭名昭著,我所看到的只是 EXC_BAD_ACCESS
,这可能意味着访问已发布的对象或潜在的内存泄漏。
MyObjectclass定义如下:
头文件:
@interface ISNEvent : NSObject
@property(nonatomic, assign) NSNumber* number;
-(instancetype)initObjectWith:(NSNumber*)number;
@end
.m 文件:
- (instancetype)initObjectWith:(NSNumber*)number {
self = [super init];
if (self) {
_number = number;
}
return self;
}
您已使用 assign
内存语义定义了 属性:
@property(nonatomic, assign) NSNumber* number;
这意味着您将获得对您提供的任何内容的引用,但您不会保留强引用,并且在对象被释放时您不会 nil
您的引用。这是两全其美的情况,因为您保留了对允许释放的对象的悬空引用。正如您所说,这个特定错误“可能......意味着访问一个已被释放的对象”,而这正是这里发生的事情。
你可以考虑暂时开启僵尸(command+<) 或者“产品”»“方案”»“编辑方案”。 ..”然后转到“运行”设置的“诊断”部分,看看您的行为是否发生变化。您可能不会再看到 NSIndexPath
(或其他)引用,而是确认 NSNumber
实例已被释放。
无论如何,您无疑是想将此 NSNumber
属性 设为 strong
参考:
@property(nonatomic, strong) NSNumber *number;
另一个解决方案是使它成为 weak
,允许它被释放,但安全地将您的引用设置为 nil
。这比 assign
更安全,但我也怀疑这是你的意图。第三种选择是 copy
,这是我们有时使用的可变类型,在这里不适用。
归根结底,如今,我建议不要对任何对象类型使用 assign
内存语义。使用 strong
、copy
或 weak
。在这种情况下,strong
就是您想要的。仅将 assign
用于原始数据类型(例如 NSInteger
、CGFloat
等),而不是对象类型。
而且,请记住,当您完成对僵尸的测试后,请关闭该诊断功能。