Category-like extension for instance variables

Is there a way to somehow emulate category behavior for a class regarding to it’s instance variables, not methods ?

I have a ClassA, and I want to keep its name after extending it with new methods AND ivars from other cllass (ClassB).
Of course, I can inherit ClassA, but resulting class will have different name.

  • Mach-O Linker Error When Adding Unit Tests - XCode
  • How to create a centered UICollectionView like in Spotify's Player
  • How to save struct to NSUserDefaults in Swift 2.0
  • How to use MBProgressHUD with swift
  • NSFetchedResultsController with sections created by first letter of a string
  • Why is my map view callout translucent/transparent and how do I change it's color?
  • For methods addition, it’s not a problem – category would be a good solution.

    UPDATE: ClassA used as file owner for a XIB, and these fields to be extended are IBOutlets. So I need them at build phase.

    3 Solutions Collect From Internet About “Category-like extension for instance variables”

    Since the iPhone uses the modern Objective-C runtime, you can use associative references to add data to instances without having to declare instance variables. See the documentation for objc_setAssociatedObject etc.

    If you wrap the calls to the runtime in standard accessor methods, it will be very easy to use.

    I’ve investigated this question playing around associative references (thanks to Ole), with methods static variables, methods swizzling, and finally come to this simple solution (no runtime stuff). I simply use “categorized” class only to return a pointer to a derived class, which of course can contain additional ivars. Doing so I achieve one unexpected benefit: I can call super‘s class methods, which is impossible when extending through categories.

    Example of a class extension (tested):

    ClassA+ClassB.h

    @protocol _ClassB_Protocol
      @optional // to avoid warnings
    - (IBAction) onClick:(id)sender;
      @property (nonatomic, retain) IBOutlet UIButton *aButton;
    @end
    
    @interface ClassA (_ClassA_Category) <_ClassB_Protocol>
    @end
    
    @interface ClassB: ClassA <_ClassB_Protocol> {
        UIButton *aButton; // _ivar_ to add
    }
    @end
    

    ClassA+ClassB.m

    @implementation ClassA (_ClassA_Category)
    // this will be called first on [ClassA alloc] or [ClassA allocWithZone:(NSZone *)zone]
    +(id) alloc {
        if ([self isEqual: [ClassA class]]) {
            return [ClassB alloc];
        } else {
            return [super alloc];
        }
    }
    @end
    
    
    @implementation ClassB: ClassA
    
    @synthesize aButton;
    
    -(void) dealloc {
        [aButton release];
    
        [super dealloc]; // this is impossible for an ordinary category
    }
    
    - (void) onClick:(id)sender {
        // some code here
    }
    
    @end
    

    Now we have in the same time:

    • ClassB “extends” ClassA (category way);
    • ClassB inherits ClassA (ClassB can call ClassA methods);
    • ClassB can be accessed through ClassA name (category way)

    I put Martin’s example into a trivial app replacing ClassA with NSData, ClassB with XXData, and onClick with getIvar, and invoked it (Mac OS X 10.6.6, Xcode 4 Final) with:

    NSData * data = [NSData data];
    NSLog(@"%@", [data getIvar]);
    

    It fails with “-[NSConcreteData getIvar]: unrecognized selector sent to instance” ..

    It fails because “alloc” in the NSData category (which returns the pointer to the derived class) is not called by the above code. If, instead, “alloc” is called explicitly, as in:

    NSData * data = [[NSData alloc] init];
    NSLog(@"%@", [data getIvar]);
    

    then all is well.