Is it possible to initialize a property in a category before any category method is called?

StackOverflow https://stackoverflow.com/questions/21898667

  •  14-10-2022
  •  | 
  •  

Pregunta

Is it possible to initialize a property in a category?

For example, if I have a mutable array property called nameList in a class. Is it possible to have a category created for this class to add an object to the array property before any of the category method is called?

¿Fue útil?

Solución

If I understand you correctly, and others are interpreting your question differently, what you have is:

  • A class with a property
  • A category on that class

And you want to call a particular method automatically before any category method is called on a given instance, that method would "initialise" the category methods by modifying the property.

In other words you want the equivalent of a subclass with its init method, but using a category.

If my understanding is correct then the answer is no, there is no such thing as a category initializer. So redesign your model not to require it, which may be to just use a subclass - as that provides the behaviour you are after.

The long answer is you could have all the category methods perform a check, say by examining the property you intend to change to see if you have. If examining the property won't determine if an object has been "category initialized" then you might use an associated object (look in Apple's runtime documentation), or some other method, to record that fact.

HTH

Addendum: An even longer/more complex solution...

GCC & Clang both support a function (not method) attribute constructor which marks a function to be called at load time, the function takes no parameters and returns nothing. So for example, assume you have a class Something and a category More, then in the category implementation file, typically called Something+More.m, you can write:

__attribute__((constructor)) static void initializeSomethingMore(void)
{
   // do stuff
}

(The static stops the symbol initializeSomethingMore being globally visible, you neither want to pollute the global name space or have accidental calls to this function - so you hide it.)

This function will be called automatically, much like a the standard class + (void) initialize method. What you can then do using the Objective-C runtime functions is replace the designated initializer instance methods of the class Something with your own implementations. These should first call the original implementation and then an initialize your category before returning the object. In outline you define a method like:

- (id) categoryVersionOfInit
{
    self = [self categoryVersionOfInit]; // NOT a mistake, see text!
    if (self)
    {
       // init category
    }
    return self;
}

and then in initializeSomethingMore switch the implementations of init and categoryVersionOfInit - so any call of init on an instance of Something actually calls categoryVersionOfInit. Now you see the reason for the apparently self-recursive call in categoryVersionOfInit - by the time it is called the implementations have been switched so the call invokes the original implementation of init... (If you're crosseyed at this point just draw a picture!)

Using this technique you can "inject" category initialization code into a class. Note that the exact point at which your initializeSomethingMore function is called is not defined, so for example you cannot assume it will be called before or after any methods your target class uses for initialization (+ initialize, + load or its own constructor functions).

Otros consejos

Sure, it possible through objc/runtime and objc_getAssociatedObject/objc_setAssociatedObject
check this answer

No it's not possible in objective c.Category is the way to add only method to an existing class you can not add properties in to this. Read this

Why can't I @synthesize accessors in a category?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top