Conditional redefinition of a system method through categories in Objective-C?

Is there a way to provide an implementation of a method (which has the same method name defined by the framework) only when the method is not yet defined in the system? For example, the [NSSomeClass someMethod:] method exists only in Mac OS X 10.6, and if my application runs in 10.5, I will provide this method definition in the category. But when the application runs in 10.6, I want the method supported by the OS to be executed.

Background: I am creating an application designed for 10.5 and 10.6. The problem is that I recently realized that the +[NSSortDescriptor sortDescriptorWithKey:ascending:] method only exists in 10.6, and my code is already inundated with this method call. I could provide a default implementation for it (since this time it is not too difficult to implement it myself), but I want the native to be called whenever my application runs on 10.6. In addition, if I encounter similar problems in the future (with more complicated methods to implement), I may not be able to get away with providing a single-layer replacement.

This question is vaguely similar to Overriding a method through the ObjC Category and calling the default implementation? , but the difference is that I want to provide implementations only when the system does not work, t already exists.

Thanks.

+7
objective-c cocoa macos
source share
4 answers

Yes it is possible. Since you are targeting 10.5+, I assume you are using the ObjC2 runtime, which makes it pretty simple.

The Objective-C Runtime Reference contains all the methods you need. In particular, you can use class_getClassMethod or class_getInstanceMethod to find out if this method already exists, and then class_addMethod to bind the implementation to this selector if the class does not already have it.

+4
source share

I would compile +[NSSortDescriptor sortDescriptorWithKey:ascending:] in a category in a separate package. Then, at the very beginning of your main, check if the NSSortDescriptor class has a sortDescriptorWithKey:ascending: method with respondsToSelector: If it is not implemented (that is, you work on <10.6), download the package using -[NSBundle loadAndReturnError:] .

Thus, you will run the 10.6 method provided by the OS and your implementation at 10.5.

+7
source share

Alternatively, you can simply find find and sub -[NSSortDescriptor initWithKey:ascending:] , and then add the appropriate release statement.

This is more cumbersome to implement, but much less fragile and error prone than changing the class itself. This is especially true if you have never done this before. You will probably spend more time accelerating on redefinition than just finding.

+1
source share

think of a trade-off between changing initWithKey: ascending: the method and adding a new method at runtime is just a subclass of NSSortDescriptor and replace all calls to NSSortDescriptor with NSMySortDescriptor;

 //NSMySortDescriptor.h @interface NSMySortDescriptor : NSSortDescriptor { } - (id)initWithKey:(NSString *)keyPath ascending:(BOOL)ascending @end //NSMySortDescriptor.m @implementation NSMySortDescriptor - (id)initWithKey:(NSString *)keyPath ascending:(BOOL)ascending{ // check if super ie has initWithKey:ascending: method if( [NSSortDescriptor instancesRespondToSelector:@selector(initWithKey:ascending:)] ) { [NSSortDescriptor initWithKey:ascending:]; } else{ // your custom realization for Mac OS X 10.5 //... } } @end 
0
source share

All Articles