Overriding methods in Objective-C

There are few ways to override methods in Objectiv-C. First lets define what overriding method means. Method overriding is a language feature in which a class can provide an implementation of a method that is already provided by one of its parent classes. The implementation in this class replaces (that is, overrides) the implementation in the parent class.

@interface MyClass : NSObject

- (NSString*)myString;

@end

@implementation MyClass

- (NSString*)myString
{
    return @"Default value";
}

@end

#import "MyClass.h"

@interface MySubclass : MyClass

@end

@implementation MySubclass

- (NSString*)myString
{
    return @"Subclass value";
}

@end

If you create an instance of MyClass and send it a myString message, it returns @”Default value”. If you create an instance of MySubclass and send it a myString message, it returns @”Subclass value”. Notice that the subclass’s method must have the same name and parameter list as the superclass’s overridden method.

In some cases you will need to change method implementation without creating additional subclass. This can be achieved simply by making category and implementing method with same signature to override default method implementation.

#import "MyClass.h"

@interface MyClass (Category)

- (NSString*)myString;

@end

@implementation MyClass (Category)

- (NSString*)myString
{
    return @"Category value";
}

@end

Also, there is another way to modify the runtime code. Dynamic language such as Objective-C supports method swizzling. This way you can modify the mappings from a selector (method name) to an implementation (the method code itself) or simply “patch” methods in code you don’t have the source to by exchanging 2 methods.

#import "MyClass.h"

@interface MyClass (Swizzle)

- (NSString*)myString;

@end

#import <objc/runtime.h>

void SwizzleInstanceMethod(Class c, SEL orig, SEL new)
{
    Method origMethod = class_getInstanceMethod(c, orig);
    Method newMethod = class_getInstanceMethod(c, new);
    if(class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)))
        class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
    else
        method_exchangeImplementations(origMethod, newMethod);
}

void SwizzleClassMethod(Class c, SEL orig, SEL new)
{
    Method origMethod = class_getClassMethod(c, orig);
    Method newMethod = class_getClassMethod(c, new);

    c = object_getClass((id)c);

    if(class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)))
        class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
    else
        method_exchangeImplementations(origMethod, newMethod);
}

@implementation MyClass (Swizzle)

+ (void)load
{
    SwizzleInstanceMethod([self class], @selector(myString), @selector(myStringSwizzled));
}

- (NSString*)myStringSwizzled
{
    return @"Swizzled Method value";
}

@end

Example project https://github.com/IvanKalaica/OverridingMethodCallsExample

Saluto! 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *