消息机制 - 调用私有方法
OC的runtime特性,使其没有严格意义上的私有方法。
objc_getClass()
sel_registerName()
objc_msgSend()
例:
@interface MyObjcet : NSObject
@end
@implementation MyObjcet
- (void)myFunction
{
NSLog(@"myFunction");
}
@end
//即使myFunction方法没有通过.h暴露出来,也是可以调用成功的。
MyObjcet *obj = [MyObjcet new];
objc_msgSend(obj, sel_registerName("myFunction"));
方法交换
很多时候,我们想要对系统框架的某些方法添加一些自定义逻辑。继承是个解决办法,但得改代码,如何尽可能少的侵入项目呢?
class_getClassMethod()
class_getInstanceMethod()
method_exchangeImplementations()
例: NSMutableDictionary的setObject:forKey:方法,当obj为nil的时候就会抛异常。多写几个if其实也ok,可是...
+ (void)load
{
Class clas = [object_getClass([NSMutableDictionary dictionary]) class];
Method original = class_getInstanceMethod(clas, @selector(setObject:forKey:));
Method new = class_getInstanceMethod(clas, @selector(he_setObject:forKey:));
method_exchangeImplementations(original, new);
}
@implementation NSMutableDictionary (HECrashHandle)
- (void)he_setObject:(id)anObject forKey:(id<NSCopying>)aKey{
if(aKey == nil) return;
if(anObject == nil){
[self removeObjectForKey:aKey];
}else{
[self he_setObject:anObject forKey:aKey];
}
}
@end
分类中添加属性
分类的初衷是为扩展方法而存在的,但很多时候我们需要在分类中添加属性以满足需求。
objc_setAssociatedObject()
objc_getAssociatedObject()
例: 为UIView添加属性myDesc
@interface UIView (Desc)
@property NSString *myDesc;
@end
@implementation UIView (Desc)
- (NSString *)myDesc
{
return objc_getAssociatedObject(self, _cmd);
}
- (void)setMyDesc:(NSString *)myDesc
{
objc_setAssociatedObject(self, @selector(myDesc), myDesc, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
@end
添加方法
这个我这没怎么用上,如果有好的使用场景,欢迎在下方的评论区一起交流
resolveClassMethod:
resolveInstanceMethod:
class_addMethod()
示例:
void myMethodIMP(id self, SEL _cmd) { .... }
@implementation MyClass
+ (BOOL)resolveInstanceMethod:(SEL)aSEL
{
if (aSEL == @selector(resolveThisMethodDynamically)) {
class_addMethod([self class], aSEL, (IMP) dynamicMethodIMP, "v@:");
return YES;
}
return [super resolveInstanceMethod:aSEL];
}
@end