iOS开发技能回顾

OC动态性 的体现 及消息传递与转发机制

2019-10-25  本文已影响0人  猿人

OC动态性

oc的动态性主要体现三个方面

1 动态类型

2 动态绑定

1 . 利用动态类型和动态绑定还可以实现动态改变消息的执行者和消息的接受者。

2 . 利用消息传递和消息转发机制 主要处理应对一些接收者无法处理的消息,有机会将消息转发给其他对象处理。

3 . 运行时可以动态添加方法和属性; 动态绑定是基于动态类型的,运行对象类型确定后,对象的属性和方法也就确定了,可以通过isa指针找到方法列表 和属性

3 动态加载

4 消息传递机制

   ///objc_msgSend("对象","SEL","参数"...)
   objc_msgSend( id self, SEL op, ... )

5消息转发机制

1 .动态补加方法的实现

+(BOOL)resolveInstanceMethod:(SEL)sel
+(BOOL)resolveClassMethod:(SEL)sel

2 .将消息发送给另一个对象去处理

-(id)forwardingTargetForSelector:(SEL)aSelector

3 . 手动生成方法签名并转发给另一个对象

-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
-(void)forwardInvocation:(NSInvocation *)anInvocation
举例消息转发的过程

.首先创建Person 类 在.h里声明一个实例方法(这里以-(void)instanceMethod)为例子。然后.m不进行实现。在main 函数里初始化并且调用该方法。

//这是 Person.h
 #import <Foundation/Foundation.h>
   
   @interface Person : NSObject


 -(void)instanceMethod;
 
 @end
///这是main.m
#import "Person.h"
int main(int argc, const char * argv[]) {
   @autoreleasepool {
       
       
        Person * person = [[Person alloc]init];
       [person instanceMethod];
       
   }
   return 0;

. 这时运行 由于方法没有实现 所以一定会触发消息转发机制

. 首先进入第一道防线Person.m文件会提供运行时的转发接应,实现 resolveInstanceMethod 为找不到的方法(-(void)instanceMethod)的实现进行补救。

#import "Person.h"
#import <objc/runtime.h>
@implementation Person
//被动态添加的实例方法
void insMethod(id self,SEL _cmd)
{
   NSLog(@"我收到消息了动态补加的");
}
//动态补加方法
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
   if (sel == @selector(instanceMethod)) {
       class_addMethod(self, sel, (IMP)insMethod, "v@:");
       return YES;
   }
   return [super resolveInstanceMethod:sel];
}

.运行

2019-10-25 11:28:23.777657+0800 OC 动态性[17788:1898041] 我收到消息了动态补加的
Program ended with exit code: 0

.如果没有实现 + (BOOL)resolveInstanceMethod:(SEL)sel 或者返回了NO 那么进入第二道防线 实现-(id)forwardingTargetForSelector:(SEL)aSelector 方法返回一个实例对象,让对象代替原对象处理这个消息

#import "Person.h"
#import "Person2.h"
#import <objc/runtime.h>
@implementation Person
-(id)forwardingTargetForSelector:(SEL)aSelector
{
   //返回消息转发的实例 注意消息转发实例要和当前实例未实现的方法名一模一样。
   if (aSelector==@selector(instanceMethod)) {
       return [[Person2 alloc]init];
   }
   return nil;
}
///Person2.h 我是头文件
 #import <Foundation/Foundation.h>
 @interface Person2 : NSObject

 -(void)instanceMethod;

 @end

 ///Person2.m 我是实现文件
 #import "Person2.h"
 @implementation Person2

 -(void)instanceMethod;
 {
    NSLog(@"我是替Person完成的消息,我收到了");
 }
 @end
 

运行

2019-10-25 11:36:58.230856+0800 OC 动态性[17884:1901837] 我是替Person完成的消息,我收到了
Program ended with exit code: 0

如果上面的两个补救方法都没有实现 或者forwardingTargetForSelector 返回了nil 那么进入最后一道防线,需要手动生成方法签名并实现forwardInvocation方法将消息转发给另一个对象类似第二道防线 下面看代码

-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
   //为指定的方法手动生成签名
   NSString * selName = NSStringFromSelector(aSelector);
   if ([selName isEqualToString:@"instanceMethod"]) {
       return [NSMethodSignature signatureWithObjCTypes:"v@:"];
   }
   return [super methodSignatureForSelector:aSelector];
}
-(void)forwardInvocation:(NSInvocation *)anInvocation
{
   //如果另外一个对象可以响应该消息,那么将消息转发给它
   Person2 * person2 = [[Person2 alloc]init];
   if ( [person2 respondsToSelector:[anInvocation selector]]) {
       [anInvocation invokeWithTarget:person2];
   }
   
///Person2.h 我是头文件
#import <Foundation/Foundation.h>
@interface Person2 : NSObject

-(void)instanceMethod;

@end

///Person2.m 我是实现文件
#import "Person2.h"
@implementation Person2

-(void)instanceMethod;
{
   NSLog(@"我是替Person完成的消息,我收到了");
}
@end

运行

 2019-10-25 11:56:04.493146+0800 OC 动态性[18067:1910152] 我是替Person完成的消息,我收到了
Program ended with exit code: 0





上一篇 下一篇

猜你喜欢

热点阅读