现在面试说几句就离不开Runtime,下面我将写一些简单的Runtime的概念,一方面复习巩固知识,另一方面希望读者能够有所收获。
Runtime是Objective-C中非常强大和灵活的运行时系统,它提供了一组API来动态地创建、修改、查询类和对象,支持消息发送、方法交换、动态添加方法等高级特性。下面,我们将以实际代码案例的形式,介绍Runtime的具体用法。
动态添加方法
动态添加方法是Runtime的一个重要特性之一,它允许我们在运行时动态地为一个类添加新的方法。下面是一个简单的例子:
#import <objc/runtime.h> @interface MyClass : NSObject @end @implementation MyClass @end void dynamicMethodIMP(id self, SEL _cmd) { NSLog(@"添加的方法已经被调用"); } int main(int argc, char * argv[]) { @autoreleasepool { MyClass *myClass = [[MyClass alloc] init]; class_addMethod([myClass class], @selector(dynamicMethod), (IMP) dynamicMethodIMP, "v@:"); if ([myClass respondsToSelector:@selector(dynamicMethod)]) { [myClass performSelector:@selector(dynamicMethod)]; } else { NSLog(@"方法未被添加"); } } return 0; }
在这个例子中,我们首先定义了一个MyClass类,并在运行时动态地为它添加了一个名为dynamicMethod的方法。我们使用class_addMethod函数来添加方法,它需要传入一个类对象、一个方法选择器、一个方法的实现和一个方法签名。在这个例子中,我们使用了一个名为dynamicMethodIMP的函数作为方法的实现,它打印一条消息。最后,我们通过检查对象是否响应dynamicMethod方法来判断方法是否已经被添加,并使用performSelector方法来调用它。
方法交换
方法交换是Runtime的另一个重要特性,它允许我们在运行时动态地交换两个方法的实现。下面是一个简单的例子:
#import <objc/runtime.h> @interface MyClass : NSObject - (void)originalMethod; @end @implementation MyClass - (void)originalMethod { NSLog(@"原始方法已经被调用"); } @end @implementation MyClass (Category) - (void)swizzledMethod { NSLog(@"交换后的方法已经被调用"); [self swizzledMethod]; } @end int main(int argc, char * argv[]) { @autoreleasepool { MyClass *myClass = [[MyClass alloc] init]; Method originalMethod = class_getInstanceMethod([MyClass class], @selector(originalMethod)); Method swizzledMethod = class_getInstanceMethod([MyClass class], @selector(swizzledMethod)); method_exchangeImplementations(originalMethod, swizzledMethod); [myClass originalMethod]; } return 0; }
在这个例子中,我们首先定义了一个MyClass类,并在它的Category中添加了一个名为swizzledMethod的方法。我们使用method_exchangeImplementations函数来交换originalMethod和swizzledMethod的实现。最后,我们使用originalMethod方法来调用原始的方法,但实际上它会调用被交换后的swizzledMethod。
消息转发
消息转发是Runtime的另一个重要特性,它允许我们在运行时处理未知消息或方法。下面是一个简单的例子:
#import <objc/runtime.h> @interface MyClass : NSObject @end @implementation MyClass - (void)forwardInvocation:(NSInvocation *)anInvocation { NSLog(@"消息转发已经被触发"); } - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { return [NSMethodSignature signatureWithObjCTypes:"v@:"]; } @end int main(int argc, char * argv[]) { @autoreleasepool { MyClass *myClass = [[MyClass alloc] init]; [myClass performSelector:@selector(unknownMethod)]; } return 0; }
在这个例子中,我们首先定义了一个MyClass类,并重写了forwardInvocation和methodSignatureForSelector方法。当对象收到一个未知的消息时,它会触发forwardInvocation方法。我们还需要重写methodSignatureForSelector方法来返回一个合法的方法签名,这是消息转发的必要步骤。最后,我们使用performSelector方法来调用一个名为unknownMethod的未知方法,这会触发消息转发机制并调用forwardInvocation方法。
上述代码案例展示了Runtime的一些常用特性和API的用法,包括动态添加方法、方法交换和消息转发,献丑了各位。