iOS消息转发机制

简介:

    在Objective-C中,使用对象进行方法调用是一个消息发送的过程(Objective-C采用“动态绑定机制”,所以所要调用的方法直到运行期才能确定)。

    方法在调用时,系统会查看这个对象能否接收这个消息(查看这个类有没有这个方法,或者有没有实现这个方法。),如果不能并且只在不能的情况下,就会调用下面这几个方法,给你“补救”的机会,你可以先理解为几套防止程序crash的备选方案,我们就是利用这几个方案进行消息转发,注意一点,前一套方案实现后一套方法就不会执行。如果这几套方案你都没有做处理,那么程序就会报错crash。

    OC的运行时在程序崩溃前提供了三次拯救程序的机会:

方案一:

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

方案二:

?
1
- (id)forwardingTargetForSelector:(SEL)aSelector

方案三:

?
1
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;
?
1
- ( void )forwardInvocation:(NSInvocation *)anInvocation;


    上图显示了消息转发的具体流程,接收者在每一步中均有机会处理消息。步骤越往后处理消息的代价越大。首先,会调用

+ (BOOL)resolveInstanceMethod:(SEL)sel。若方法返回YES,则表示可以处理该消息。在这个过程,可以动态地给消息增加方法。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// Person.m
 
// 不自动生成getter和setter方法
@dynamic name; 
 
+ ( BOOL )resolveInstanceMethod:(SEL)sel
{
     if  (sel == @selector(name)) {
         // BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
         class_addMethod(self, sel, (IMP)GetterName,  "@@:" );
         return  YES;
     }
     if  (sel == @selector(setName:)) {
         class_addMethod(self, sel, (IMP)SetterName,  "v@:@" );
         return  YES;
     }
     
     return  [super resolveInstanceMethod:sel];
}
 
// (用于类方法)
//+ (BOOL)resolveClassMethod:(SEL)sel
//{
//    NSLog(@"resolveClassMethod called %@", NSStringFromSelector(sel));
//    
//    return [super resolveClassMethod:sel];
//}
 
id GetterName(id self, SEL cmd)
{
     NSLog(@ "%@, %s" , [self  class ], sel_getName(cmd));
 
     return  @ "Getter called" ;
}
 
void  SetterName(id self, SEL cmd, NSString *value)
{
     NSLog(@ "%@, %s, %@" , [self  class ], sel_getName(cmd), value);
     
     NSLog(@ "SetterName called"
);

签名符号含义:

*          代表  char * 
char BOOL  代表  c
:          代表  SEL 
^type      代表  type *
@          代表  NSObject * 或 id
^@         代表  NSError ** 
#          代表  NSObject 
v          代表  void
?
1
2
3
4
5
6
7
8
9
// main.m
/* 现在在main.m中给Person发送setName:和name消息,由于Person中未实现这两个方法,就会经消息转发调用GetterName和SetterName方法
*/
 
Person *person = [[Person alloc] init];
         
[person setName:@ "Jake" ];
         
NSLog(@ "%@" , [person name]);
?
1
2
3
4
5
6
// 输出结果:
 
Person, setName:, Jake
SetterName called
Person, name
Getter called

    

    若方法返回NO,则进行消息转发的第二步,查找是否有其它的接收者。对应的处理函数是:

- (id)forwardingTargetForSelector:(SEL)aSelector。可以通过该函数返回一个可以处理该消息的对象。

    现在新建一个类Child,在Child中实现一个eat方法,在Person类中定义eat方法但不实现它。

?
1
2
3
4
5
6
// Child.m
 
- ( void )eat
{
     NSLog(@ "Child method eat called" );
}

    然后在Person类中实现forwardingTargetForSelector:方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
// Person.m
// 当调用Person中的eat方法时,由于Person中并未实现该方法,就会经下面的方法将消息转发给可以处理eat方法的对象
 
- (id)forwardingTargetForSelector:(SEL)aSelector
{
     NSString *selStr = NSStringFromSelector(aSelector);
     
     if  ([selStr isEqualToString:@ "eat" ]) {
         return  [[Child alloc] init];         // 这里返回Child类对象,让Child去处理eat消息
     }
 
     return  [super forwardingTargetForSelector:aSelector];
}
?
1
2
3
// main.m
 
[person eat];
?
1
2
3
// 输出结果:
 
Child method eat called

    通过此方案,我们可以用“组合”来模拟出“多重继承”的某些特性。在一个对象内部,可能还有一系列其他对象,该对象可以经由此方法将能够处理某选择子的相关内部对象返回,这样的话,在外界看来好像是该对象亲自处理了这些消息。

    伪多继承与真正的多继承的区别在于,真正的多继承是将多个类的功能组合到一个对象中,而消息转发实现的伪多继承,对应的功能仍然分布在多个对象中,但是将多个对象的区别对消息发送者透明。


    若第二步返回nil,则进入消息转发的第三步。调用

- (void)forwardInvocation:(NSInvocation *)anInvocation。这个方法实现得很简单。只需要改变调用目标,使消息在新目标上得以调用即可。不过,如果采用这种方式,实现的效果与第二步的消息转发是一致的。所以比较有用的实现方式是:先以某种方式改变消息内容,比如追加另外一个参数,或者改换选择子,等等。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Person.m
 
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
      NSString *sel = NSStringFromSelector(aSelector);
     // 判断要转发的SEL
     if  ([sel isEqualToString:@ "sleep" ]) {
         // 为转发的方法手动生成签名
         return  [NSMethodSignature signatureWithObjCTypes: "v@:" ];
     }
     
     return  [super methodSignatureForSelector:aSelector]; 
}
 
- ( void )forwardInvocation:(NSInvocation *)anInvocation
{
     SEL selector = [anInvocation selector];
     // 新建需要转发消息的对象
     Child *child = [[Child alloc] init];
     if  ([child respondsToSelector:selector]) {
         // 唤醒这个方法
         [anInvocation invokeWithTarget:child];
     }
}
?
1
2
3
4
5
6
7
8
9
10
11
// Child.h
 
#import <Foundation/Foundation.h>
 
@interface Child : NSObject
 
- ( void )eat;
 
- ( void )sleep;
 
@end
?
1
2
3
4
5
6
// Child.m
 
- ( void )sleep
{
     NSLog(@ "Child method sleep called" );
}
?
1
2
3
// 输出结果:
 
Child method sleep called

    

    有时候服务器很烦不靠谱,老是不经意间返回null,可以重写NSNull的消息转发方法, 让他能处理这些异常的方法,达到解决问题的目的。

目录
相关文章
|
存储
13-iOS消息转发机制以及常用场景
13-iOS消息转发机制以及常用场景
89 0
|
1月前
|
存储 安全 Android开发
探索Android与iOS的隐私保护机制
在数字化时代,移动设备已成为我们生活的一部分,而隐私安全是用户最为关注的问题之一。本文将深入探讨Android和iOS两大主流操作系统在隐私保护方面的策略和实现方式,分析它们各自的优势和不足,以及如何更好地保护用户的隐私。
|
29天前
|
Linux Android开发 iOS开发
深入探索Android与iOS的多任务处理机制
在移动操作系统领域,Android和iOS各有千秋,尤其在多任务处理上展现出不同的设计理念和技术实现。本文将深入剖析两大平台在后台管理、资源分配及用户体验方面的策略差异,揭示它们如何平衡性能与电池寿命,为用户带来流畅而高效的操作体验。通过对比分析,我们不仅能够更好地理解各自系统的工作机制,还能为开发者优化应用提供参考。
|
1月前
|
存储 安全 算法
深入探索iOS系统安全机制:保护用户隐私的前沿技术
本文旨在探讨苹果公司在其广受欢迎的iOS操作系统中实施的先进安全措施,这些措施如何共同作用以保护用户的隐私和数据安全。我们将深入了解iOS的安全架构,包括其硬件和软件层面的创新,以及苹果如何通过持续的软件更新来应对新兴的安全威胁。此外,我们还将讨论iOS系统中的一些关键安全功能,如Face ID、加密技术和沙箱环境,以及它们如何帮助防止未经授权的访问和数据泄露。
|
1月前
|
安全 数据安全/隐私保护 Android开发
深入探索iOS系统安全机制:从基础到高级
本文旨在全面解析iOS操作系统的安全特性,从基础的权限管理到高级的加密技术,揭示苹果如何构建一个既开放又安全的移动平台。我们将通过实例和分析,探讨iOS系统如何保护用户数据免受恶意软件、网络攻击的威胁,并对比Android系统在安全性方面的差异。
|
2月前
|
存储 安全 数据安全/隐私保护
探索安卓与iOS的隐私保护机制####
【10月更文挑战第15天】 本文深入剖析了安卓和iOS两大操作系统在隐私保护方面的策略与技术实现,旨在揭示两者如何通过不同的技术手段来保障用户数据的安全与隐私。文章将逐一探讨各自的隐私控制功能、加密措施以及用户权限管理,为读者提供一个全面而深入的理解。 ####
78 1
|
5月前
|
调度 Swift Android开发
苹果iOS新手开发之Swift中的并发任务和消息机制
Swift的消息机制类似Android的Handler,实现任务调度有三种方式: 1. **Grand Central Dispatch (GCD)**:使用`DispatchQueue`在主线程或后台线程执行任务。 2. **OperationQueue**:提供高级接口管理`Operation`对象。 3. **RunLoop**:处理事件如输入源、计时器,类似Android的`Looper`和`Handler`。 **示例**: - GCD:在不同线程执行代码块。 - OperationQueue:创建操作并执行。 - RunLoop:用Timer添加到RunLoop中。
109 2
|
6月前
|
安全 算法 数据安全/隐私保护
探索iOS与Android的隐私保护机制
【6月更文挑战第5天】在数字时代,隐私保护已成为用户最关心的问题之一。iOS和Android作为两大主流操作系统,各自发展出了独特的隐私保护技术。本文将深入探讨这两个平台在隐私保护方面的策略、技术和挑战。
165 3
|
API iOS开发
iOS 沙盒机制
iOS 沙盒机制
155 0
|
iOS开发
iOS开发-聊天气泡的绘制和聊天消息列表
iOS开发-聊天气泡的绘制和聊天消息列表
256 0
iOS开发-聊天气泡的绘制和聊天消息列表