iosobjective-cobjective-c-category

setString on nil object with categories


It looks to me like sending setString: to a NSMutableString that hasn't had init called on it yet does not call init on it's own. For example:

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

I'd like to overwrite this behavior, so that essentially

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

I could do so with a subclass, but I would have to go through my project and replace all my NSMutableStrings with my subclass, which is a pain. I was looking at the Apple Docs and it looks like what I want to do is create a Category for NSMutableString. I haven't used categories before, so I got a couple questions:

First, it looks like categories only allow me to add new methods, it doesn't allow me to overwrite existing methods. I suppose it is easy enough to just create a setStringWithInit: method that does what I want, so this first issue isn't really an issue after all (although I still have to do a find-replace through my project for setString, but oh well).

Second, and more importantly, how do I check if the sender of my new method is nil? If setString: returned something other than void, I think I could get it to work, but that's not the case here. How do I get the if (!self) check from my code above to work with a category?

Or are categories not the way to go for this kind of thing, and I'd just be better off sub-classing after all?

EDIT: So the strings I'm using this on will actually be @propertys of a custom NSObject subclass. In my code, I'll actually be calling [myObject.someProperty setString:@"foo"];, and the debugger is showing me that someProperty is nil when I try to do this. Also, in other parts of my app I'm checking if (!myObject.someProperty) to see if that property has been used yet, so I don't want to just automatically self.someProperty = [[NSMutableString alloc] init]; in the init method of myObject's class.

Although now that I think about it, I think I can get away with replacing if (!myObject.someProperty) with if ([myObject.someProperty length] == 0), which would allow me to go through and alloc-init things right away. But if I'm initializing everything right away, that will create some memory space for it, correct? It's probably negligible though. Hm, perhaps this is what I should be doing instead.


Solution

  • macros FTW!

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

    When I try to assign a value with this:

    Drawbacks: