Question

In Objective-C, is there any way to run a specific selector automatically every time an object is instantiated? (I know about +initialize but I need an instance method).

Specifically, I am writing a custom string class (that inherits from my own root class with a similar interface to NSObject) and I am trying to make it 'play nicely' with Objective-C constant strings. To do this, I have the following class definition (as required by the runtime):

// 1) Required Layout
@interface MYConstantString : MYObject {
    //Class isa; inherited from MYObject
    char *c_string;
    unsigned int length;
}

Now, I want to implement my string class by using a pointer to a C-struct inside the class (this "C object" is already well implemented so I basically just want to wrap it in an Objective-C class). Ideally therefore, my Objective-C class would look like this:

// 2) Desired Laout
@interface MYConstantString : MYObject {
    // Class isa;
    StringObject *string;
}

And then the class and instance methods would just wrap C function calls using that StringObject.

So because I can't have the desired ivar layout (2), I wish to hack around the required ivar layout (1) to work for me. For example:

- (void)fixup {
    // Pseudocode
    temp = copystring(c_string);
    c_string = (void *)StringObjectNewWithString(temp); // Fudge pointer
    length = ... // I can do something else with this.
}

So, to return to the question, is there a way to call -fixup automatically, rather than having to do the following every time I make write an Objective-C constant string?

MYConstantString *str = @"Constant string";
[str fixup];

I know this is an obscene hack, and Objective-C constant string interoperability isn't totally crucial for what I need, but it would be nice to be able to use the @"" syntax and make the code more 'naturally' Objective-C.

Was it helpful?

Solution

I'm guessing you left out an important fact: you're using -fconstant-string-class=MYConstantString when building to have the compiler use your class for constant string objects (@"...").

Given that, then, no. There are two significant problems. First, "instance creation" for constant strings happens at compile time, not run time. The reason that there's a required layout is that the compiler does nothing but lay out the string's data in a data section with a reference to the appropriate class object where the isa pointer goes. It doesn't invoke any custom code. It is not necessarily even aware of such custom code at compile time. A given translation unit may not include the constant string class. The reference to that is resolved at link time.

Second, the constant string instance is almost certainly laid out in a read-only data section. There's a good chance that even calling your -fixup method manually as in your question would encounter an access violation because you'd be modifying read-only memory.

You should consider using a class cluster. Make MYConstantString one concrete subclass of an abstract base class. Make it conform to the required layout and just use the character pointer and length ivars as they are. If it would be convenient to translate to StringObject at various points, do that at those points. Implement other, separate concrete subclasses to use StringObject internally, if desired.

OTHER TIPS

MYConstantString *str = @"Constant string";

That can't work because @"..." is an NSString, and it's not only a problem of layout but of instance sizes. If you want 0-copy or anything like that, what you have to do is have something like:

MYConstantString *str = [MyConstantString stringWithNSString:@"Constant string"];

and let -stringWithNSString: recognize when the passed string is a constant one (I'm pretty sure the concrete class of constant strings is easy to recognize, and probably hasn't changed ever for backward compatibility reasons) and then hack it around to grab the pointer to the bytes and similar things.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top