proto 通过 tar sign cat pack pre form
一、便利类的成员变量、属性、方法
/** 遍历类所以成员变量
* @param <#__unsafe_unretained Class cls#> 要遍历的类
* @param <#unsigned int *outCount#> 成员变量数量
*/
// class_copyIvarList(<#__unsafe_unretained Class cls#>, <#unsigned int *outCount#>)
unsigned int count = 0;
Ivar * ivars = class_copyIvarList([UIView class], &count);
for (int i = 0; i < count; i++) {
Ivar ivar = ivars[i];
const char * name = ivar_getName(ivar);
NSString * str = [NSString stringWithUTF8String:name];
NSLog(@"%d:%@",i,str);
}
free(ivars);
/** 遍历类所以属性
* @param <#__unsafe_unretained Class cls#> 要遍历的类
* @param <#unsigned int *outCount#> 属性数量
*/
//class_copyPropertyList(<#__unsafe_unretained Class cls#>, <#unsigned int *outCount#>)
unsigned int propertyCount = 0;
objc_property_t * propertys = class_copyPropertyList([UIView class], &propertyCount);
for (int i = 0; i < propertyCount; i++) {
objc_property_t property = propertys[i];
const char * name = property_getName(property);
NSString * str = [NSString stringWithUTF8String:name];
NSLog(@"%d:%@",i,str);
}
free(propertys);
/** 遍历类所有方法
* @param <#__unsafe_unretained Class cls#> 要遍历的类
* @param <#unsigned int *outCount#> 属性数量
*/
//class_copyMethodList(<#__unsafe_unretained Class cls#>, <#unsigned int *outCount#>)
unsigned int methodCount = 0;
Method * methods = class_copyMethodList([UIView class], &methodCount);
for (int i = 0; i < count; i++) {
Method method = methods[i];
SEL sel = method_getName(method);
NSLog(@"%d:%@",i,NSStringFromSelector(sel));
}
free(methods);
二、消息转发
消息转发机制执行前,Runtime 系统允许我们替换消息的接收者为其他对象。通过
方法。
- - (id)forwardingTargetForSelector:(SEL)aSelector
- - (id)forwardingTargetForSelector:(SEL)aSelector
- {if(aSelector ==@selector(mysteriousMethod:)){return alternateObject;
- }return [super forwardingTargetForSelector:aSelector];
- }
如果此方法返回
或者
- nil
,则会计入消息转发机制 (
- self
),否则将向返回的对象重新发送消息。
- forwardInvocation:
当动态方法解析不做处理返回
时,则会触发消息转发机制。这时
- NO
方法会被执行,我们可以重写这个方法来自定义我们的转发逻辑:
- forwardInvocation:
- - (void)forwardInvocation:(NSInvocation *)anInvocation
- {if ([someOtherObject respondsToSelector:
- [anInvocation selector]])
- [anInvocation invokeWithTarget:someOtherObject];else
- [super forwardInvocation:anInvocation];
- }
唯一参数是个
类型的对象,该对象封装了原始的消息和消息的参数。我们可以实现
- NSInvocation
方法来对不能处理的消息做一些处理。也可以将消息转发给其他对象处理,而不抛出错误。
- forwardInvocation:
注意:参数
在
- anInvocation 是从哪来的?
消息发送前,Runtime 系统会向对象发送
- forwardInvocation:
消息,并取到返回的方法签名用于生成 NSInvocation 对象。所以重写
- methodSignatureForSelector:
的同时也要重写
- forwardInvocation:
方法,否则会抛异常。
- methodSignatureForSelector:
当一个对象由于没有相应的方法实现而无法相应某消息时,运行时系统将通过
消息通知该对象。每个对象都继承了
- forwardInvocation:
方法。但是,
- forwardInvocation:
中的方法实现只是简单的调用了
- NSObject
。通过实现自己的
- doesNotRecognizeSelector:
方法,我们可以将消息转发给其他对象。
- forwardInvocation:
方法就是一个不能识别消息的分发中心,将这些不能识别的消息转发给不同的接收对象,或者转发给同一个对象,再或者将消息翻译成另外的消息,亦或者简单的 "吃掉" 某些消息,因此没有响应也不会报错。这一切都取决于方法的具体实现。
- forwardInvocation:
注意:
方法只有在消息接收对象中无法正常响应消息时才会被调用。所以,如果我们向往一个对象将一个消息转发给其他对象时,要确保这个对象不能有该消息的所对应的方法。否则,
- forwardInvocation:
将不可能被调用。
- forwardInvocation:
转发和继承相似,可用于为 Objc 编程添加一些多继承的效果。就像下图那样,一个对象把消息转发出去,就好像它把另一个对象中的方法接过来或者 "继承" 过来一样。
这使得在不同继承体系分支下的两个类可以实现 "继承" 对方的方法,在上图中
和
- Warrior
没有继承关系,但是
- Diplomat
将
- Warrior
消息转发给了
- negotiate
后,就好似
- Diplomat
是
- Diplomat
的超类一样。
- Warrior
消息转发弥补了 Objc 不支持多继承的性质,也避免了因为多继承导致单个类变得臃肿复杂。
虽然转发可以实现继承的功能,但是
还是必须表面上很严谨,像
- NSObject
和
- respondsToSelector:
这类方法只会考虑继承体系,不会考虑转发链。
- isKindOfClass:
如果上图中的
对象被问到是否能响应
- Warrior
消息:
- negotiate
- if ( [aWarrior respondsToSelector:@selector(negotiate)] )
- ...
回答当然是
, 尽管它能接受
- NO
消息而不报错,因为它靠转发消息给
- negotiate
类响应消息。
- Diplomat
如果你就是想要让别人以为
继承到了
- Warrior
的
- Diplomat
方法,你得重新实现
- negotiate
和
- respondsToSelector:
来加入你的转发算法:
- isKindOfClass:
- - (BOOL)respondsToSelector:(SEL)aSelector
- {if ( [super respondsToSelector:aSelector] )returnYES;else {/* Here, test whether the aSelector message can *
- * be forwarded to another object and whether that *
- * object can respond to it. Return YES if it can. */
- }returnNO;
- }
除了
和
- respondsToSelector:
之外,
- isKindOfClass:
中也应该写一份转发算法。如果使用了协议,
- instancesRespondToSelector:
同样也要加入到这一行列中。
- conformsToProtocol:
如果一个对象想要转发它接受的任何远程消息,它得给出一个方法标签来返回准确的方法描述
,这个方法会最终响应被转发的消息。从而生成一个确定的
- methodSignatureForSelector:
对象描述消息和消息参数。这个方法最终响应被转发的消息。它需要像下面这样实现:
- NSInvocation
- - (NSMethodSignature*)methodSignatureForSelector:(SEL)selector
- {NSMethodSignature* signature = [super methodSignatureForSelector:selector];if (!signature) {
- signature = [surrogate methodSignatureForSelector:selector];
- }return signature;
- }
runtime 的一些应用
来源: http://www.bubuko.com/infodetail-2011955.html