【问题标题】:Why am I NOT getting an Exception with this getter and setter for a NSMutableString Property为什么我没有得到一个 NSMutableString 属性的 getter 和 setter 异常
【发布时间】:2012-01-23 04:07:44
【问题描述】:

我只是提出了一个错误的答案(已删除)

代码是为了响应这个question。 OP想知道他们为什么得到一个 由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“尝试使用 setString 改变不可变对象:

(我的回答是我没有注意自己在做什么,很累而且还在学习。通常的借口。:-))

当他们试图设置可变字符串时:

 [firstName setString:@""];

该属性是一个 NSMutableString

 @property (copy,nonatomic) NSMutableString* firstName

我发布了一些对我有用的代码。但是误以为 getter 是 setter。 (我还是新手,很累:-))

现在令人困惑的是,一旦有人指出我错了。我重新查看了我的代码并意识到我做了什么。

但在我的项目中,我只合成了 setter 而没有声明。

@synthesize firstName =_firstName;

我已经像这样声明了吸气剂:

-(NSMutableString *)firstName{
    if (!_firstName) _firstName = [[NSMutableString alloc]init];

    return _firstName;
}

但是没有我声明一个二传手,一切都没有问题。您应该为可变对象和(副本)的属性做什么

如果在里面放一个setter:

-(void)setFirstName:(NSMutableString *)mutableString{

    _firstName =  mutableString ;

}

它仍然可以正常工作。 我用调用:

[self.firstName setString:@"some words"];

当我认为我第一次删除 getter 并离开 setter 时,我确实得到了一次异常。 但我不能重复错误!

我希望这很清楚..

有谁知道发生了什么。在这种情况下,我是否正确地执行了 setter 和 getter。

谢谢

【问题讨论】:

    标签: objective-c ios getter-setter nsmutablestring


    【解决方案1】:

    您编写的 setter 不正确,因为它不会对传入的字符串进行可变副本。

    但我认为你真正的问题是为什么你在这里看不到异常。原因是:您在此处发布的代码中实际上并没有使用 bad setter。

    这是您发布的代码:

    [self.firstName setString:@"some words"];

    这个和这个基本一样:

    NSMutableString *tmp = [self firstName]; // this is using your getter
    [tmp setString:@"some words"]; // this is calling a method on NSMutableString
    

    所以首先你使用你的getter,它正确地返回一个NSMutableString*。然后调用一个已在 Foundation 中定义的方法,称为 -[NSMutableString setString:]。这很好用,因为您实际上是将它发送到 NSMutableString。到目前为止,您已经避免了任何问题。

    遇到异常的地方是这样的:

    // assume myObj is an instance of whatever class has this 'firstName' property
    
    [myObj setFirstName:@"Some static and immutable string"]; 
    // OOPS! Now we've used the broken setter 
    // and firstName is now NOT a mutable string!
    
    [myObj.firstName setString:@"Some other string"]; 
    // ERROR. Now we've tried to send setString to an immutable string object. 
    

    希望对你有帮助。

    顺便说一句,听起来您正在使用 ARC。在这种情况下,正确的 setter 可以像这样简单:

    -(void)setFirstName:(NSMutableString *)someString{
    
        _firstName =  [someString mutableCopy] ;
    }
    

    【讨论】:

    • 我还在想它。谢谢你的澄清。我知道我应该使用 setFirstName: 而不是基础定义的 setString。但是当我尝试使用对它的调用时,我似乎无法做到 [myObj setFirstName:@"Some static and immutable string"];与名字。我知道我在这里很厚。但是我该怎么做呢??
    • 以前看起来您是在同一个类的另一个方法中进行测试。 (self.firstName setString:...)。你可以用[self setFirstName:...][self.firstName = @"some immutable string"] 用同样的方法做同样的事情。
    • 我都试过了。不高兴我收到关于 NSMutableString 的警告没有用 [self.firstName = @"some immutable string"] 声明 setFirstName,而对于 [self setFirstName:...] 我收到关于 NSString 被传递给 NSMutableString 的警告。我可以施放它,那个警告就消失了。但我觉得我还是做错了什么?
    • 是的,你做错了什么。我以为这就是重点?您希望由于您的错误设置器而发生异常,以便您了解这一切是如何工作的。编译器警告你你将做错事。你现在想做点别的吗?
    • 对不起。我意识到我做错了什么,但不明白为什么它看起来像是在工作。目标是了解如何正确使用 getter 和 setter。一路走来,了解为什么我误导自己认为我做对了,而实际上我做错了。我觉得我不仅迷惑了自己,也迷惑了其他所有人..:-(
    【解决方案2】:

    给定一个属性声明:

    @property (copy,nonatomic) NSMutableString* firstName;
    

    非 ARC 代码中,setter 应该这样实现:

    - (void) setFirstName: (NSMutableString *) newString
    {
        if ( _firstName != newString ) {
            [_firstName release];
            _firstName = [newString mutableCopy];
        }
    }
    

    或者像这样:

    - (void) setFirstName: (NSMutableString *) newString
    {
        [_firstName autorelease];
        _firstName = [newString mutableCopy];
    }
    

    一个简单的赋值是行不通的,因为如果不复制新值你会崩溃。一个简单的copy 也不行,因为 ivar 是一个可变字符串。

    【讨论】:

    • 谢谢。我想我理解那里的逻辑。检查对象是否为零,释放它。制作一个新的可变副本。但为什么我的工作呢?即 setString 也不例外。你需要在 iOS 5 中发布吗。再次感谢
    • 我刚刚收到了发布的红色警告。弧
    • @"some words" 这样的常量字符串不会自动释放,这就是你的设置器似乎工作的原因。 iOS 5 并没有取消对内存管理的需求。 ARC 明确禁止使用releasedealloc。但即使您使用 ARC,我也强烈建议您阅读 Apple 的有关引用计数内存管理的文档,因为恕我直言,即使是有经验的开发人员,有时 ARC 规则也可能会非常混乱。
    • 上面的一个澄清。请注意,您不需要在释放对象之前测试对象是否为 nil;只是释放它。 Objective C 允许你精确地向 nil 对象发送消息,这样你就不需要一直做这个测试。发送给 nil 对象的消息什么都不做。
    • (更多关于在Apple's 'The Objective C Programming Language'向 nil 发送消息
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-09-14
    • 1970-01-01
    • 2016-09-04
    • 1970-01-01
    • 2023-03-13
    • 1970-01-01
    • 2019-04-22
    相关资源
    最近更新 更多