我想知道以下两行之间的区别
name1 = [[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement,1)] retain];
name1 = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement,1)];
如果我最后使用retain,
会对name1产生什么影响我遇到问题,并且无法在NSTimer调用的方法中使用name1,当我使用retain时,它们对我来说很好。
如果我在viewDidLoad中调用数据库中的值,并在每秒后使用NSTimer调用的方法,那么它将给出bad-exec,但是当我使用retain时它会正常工作,
我想知道原因
答案 0 :(得分:4)
这是差异
- (void)func1 {
name1 = [[NSString stringWithUTF8String:...] retain];
name2 = [NSString stringWithUTF8String:...];
}
- (void)func2 {
NSLog(@"%@", name1); //OK, name1 is still there
NSLog(@"%@", name2); //Would be crashed because name2 could be released anytime after func1 is finished.
}
答案 1 :(得分:2)
我在另一个问题上写了这个答案,但它解释了你在问什么:
目标c中的对象具有保留计数。如果当对象超出范围时(当您停止使用它时)此保留计数大于0,则它会泄漏。
以下事项会增加保留计数
[[alloc] init]
new
copy
[retain]
adding an object to an array
adding an object as a child (e.g. views)
There are likely more, but you don't appear to use any others in your code
以下减少保留计数
[release]
removing an object from an array
if you dealloc an array, all of its objects are released
您应该检查代码并确保数组的每个保留或添加都与相应的版本匹配。 (您可以在dealloc方法中释放成员变量。)
另一位用户提出了一个有效的观点,即我的答案不是
将对象添加到数组后,它将获得所有权,并在完成对象时释放该对象。您需要做的就是确保根据内存管理规则发布您拥有的任何内容
还有自动释放对象,看看这个例子;
-(init){
...
stagePickerArray = [[NSMutableArray alloc] init];
for (int i = 0; i < 3; i++)
{
//this string is autoreleased, you don't have call release on it.
//methods with the format [CLASS CLASSwithsomething] tend to be autorelease
NSString *s = [NSString stringWithFormat:@"%d", i);
[stagePickerArray addObject:s];
}
...
}
您的问题是,当您稍后使用字符串时,它的保留计数为零并且已被释放。通过在上面调用retain,你会说“我想稍后再使用它”。不要忘记将每个保留与释放匹配,否则你的对象将“泄漏”
答案 2 :(得分:1)
我敢打赌,如果您的name1
是属性,则代码不会崩溃 - (nonatomic, retain)
或(copy)
,具体取决于您的需求。
第二个条件是在你的其他函数尝试使用它时将name1
初始化为有意义的。
修改强>
对于属性,在这种情况下,您必须使用合成的setter:self.name1 = @"your string";
通常,您不必手动保留/释放使用stringWith...
方法创建的字符串,因为您使用显式alloc
在内存中没有创建任何内容。另请注意,代码:
NSString *str = [NSString stringWithUTF8String:@"your string"];
当函数超出范围时,str
(如果不用于设置属性)将停止可用(iOS eventloop将自动释放它)。