Objective-c - NSMutableString setString 与 NSString

标签 objective-c nsstring release retain nsmutablestring

在 setter 中,按如下方式保留和释放 NSString 是更好的做法吗:

-(void) setName:(NSString *)newName
{
    if(newName != nil)
    {
         [newName retain]:
         [m_Name release];
         m_Name = newName; //Where m_Name is a NSString *
    }
    //I'm not sure for this code, I have difficulties understanding memory-management in ObjC
}

或者通过 NSMutableString 更改值:

-(void) setName:(NSString *)newName
{
    if(newName != nil)
        [m_Name setString:newName]; //Where m_Name is a NSMutableString *
}

如果其中任何一个或两个方法不正确,请告诉我。

最佳答案

一些想法:

  1. 最佳实践是根本不编写 setter,以利用自动合成的访问器方法。自己编写只是一个搞乱内存管理或引入错误的机会。在编写自定义 setter 之前,您应该迫切需要一个自定义 setter 。

  2. 实例变量名称的新兴约定是使用前面带有前导下划线的属性名称(例如,对于名为 name 的属性,ivar 为 _name)。如果您省略@synthesize语句,最新版本的Xcode中包含的编译器将自动为您执行此操作。

  3. 如果您没有说明您的属性(property)拥有哪些内存限定符,那么 setter 应该是什么的问题就没有意义。我假设您将属性定义为retain

  4. 将属性更改为 NSMutableString 会更改属性的行为,我不建议您这样做,除非您出于某种原因确实需要可变字符串。

  5. 如果有人将 name 属性设置为 nil,您的第一个示例将不会执行任何操作。但如果有人想将其设置为nil,您仍然应该 (a) 释放旧的name 值; (b) 将您的 ivar 设置为 nil。 (顺便说一句,我下面的代码利用了向 nil 对象发送消息不会执行任何操作的事实,因此我不需要检查它是否为 nil 或在这种情况下不是。)

所以,我假设您有一个定义如下的属性:

@property (nonatomic, retain) NSString *name;

以及一个被省略或看起来像的合成行:

@synthesize name = _name;

然后,我认为 setter 看起来像:

-(void) setName:(NSString *)name
{
    // if you want to program defensively, you might want the following assert statement:
    //
    // NSAssert(name == nil || [name isKindOfClass:[NSString class]], @"%s: name is not string", __FUNCTION__);

    if (name != _name)
    {
        [_name release];
        _name = name;
        [_name retain];
    }
}

顺便说一句,我假设您的 init 方法正确初始化了 _name 并且 dealloc 释放了它。

- (id)init
{
    self = [super init];
    if (self) {
        _name = nil;
    }
    return self;
}

- (void)dealloc
{
    [_name release];
    [super dealloc];
}

正如 bblum 指出的那样,谨慎的做法是对 NSString 属性使用 copy :

@property (nonatomic, copy) NSString *name;

然后,我认为 setter 看起来像:

-(void) setName:(NSString *)name
{
    // if you want to program defensively, you might want the following assert statement:
    //
    // NSAssert(name == nil || [name isKindOfClass:[NSString class]], @"%s: name is not string", __FUNCTION__);

    if (name != _name)
    {
        [_name release];
        _name = [name copy];
    }
}

但实际上,除非绝对需要,否则您根本不应该编写 setter。


最后,您的代码有一条关于发现内存管理令人困惑的评论。虽然您肯定需要理解它,但我最后提出两个建议:

  1. 考虑使用Automatic Reference Counting (弧)。虽然这并不能消除了解内存管理如何工作的需要(请参阅 Advanced Memory Management Programming Guide ),但它确实使编写正确处理内存管理的代码变得更容易。如果您编写手动引用计数 (MRC) 代码,则很容易犯简单的内存管理错误,否则 ARC 会为您解决这些错误。

  2. 特别是如果您要使用 MRC,请利用 Xcode 的静态分析器(“产品”菜单上的“分析”或按 shift+ 命令+B)。这可以帮助查找困扰 MRC 代码的许多常规内存管理问题。 Finding Memory Leaks 仪器用户指南部分还说明了如何在调试代码时查找泄漏,但静态分析器通常只需检查代码即可识别问题。

关于Objective-c - NSMutableString setString 与 NSString,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16837983/

相关文章:

ios - 发布使用旧版 SDK 构建的 iOS 应用程序

ios - 如何在 Windows 上使用 Objective C 进行编码?

iphone - Objective-C考试

objective-c - 如何在 iOS 中使用 UIButton 自定义删除 UITextField 中的文本?

cocoa - 将 NSString 转换为 AXUIElementPostKeyboardEvent 的 keyCode+修饰符

ios - 如何跳过传入 [NSString stringWithFormat :] 的数据

ios - FBAudience网络:objc_boxable属性仅适用于结构或联合

iphone - NSString 中不同类型的 UTF8 解码

c - 为什么有些 C 程序在调试时可以运行,但在发布时却不行?

maven-2 - maven 发布插件 - wagon 因 ssh 身份验证失败,但 snapshort 和发布部署工作 - 嗯?