带有类别的nil对象上的setString

时间:2013-12-12 18:31:42

标签: ios objective-c objective-c-category

我认为将setString:发送给尚未NSMutableString呼叫的init但尚未自行调用init。例如:

NSMutableString *string;   // Declare, but do not init yet
[string setString:@"foo"];
NSLog (@"%@",string);      // Prints "(null)"

我想覆盖这种行为,所以基本上是

- (void) setString:(NSString *)aString
{
    if (!self)
    {
        self = [self initWithString:aString];
    }
    else
    {
        [super setString:aString];
    }
}

我可以使用子类来完成,但是我必须完成我的项目并将所有NSMutableString替换为我的子类,这很痛苦。我正在查看Apple Docs,我想要做的就是为NSMutableString创建一个类别。我之前没有使用类别,所以我有几个问题:

首先,看起来类别只允许我添加新方法,它不允许我覆盖现有方法。我想简单地创建一个可以满足我想要的setStringWithInit:方法就足够了,所以这第一个问题毕竟不是一个问题(尽管我仍然需要通过我的项目进行查找替换{ {1}},但是哦,好吧)。

其次,更重要的是,如何检查新方法的发件人是否为setString?如果nil返回setString:之外的其他内容,我想我可以让它工作,但事实并非如此。如何从上面的代码中获取void检查以使用类别?

或者类别不适合这种事情,毕竟我会更好地进行分类?

编辑: 所以我使用它的字符串实际上是自定义if (!self)子类的@property。在我的代码中,我实际上将调用NSObject,并且当我尝试执行此操作时调试器向我显示[myObject.someProperty setString:@"foo"];为nil。此外,在我的应用的其他部分,我正在检查someProperty以查看该属性是否已被使用,因此我不想仅在if (!myObject.someProperty)方法中自动self.someProperty = [[NSMutableString alloc] init]; init的课程。

虽然我现在考虑过这个问题,但我认为我可以将myObject替换为if (!myObject.someProperty),这样我就可以立即执行并分配init事件。但是,如果我马上初始化一切,那将为它创造一些内存空间,对吗?但它可能是微不足道的。嗯,也许这就是我应该做的事情。

5 个答案:

答案 0 :(得分:3)

正确的代码只是:

NSMutableString *string = [NSMutableString string];
[string setString:@"foo"];
NSLog (@"%@",string);

为什么不初始化变量?无需覆盖setString:或任何其他方法。不要试图以与任何其他类别不同的​​方式对待NSMutableString

此外,覆盖setString:仍然无法解决任何问题。只要指针为nil,就无法在其上调用方法。

答案 1 :(得分:1)

您可以使用方法调配重新实现没有子类化的方法。这是a tutorial。不过有两个理由不这样做。

  1. 这将违背良好的Objective-C做法,因为你的 setter也将是一个init方法。不好。
  2. 正如@ rmaddy 正确指出的那样,在nil对象上调用setString:会做 没有。即使你覆盖了这个方法。
  3. 因此,我建议在NSMutableString上创建一个类别,并在那里实施[NSMutableString initWithString:]。这是一个更清洁的解决方案。

答案 2 :(得分:1)

你正在走向疯狂的道路。所有进入这里的人都放弃了希望!

不要尝试更改语言语义,以便以某种方式向nil对象发送消息,从而神奇地创建对象的实例。这不是语言的运作方式。

您尝试做的事情可能是不可能的,如果您能够成功,您将创建与标准Objective-C根本不兼容的程序。您也可以找到一种新语言Objective-D

将消息发送到Objective C中的nil对象是合法的。结果是消息被静默删除,没有任何反应。在许多其他面向对象的其他语言中,向nil对象/零指针发送消息会导致崩溃。

Objective C对象创建的语义是:

首先使用类方法alloc:

为对象分配内存
NSMutableString* aString = [NSMutableString alloc];

然后向新创建的对象发送一个init方法,将其设置为初始状态:

aString = [aString init];

这两个步骤几乎总是合并为一行:

NSMutableString* aString = [[NSMutableString alloc] init];

类有时包括为您执行2步alloc / init的快捷方便“方便”方法,并在一次调用中返回一个对象,例如:

NSMutableString *aString = [NSMutableString stringWithCapacity: 50];

不要试图打击这个惯例。学会遵循它。如果您无法容忍此约定,请使用其他语言编程。真。

答案 3 :(得分:0)

你真的不能那样做 - 你有一个只能在这个对象的实例上调用的方法,所以你必须先创建它才能使用它。

在你的代码中,无论如何它都将是“无” - 它不会自己创建。

你为什么这样做而不仅仅是:

NSMutableString *string = @foo";

我无法想象避免分配对象的理由

答案 4 :(得分:0)

宏FTW!

#define setString(X,Y) if(!X){X=[[NSMutableString alloc] initWithString:Y];}else{[X setString:Y];}

当我尝试使用此值分配值时:

  • 它将始终首先初始化
  • 在我尝试给它一个值之前,它不会被初始化
  • 它不会使我的代码混乱
  • 如果X不是NSMutableString,或者如果Y不是NSStringNSMutableString
  • ,它仍然会发出警告
  • 我没有测试过Ynil,但我预计会导致崩溃,这就是我想要的。

缺点:

  • 我仍然要记得始终使用我的setString()代替库存setString:
  • 我必须为我打电话的任何其他安装人员做一些类似的事情(我唯一担心的是setValue:forKey:,这是我广泛使用的 - 我猜是一次一步 - 一个尺寸适合所有解决方案本来不错 - 也许是另一个问题的主题。
  • 无论我传入的是什么,在传递之前都必须是NSString,我无法将其转换为符合字符串的字符串 - 但至少如果我尝试这样做,我会收到构建错误,所以我不记得这样做(尽管仍然会增加混乱)

    NSMutableString *X;

    int y = 0;

    setString(X, [NSString stringWithFormat:@"%d",y]) // <--- Doesn't work

    NSString *Y = [NSStirng stringWithFormat:@"%d",y];

    setString(X,Y) // <--- Does work