今天早上我在我正在处理的iPhone应用程序中遇到了崩溃,当我修复了这个bug时,我很好奇语法原因这是一个问题。
这是我的代码简化为简单元素。我使用NSArray为项目填充TableView中的项目。 NSArray是一个财产:
@interface FooViewController : UITableViewController {
NSArray *stuff;
}
@property (nonatomic, retain) NSArray *stuff;
在我的实施文件中:
@synthesize stuff;
- (void)viewDidLoad {
NSArray *arr = [[NSArray alloc] initWithObjects:@"", @"Item 1", @"Item 2",
@"Lorem", @"Ipsum", nil];
self.stuff = arr;
[arr release];
}
现在,当我第一次写这个方法的时候,我不小心把它留下了“自我”。这导致了炸弹。虽然在测试时,它一见钟情。我试过了:
stuff = arr;
NSLog(@"%d", [stuff count]);
但在其他轰炸方法中使用 stuff 。现在我已经解决了问题,我可以在其他地方使用[stuff count]。
那么为什么我可以在某些地方使用东西但在其他地方我必须使用 self.stuff ?
答案 0 :(得分:5)
当您使用(self)和dot语法时,根据您定义属性的方式(非原子,保留),保留NSArray(stuff)。
如果不这样做,你仍然在进行赋值,但是你不会通过alloc + init保留数组,而不是保留数组,而是立即释放它。
您可以通过“self.stuff = arr”进行分配:
stuff = [arr retain];
但是既然你定义了一个属性,你显然想要使用点语法并为你调用retain。
答案 1 :(得分:4)
这也可以正常运作:
- (void)viewDidLoad {
stuff = [[NSArray alloc] initWithObjects:@"", @"Item 1", @"Item 2",
@"Lorem", @"Ipsum", nil];
}
因为数组是由alloc保留的。但是如果你有一个属性并且使用自动释放数组创建方法,那么通常更好地坚持使用点符号,在这里你可以从属性中“免费”保留:
- (void)viewDidLoad {
NSArray *arr = [NSArray arrayWithObjects:@"", @"Item 1", @"Item 2",
@"Lorem", @"Ipsum", nil];
self.stuff = arr;
}
您可能只是将其保留为简单,但您还需要在dealloc中释放此数组:
- (void)dealloc {
[stuff release]; stuff = nil;
}
答案 2 :(得分:3)
stuff = ...
直接引用属性的支持字段。它不会增加保留计数。因此,将对象释放到其他位置可能会将其保留计数降低到零,并在您仍然保持对它的引用时将其取消分配。此外,它可能会导致属性的先前值的内存泄漏
它看起来有时工作的原因是该对象可能尚未由其他人解除分配。
另一方面,self.stuff = ...
会向属性的set访问者发送一条消息,该消息将负责保留计数。
答案 3 :(得分:3)
做之间的区别:
stuff=arr;
和
self.stuff=arr;
在第二种情况下,你实际上调用了自动合成的setStuff:accessor方法,它保留了数组。在您发布的代码中,使用alloc / initWithObjects创建数组,因此它的保留计数为1。
你只需要在viewDidLoad:方法中更改删除对[arr release]的调用,一切都会好的:
- (void)viewDidLoad {
NSArray *arr = [[NSArray alloc] initWithObjects:@"", @"Item 1", @"Item 2",
@"Lorem", @"Ipsum", nil];
stuff = arr;
}
正如您所注意到的,您还可以使用self.stuff“修复”此问题。我建议不要这样做,因为它模糊了代码的含义,并添加了大多数情况下不需要的额外工作。一般来说,我建议不要使用“自我”。实例方法中的语法。