开发者

Objective C - Reflection and overriding methods?

开发者 https://www.devze.com 2023-03-18 14:51 出处:网络
I am trying to use reflection to override the getter method for my properties and create lazy initialization. how can I do that?

I am trying to use reflection to override the getter method for my properties and create lazy initialization. how can I do that?

// This should be a public method maybe a category to NSObject
- (void)overrideGetterMethod
{
   //somehow convert my original getter with lazyInitialize method
}

- (id)lazyInitialize
{
   if (!self)
   {
      self = [[self class] alloc] init];
   }
   return self;
}

Above is the implementation of the functionality, and below is the use of it

@property (nonatomic, retain) SomeObject *someObject;

- (void)viewDidLoad
{
   [super viewDidLoad];
   [someObject overrideGetterMethod];

   // So when I call the following method if the object is nil it get's instantiated automat开发者_如何学JAVAically
   [self.someObject doSomething]
}


You seem to be adopting an odd pattern, and I can't help thinking that you want to achieve is probably better done by some higher level route, such as simply:

if(result) return result;

/* stuff to fill result and then return it here */

Branch prediction should give that a negligible runtime cost.

That caveat being stated, the things you're interested in are method_setImplementation (to set the IMP for a Method), class_getMethodImplementation (to get an IMP from a class and selector) and and class_getInstanceMethod (to get a Method from a class and selector). Using those, you can set a given method to respond to whatever selector or selectors you want at runtime.

NSObject provides some convenience methods for getting the IMP and the Method, but they don't end up being any shorter.


Maybe this could be a start:

@interface NSObject (LazyKVC)
- (id)lazyValueForKey:(NSString *)key;
@end


@implementation NSObject (LazyKVC)

- (id)lazyValueForKey:(NSString *)key {
    id value = [self valueForKey:key];
    if (!value) {                                   
        // Now, look for the type of property named |key|.
        // To spare you the details of the @encode() string, use
        // [self typeOfPropertyNamed:key] - see link provided below

        NSString className = [NSString stringWithUTF8String:
                                 [self typeOfPropertyNamed:key]];

        Class propertyClass = NSClassFromString(className);

        if (propertyClass) {
            value = [[propertyClass alloc] init];
        }
    }
    return value;
}

@end    

Note:

  1. The code above uses - (const char *)typeOfPropertyNamed:(NSString *)name, available here.
  2. I omitted corner cases (dealing with errors, etc.).

Usage would be:

[foo lazyValueForKey:@"bar"];

I'm curious if you can make it work like that (I wrote this in the browser window directly...)

Note about (dependency) injection

In order for your method to be able to return the object you want at runtime (via injection) you would need - as a starting point - the following:

  1. a configuration file (to tell lazyValueForKey: where to initialize the injected object from, e.g. a plist)
  2. a convention: how will you name that configuration file so lazyValueForKey: will find it
  3. a method that will enable you to lookup and initialize an object from a configuration file (e.g. what fields and attributes will you include in your configuration file to describe objects).
  4. modify the lazyValueForKey: method to effectively de-serialize/read objects from the configuration file

Note that points 1-2-3 above could further lead you to abstract a dependency injection data source that would manage the configuration of your injected objects and provide you with them at runtime.

I am certainly missing other important points here, but I believe this is starting to get out of the scope of your original question, so I won't go any further with my answer. Implementing a dependency injection mechanism is no easy feat. However, you might find more info at this nice SO question.


If I understood you correctly you want something like this:

-(SomeObject*) someObject {
    if( !mSomeObject ) {
        //initialize it
        mSomeObject = [[SomeObject alloc] init];
    }

    return mSomeObject;
}

If you want to do that automatically, then you're probably need to check key-value coding programming guide or as an option you can use method swizzling.

0

精彩评论

暂无评论...
验证码 换一张
取 消