iOS中消息转发的实现

嗯,运行时,运行时是个好东西。在Objective-C语言中,这个特性可以帮助我们干很多的事情。

首先这个特性是把代码的决策从编译和链接时变成运行的时候,这样我们就可以用这个特性来做一些只有在运行的时候才能做到的东西,具体包括:

1.swizzling (交换两个方法的实现)

2.动态方法(可以在运行的时候对一个类进行方法的增加,我们这篇博客会主要讲解这个)

3.相关引用(可以把一个类和一个对象使用一个key进行关联)

4.内省(判断一个对象是否可以调用一个方法)

5.使用emoji字符作为方法名

我们分为两部分讲解消息转发,一种是在本类中增加一个对于无法响应的方法的实现,一个是让另一个对象来响应用户调用的方法。

我们首先知道,当我们调用一个对象的一个方法的时候,会通过*isa真寻找本类中对于该方法的实现IMP,如果本类找不到,则会向父类寻找,当走到NSObject都无法调用时,程序会crash掉。但是在crash之前,运行时为我们提供了一个机制就是可以动态地增加这个方法的实现或者让另一个对象来响应这个方法。

我们先看看动态增加一个方法吧,比如我们调用了对象无法响应的doFoo方法,但是我们在类中有一个方法实现的声明:

void fooMethod(id obj, SEL _cmd) {

    NSLog(@"hehe");
}

我们希望用这个方法来实现doFoo方法,那么我们就需要重写+(BOOL)resolveInstanceMethod:(SEL)aSEL方法,具体如下:

+(BOOL)resolveInstanceMethod:(SEL)aSEL
{
    if(aSEL == @selector(doFoo)){
        class_addMethod([self class],aSEL,(IMP)fooMethod,"[email protected]:");
        return YES;
    }
    return [super resolveInstanceMethod:aSEL];
}

打一下断点,我们就可以看到控制台输出了"hehe".

以上就是动态增加这个方法的实现的过程。

第二个就是让另一个对象响应这个方法。

系统会先走入- (id)forwardingTargetForSelector:(SEL)aSelector方法来进行转发,我们就需要重写这个方法,具体如下:

- (id)forwardingTargetForSelector:(SEL)aSelector
{
    if(aSelector == @selector(doFoo)){
        return self.alternativeObject;
    }
    return [super forwardingTargetForSelector:aSelector];
}

系统获得了这个对象之后,就会使用-(void)forwardInvocation:(NSInvocation
*)invocation方法来把方法统一进行执行,具体如下:

-(void)forwardInvocation:(NSInvocation *)invocation
{
    SEL invSEL = invocation.selector;

    if([self.alternativeObject respondsToSelector:invSEL]) {
        [invocation invokeWithTarget:self.alternativeObject];
    } else {
        [self doesNotRecognizeSelector:invSEL];
    }
}

好了,我们在alternativeObject中响应方法打断点,我们发现执行到了!~

以上就是要说明的啦~~

时间: 2024-12-21 23:48:33

iOS中消息转发的实现的相关文章

iOS开发-消息转发

消息转发是OC运行时比较重要的特性,Objective-C运行时的主要的任务是负责消息分发,我们在开发中"unrecognized selector sent to instance xx",实例对象没有实现对应的消息,通常我们只需要实现未实现的方法即可.一般情况我们处理一个方法,运行时寻找匹配的selector然后执行,但是有时候只想在运行时才创建某个方法,消息确没有具体的实现,这个时候就会出出现运行时错误,按照消息转发的顺序我们有三种解决办法. 动态方法处理 首先我们来看一个简单的

iOS中消息的传递机制(KVO、Notification、delegation、block以及target-action)---转载

注1:本文由破船[博客]译自Communication Patterns. 本文目录如下所示: 可用的机制 做出正确的选择 Framework示例 小结 每个应用程序或多或少,都由一些松耦合的对象构成,这些对象彼此之间要想很好的完成任务,就需要进行消息传递.本文将介绍所有可用的消息传递机制,并通过示例来介绍这些机制在苹果的Framework中如何使用,同时,还介绍了一些最佳实践建议,告诉你什么时机该选择使用什么机制. 虽然这一期的主题是关于Foundation Framework的,不过本文中还

关于OC中消息转发机制的理解以及在项目中的实际应用

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">关于OC中的消息转发机制想必大家都很了解,现在来温习一下:</span> 一.什么是消息转发? @selector 是什么? 1一种类型 SEL 2代表你要发送的消息(方法), 跟字符串有点像, 也可以互转.: NSSelectorFromString()   /   NSS

iOS中消息的传递机制

小结 每个应用程序或多或少,都由一些松耦合的对象构成,这些对象彼此之间要想很好的完成任务,就需要进行消息传递.本文将介绍所有可用的消息传递机制,并通过示例来介绍这些机制在苹果的Framework中如何使用,同时,还介绍了一些最佳实践建议,告诉你什么时机该选择使用什么机制. 虽然这一期的主题是关于Foundation Framework的,不过本文中还介绍了一些超出Foundation Framework(KVO和Notification)范围的一些消息传递机制,另外还介绍了delegation,

iOS消息转发机制

iOS消息转发机制 “消息派发系统”(message-dispatch system) 若想令类能够理解某条消息,我们必须实现出对应的方法才行.但是,在编译器向类发送其无法解读的消息时并不会报错,因为在运行期可以继续向类中添加方法,所以编译器在编译时还无法确定类中到底会不会有某个方法的实现.当对象接收到无法解读的消息时,就会启动“消息转发”机制,我们可以经由此过程告诉对象应该如何处理未知消息. 消息转发分为两个阶段.第一阶段先征询接收者所属的类,看其是否能动态添加方法,已处理当前这个“未知的选择

iOS知识树,知识目录(包括对象、Block、消息转发、GCD、运行时、runloop、动画、Push、KVO、tableview,UIViewController、提交AppStore)

本文旨在总结iOS知识网络,该知识网络罗列出常见UIKit,Foundation的对象特点和一些使用经验:文本编辑采用树的形式,对知识点进行罗列,并标注一些使用经验(★)希望对初学者有用或给一些解决疑难杂症者提供思路:某些知识点会深入探讨:通过总结希望站在一个较高平台的角度全观Objective-C.知识树中有些是原创文章,有些则是转载网络上iOS大神的文章.笔者会尽量详细的介绍各个知识点.当然一个人的知识面是相当有限的,在给各位读者提供知识参考的同时,欢迎大家对本文提意见. /->UIView

iOS runtime探究(二): 从runtime開始深入理解OC消息转发机制

你要知道的runtime都在这里 转载请注明出处 http://blog.csdn.net/u014205968/article/details/67639289 本文主要解说runtime相关知识,从原理到实践.由于包括内容过多分为下面五篇文章详细解说.可自行选择须要了解的方向: 从runtime開始: 理解面向对象的类到面向过程的结构体 从runtime開始: 深入理解OC消息转发机制 从runtime開始: 理解OC的属性property 从runtime開始: 实践Category加入属

iOS消息转发

消息转发是一种功能强大的技术,可以大大增加Objective-C的表现力.什么是消息转发?简而言之,它允许未知的消息被困住并作出反应.换句话说,无论何时发送未知消息,它??都会以一个很好的包发送到您的代码中,此时您可以随心所欲地执行任何操作. 为什么它被称为 "转发"? 当某个对象没有任何响应某个 消息 的操作就 "转发" 该 消息.原因是这种技术主要是为了让对象让其他对象为他们处理 消息,从而 "转发". 1. 类,对象,方法 在我们开始使用消

IOS 消息转发

最近在看消息转发的资料,发现大部分都是理论知识,很少有完整的代码.现在以代码的形式形象的解释一下: 用Xcode创建一个工程 1.正常方法调用 创建一个类Person 代码如下 Person.h代码如下: #import <Foundation/Foundation.h> @interface Person : NSObject - (instancetype)init NS_UNAVAILABLE; - (instancetype)initWithUserName:(NSString *)u