If I use a core iOS class in my app, like NSURLCache; I would like to print a log message anytime [[NSURLCache sharedURLCache] removeAllCachedResponses]
gets called. How can I extend a class method like that without explicitly subclassing NSURLCache and replacing all references of that within a project with a custom class? Is there some way to do this with category?
You can do it using Method Swizzling. Here is a page with a nice overview of the technique from which I borrowed most of the code below:
@interface SwizzleNSURLCache : NSURLCache
+(void)load;
-(void)swzl_removeAllCachedResponses;
@end
+(void)load {
Class class = [SwizzleNSURLCache class];
SEL originalSelector = @selector(removeAllCachedResponses);
SEL swizzledSelector = @selector(swzl_removeAllCachedResponses);
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
BOOL didAddMethod = class_addMethod(class,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(class,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
-(void) swzl_removeAllCachedResponses {
// This is your replacement method. You can do whatever you want here.
NSLog(@"Running removeAllCachedResponses");
// If you need to call the actual implementation, do it like this:
[self swzl_removeAllCachedResponses];
}
You do not need to replace references of NSURLCache
with this subclass. All you need is to load it once from some place in your program.
Note: I am not sure if there is an easier way to do it. Method swizzling is definitely a heavy artillery, but it gets the job done.