3
votes

I am trying to change the class of objects created with a nib with the iPhone SDK.

The reason for this is; i dont know until runtime what the class is that i want the nib object to be (though they will have the same UIView based super class), and i dont want to create a different nib for every eventuality - as the .nib will be the same for each, apart from the class of one object.

I have been successful, with a couple of methods, but either have some knock on effects or am unsure of how safe the methods I have used are:

Method 1: Override alloc, on the super class and set a c variable to the class I require:

+ (id) alloc {
 if (theClassIWant) {
  id object = [theClassIWant allocWithZone:NSDefaultMallocZone()]; 
  theClassIWant = nil;
  return object;
 }
 return [BaseClass allocWithZone:NSDefaultMallocZone()];
}

this works well, and i assume is 'reasonably' safe, though if have a nib with the correct class as the class identity in the Nib, or I alloc a subclass myself (without setting 'theClassIWant') - an object of the base class is created. I also dont really like the idea of overriding alloc...

Method 2: use object_setClass(self,theClassIWant) in initWithCoder (before calling initWithCoder on the super class):

- (id) initWithCoder:(NSCoder *)aDecoder {
 if (theClassIWant) {

  // the framework doesn't like this:
  //[self release];  
  //self = [theClassIWant alloc];

  // whoa now! 
  object_setClass(self,theClassIWant);

  theClassIWant = nil;
  return [self initWithCoder:aDecoder];
 }

 if (self = [super initWithCoder:aDecoder]) {
           ...
  • this also works well, but not all the subclasses are necessarily going to be the same size as the super class, so this could be very unsafe! To combat this i tried releasing and re-allocing to the correct type within initWithCoder, but i got the following error from the framework:

    "This coder requires that replaced objects be returned from initWithCoder:"

dont quite get what this means! i am replacing an object in initWithCoder...

Any comments on the validity of these methods, or suggestions of improvements or alternatives welcome!

1
actually i have improved method 1, by using 'self' as the class if 'theClassIWant' is not set. I dint realise self could be used in a class method. i.e. return [self allocWithZone:NSDefaultMallocZone()]; - Nick Hingston
+1 for fearless abuse of the language. - cduhn

1 Answers

0
votes

While I'm curious to see if you can pull this off using your approach, you may want to consider using custom placeholder objects.