为什么我必须保留/复制此NSString?

时间:2011-11-16 19:33:23

标签: ios memory-management nsstring copy retain

我最近在我的一个类中重写了一些代码,这给了我一个NSString错误。这就是我现在所拥有的:

我的班级标题:

@interface MyViewController : UITableViewController {
   NSString *myString;
}

@property (nonatomic, retain) NSString *myString; // Or copy instead of retain.

@end

并实施了一些方法:

- (void)viewDidLoad {
    myString = @"This is";

    if (something) {
        myString = [NSString stringWithFormat:@"%@ a string.", myString]; // *1
    }

    [myString retain]; // <-- Why do I have to retain/copy here?
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.row == 0) {
        /* Some code for creating a UITextView called myTextView */
        // ..and then setting the text property:
        myTextView.text = myString; // <-- Crashes here if I don't retain/copy in viewDidLoad.
    }
}

经过一些调试后我发现我必须保留/复制NSString。

如果我想稍后使用它,为什么我必须在viewDidLoad中保留/复制NSString?

另外,我注意到如果我删除标记为* 1的行,我不必保留/复制。

3 个答案:

答案 0 :(得分:1)

如果您使用合成的setter方法分配变量,它将自动为您保留NSString

if (something) {
    self.myString = [NSString stringWithFormat:@"%@ a string.", myString]; // *1
}

答案 1 :(得分:1)

您更好地理解这一点的一种方法是在私有属性前加上下划线_myString并将您的属性保存为myString - 这样可以很容易地计算出正在使用的属性或属性。

由于你似乎只是在课堂上使用这个值,我会质疑为什么你有一个属性,因为我认为这是混乱的根源。

如果您已经设置了前缀,那么您将始终知道_myString在分配时需要保留,myString将自动保留。

* 1处的行正在用新字符串替换myString的值,由于某种原因,在处理第二个方法中的代码之前,这个值是自动释放的。我不记得确切的原因,但我认为第一次分配不会发生这种情况,因为你创建了一个带有@“This is”的字符串文字,它不是自动释放的。

我希望这会有所帮助。

答案 2 :(得分:0)

您可以使用将自动释放/保留的保留属性访问者

- (void)viewDidLoad {
    self.myString = @"This is";
    if (something) {
        self.myString = [NSString stringWithFormat:@"%@ a string.", myString]; // *1
    }
    // no need to retain
}

当你删除标记为* 1的行时它没有崩溃的原因是因为myString仍然指向@"This is",这是一个litteral,它在程序的整个持续时间内存在于内存的一角。永远不会被破坏,因此内存位置仍然有效。