在obj-c中我们可以向一个实例发送消息,相当于c/c++ java中的方法调用,只不过在这儿是说发送消息,实例收到消息后会进行一些处理。比如我们想调用一个方法,便向这个实例发送一个消息,实例收到消息后,如果能respondsToSelector,那么就会调用相应的方法。如果不能respond一般情况下会crash。今天要的,就是不让它crash。
首先说一下向一个实例发送一个消息后,系统是处理的流程:
1. 发送消息如:[self startwork]
2. 系统会check是否能response这个消息
3. 如果能response则调用相应方法,不能则抛出异常
在第二步中,系统是如何check实例是否能response消息呢?如果实例本身就有相应的response,那么就会相应之,如果没有系统就会发出methodSignatureForSelector消息,寻问它这个消息是否有效?有效就返回对应的方法地址之类的,无效则返回nil。如果是nil,Runtime则会发出-doesNotRecognizeSelector:消息,程序这时也就挂掉了. 如果不是nil接着发送forwardInvocation消息。
所以我们在重写methodSignatureForSelector的时候就人工让其返回有效实例。
我们定义了这样一个类
@interface TargetProxy : NSProxy { id realObject1; id realObject2; } - (id)initWithTarget1:(id)t1 target2:(id)t2; @end
实现:
@implementation TargetProxy - (id)initWithTarget1:(id)t1 target2:(id)t2 { realObject1 = [t1 retain]; realObject2 = [t2 retain]; return self; } - (void)dealloc { [realObject1 release]; [realObject2 release]; [super dealloc]; } // The compiler knows the types at the call site but unfortunately doesn't // leave them around for us to use, so we must poke around and find the types // so that the invocation can be initialized from the stack frame. // Here, we ask the two real objects, realObject1 first, for their method // signatures, since we'll be forwarding the message to one or the other // of them in -forwardInvocation:. If realObject1 returns a non-nil // method signature, we use that, so in effect it has priority. - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { NSMethodSignature *sig; sig = [realObject1 methodSignatureForSelector:aSelector]; if (sig) return sig; sig = [realObject2 methodSignatureForSelector:aSelector]; return sig; } // Invoke the invocation on whichever real object had a signature for it. - (void)forwardInvocation:(NSInvocation *)invocation { id target = [realObject1 methodSignatureForSelector:[invocation selector]] ? realObject1 : realObject2; [invocation invokeWithTarget:target]; } // Override some of NSProxy's implementations to forward them... - (BOOL)respondsToSelector:(SEL)aSelector { if ([realObject1 respondsToSelector:aSelector]) return YES; if ([realObject2 respondsToSelector:aSelector]) return YES; return NO; } @end
现在我们还用这个类,注意向它发送的消息:
id proxy = [[TargetProxy alloc] initWithTarget1:string target2:array]; // Note that we can't use appendFormat:, because vararg methods // cannot be forwarded! [proxy appendString:@"This "]; [proxy appendString:@"is "]; [proxy addObject:string]; [proxy appendString:@"a "]; [proxy appendString:@"test!"]; NSLog(@"count should be 1, it is: %d", [proxy count]); if ([[proxy objectAtIndex:0] isEqualToString:@"This is a test!"]) { NSLog(@"Appending successful."); } else { NSLog(@"Appending failed, got: '%@'", proxy); }
运行的结果是:
count should be 1, it is: 1
Appending successful.
TargetProxy声明中是没有appendString与addObject消息的,在这儿却可以正常发送,不crash,原因就是发送消息的时候,如果原本类没有这个消息响应的时候,转向询问methodSignatureForSelector,接着在forwardInvocation将消息重定向。
///////////
相关推荐
这两个特性是基于Objective-C的动态性,源码中会有对应的实现细节。 3. **初始化和释放**:`NSObject`定义了`init`和`dealloc`方法,是所有对象初始化和销毁的基本入口。通过阅读源码,我们可以看到如何正确地初始...
定义了一个`KeyboardProtocol`协议,其中包含两个必需的方法:`keyboardWillShow:` 和 `keyboardWillHide:`。这些方法在键盘将要显示和将要隐藏时调用,允许类接收这些通知并作出相应的反应。 ##### 1.2 ...
- **`- (BOOL)isEqual:(id)object`**:比较两个对象是否相等。此方法允许对对象进行等价性检查。 - **`- (NSUInteger)hash`**:返回对象的哈希值。通常与 `-isEqual:` 配合使用,以提高效率。 - **`- (NSString *)...
NSObject脑图
`没有处理消息,最后会进入完整的消息转发流程,调用`- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector`获取方法签名,然后通过`NSInvocation`发送消息给`- (void)forwardInvocation:...
6. **添加属性**:添加属性涉及到两个步骤:声明属性和实现存取方法。可以使用`class_addProperty()`添加属性,然后通过`class_getProperty()`获取属性信息。接着,为属性添加对应的getter和setter方法,可以使用`...
4. **方法的交换(Method Swizzling)**:Runtime的另一个强大功能是方法交换,通过`method_exchangeImplementations`函数,可以替换两个方法的实现。这常用于AOP(面向切面编程),比如在不修改原代码的情况下添加...
这一过程涉及到两个关键方法:`methodSignatureForSelector:` 和 `forwardInvocation:`。 - `methodSignatureForSelector:` 方法负责为即将转发的消息创建方法签名。如果没有匹配的方法签名,则尝试为消息创建一个...
而`description`方法是`NSObject`中的一个关键方法,用于返回一个对象的字符串表示,通常用于调试和日志记录。`NSObject+Description`这个类别(Category)是为了提供一种更快捷、更方便的方式来使用`description`...
在PYTheme中,类别被用来扩展`NSObject`,使得所有的Swift对象都可以方便地与主题系统进行交互。 PYTheme的核心思想是将主题定义为一组颜色、图片等资源的集合,通过一个全局的主题管理器来控制这些资源的切换。当...
协议中<NSobject>是什么意思? 子类继承了父类,子类会遵守父类遵守的协议吗? 会遵守NSObject协议,但是只在头文件中声明,编译器是不会自动生成实例变量的。需要自己处理getter和setter 方法 NS/CF/CG/CA/UI这些...
值得一提的是,如果我们计算NSObjct大小的话,会发现malloc_size方法返回的是16字节,原因如下:OC的底层代码中对给对象分配的最小内存空间做了限制,限制最小为16字节,所以NSObject对象虽然仅仅有一个ISA指针,...
- `method_exchangeImplementations()`: 交换两个方法的实现。 - `object_setIvar()` 和 `object_getIvar()`: 设置和获取实例变量的值。 - `addMethod()` 和 `removeMethod()`: 添加或删除方法。 - `...
在NSObject类中,`isa`通常指向元类(meta-class),元类是类的类,负责存储类的方法列表。 其次,OC对象还包含实例变量。实例变量是对象内部存储数据的地方,这些数据可以是基本类型如int、float,也可以是其他...
利用runtime对NSObject进行分类扩展,解决字典转Model的问题 原理:http://www.jianshu.com/p/71454166c397 github:https://github.com/cccgoodboy/CCModel 喜欢请给个star 谢谢!
NSObject-序列化用法要运行示例项目, ... 要安装它,只需将以下行添加到您的 Podfile 中: pod "NSObject-Serialize"作者ipconfiger, 执照NSObject-Serialize 在 MIT 许可下可用。 有关详细信息,请参阅许可证文件。
本篇将详细介绍如何在两个ViewController之间利用委托协议进行值传递,以及它与Android中`onActivityResult`方法的相似之处。 首先,我们需要理解什么是委托协议。在Objective-C或Swift中,委托是一种设计模式,...
因为,NSObject是顶级父类,在NSObject中添加了该方法,也就是说通过继承关系,所有的类中都有该方法。 正式协议是通过protocol指定的一系列方法的声明,然后由实现该协议的类自己去实现这些方法。而非正式协议是...