NSNumber 导致应用程序崩溃

Owe*_*hao 2 objective-c nsnumber

我在 .h 文件中有一个 @property opacity

@property (assign) NSNumber *opacity;
Run Code Online (Sandbox Code Playgroud)

然后在 .m 文件中我

@synthesize opacity;
Run Code Online (Sandbox Code Playgroud)

然后在

- (id)initWithFrame:(NSRect)frame
Run Code Online (Sandbox Code Playgroud)

我做了

 opacity = [NSNumber numberWithFloat:1.0];
Run Code Online (Sandbox Code Playgroud)

当我运行应用程序时,Xcode 显示此错误

Thread 1: EXC_BAD_ACCESS (code-EXC_I386_GPFLT)
Run Code Online (Sandbox Code Playgroud)

但是,如果我将该行更改为

opacity = [NSNumber numberWithInteger:1];
Run Code Online (Sandbox Code Playgroud)

一切正常。

Mat*_*uch 5

看起来它工作正常。但是您刚刚使用 NSNumber 的实现细节覆盖了该错误。

正如沃尔克指出的那样,您有内存管理问题。您的财产应使用strong. 如:

@property (strong) NSNumber *opacity;
Run Code Online (Sandbox Code Playgroud)

并且您应该在分配值时使用该属性。例如:

self.opacity = [NSNumber numberWithFloat:1.0];
Run Code Online (Sandbox Code Playgroud)

那么为什么它与[NSNumber numberWithInteger:1]? 因为 iOS 试图变得聪明。整数 1 NSNumber 是一个永远不会被释放的单例对象。[NSNumber numberWithFloat:1.0]不是这样一个坚不可摧的对象,一旦它的引用计数下降到零,它就会被释放。这发生在您离开创建 NSNumber 实例的范围之后,因为它永远不会保留在您的代码中。

你可以用这个小日志代码看到单例行为,它记录了 NSNumber 实例的指针地址:

NSLog(@"Address of `[NSNumber numberWithFloat:1.0]`: %p", [NSNumber numberWithFloat:1.0]);
NSLog(@"Address of `[NSNumber numberWithInteger:1]`: %p", [NSNumber numberWithInteger:1]);

NSLog(@"Address of `[NSNumber numberWithFloat:1.0]`: %p", [NSNumber numberWithFloat:1.0]);
NSLog(@"Address of `[NSNumber numberWithInteger:1]`: %p", [NSNumber numberWithInteger:1]);
Run Code Online (Sandbox Code Playgroud)

这产生

Address of `[NSNumber numberWithFloat:1.0]`: 0x10c622d10
Address of `[NSNumber numberWithInteger:1]`: 0xb000000000000013
Address of `[NSNumber numberWithFloat:1.0]`: 0x10c129fb0
Address of `[NSNumber numberWithInteger:1]`: 0xb000000000000013
Run Code Online (Sandbox Code Playgroud)

如您所见,来自的两个地址numberWithFloat:1.0不同,来自的两个地址numberWithInteger:1相同。因为[NSNumber numberWithInteger:1]总是返回相同的对象。