Runtime实践
2016-06-03 09:34
295 查看
基础
总结:1.对类操作:class_
2. 对对象操作:objc_,ojbect_
3. 对属性操作:property_
4. 对变量操作:property_
5. 对变量操作:ivar_
6. 对方法操作:method_ (SEL+IMP)
7. 对方法操作: imp_
8. 对协议操作: protocol_
继承体系
//实例方法(减号方法): 实例对象instance->类class->方法method(->SEL->IMP)->实现函数
//静态方法(加号方法): 类对象->元类class->方法method(->SEL->IMP)->实现函数
struct objc_class { Class isa OBJC_ISA_AVAILABILITY; };
struct objc_object { Class isa OBJC_ISA_AVAILABILITY; };
## Method Swizzling,面向切面编程(另一种实现方式:继承)
- Method Swizzling 两种实现方式
方法1 - method_exchangeImplementations
/** * 要先尝试添加原 selector 是为了做一层保护,因为如果这个类没有实现 originalSelector ,但其父类实现了,那 class_getInstanceMethod 会返回父类的方法。这样 method_exchangeImplementations 替换的是父类的那个方法,这当然不是你想要的 * */ void swizzleMethod(Class class, SEL originalSelector, SEL swizzledSelector) { // 方法可能在当前类不存在,在父类存在,这时我们不需要swi Method originalMethod = class_getInstanceMethod(class, originalSelector); Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector); // 如果已存在,则会添加失败 为viewdidLoad添加swizzleViewDidLoad的实现 BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)); // 如果没有我们为其添加一个,以避免替换父类的方法 if (didAddMethod) { class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)); } else { method_exchangeImplementations(originalMethod, swizzledMethod); } } //调用 swizzleMethod(self.class, @selector(viewDidLoad), @selector(swizzleViewDidLoad)); -(void)swizzleViewDidLoad{//系统调用viewDidLoad(SEL)---找到这里swizzleViewDidLoad(IMP) [self swizzleViewDidLoad];//这里swizzleViewDidLoad(SEL)---找到viewDidLoad(IMP) NSLog(@"swizzleViewDidLoad invoked"); }
方法2—class_addMethod
void resetOriginMethodIMP(Class clazz, SEL originalSelector){ Method originalMethod=class_getInstanceMethod(clazz,originalSelector); originViewDidLoad=(void *)method_getImplementation(originalMethod); //IMP创建方法1 IMP swizzleIMP=imp_implementationWithBlock(^(id self,SEL _cmd){ NSLog(@"swizzleViewDidLoad invoked"); originViewDidLoad(self, _cmd); }); BOOL didAddMethod = class_addMethod(clazz, @selector(viewDidLoad),swizzleIMP, method_getTypeEncoding(originalMethod)); if (!didAddMethod) { method_setImplementation(originalMethod, swizzleIMP); } } //调用 resetOriginMethodIMP(self.class,@selector(viewDidLoad)); -(void)viewDidLoad{ [super viewDidLoad]; NSLog(@"viewDidLoad invoked"); }
小知识
问题 | +(void)load | +(void)initialize |
---|---|---|
执行时机 | 类别中的定义 | 在类的方法第一次被调时执行 |
若自身未定义,是否沿用父类的方法? | 否 | 是 |
类别中的定义 | 全都执行,但后于类中的方法 | 覆盖类中的方法,只执行一个 |
处理iOS中常见的崩溃
数组越界,数组中值为空,字典中值为空Method Swizzling
不识别的方法
//方案一(Method Resolution) //动态添加实现 +(BOOL)resolveInstanceMethod:(SEL)sel; //方案二(消息转发Fast forwarding) -(id)forwardingTargetForSelector:(SEL)aSelector; //方案三(伪多继承 Normal forwarding) -(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;
分类
当系统方法变为自定义方法- (void)fd_reloadRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation { if (self.fd_indexPathHeightCache.automaticallyInvalidateEnabled) { [self.fd_indexPathHeightCache buildCachesAtIndexPathsIfNeeded:indexPaths]; [indexPaths enumerateObjectsUsingBlock:^(NSIndexPath *indexPath, NSUInteger idx, BOOL *stop) { [self.fd_indexPathHeightCache enumerateAllOrientationsUsingBlock:^(FDIndexPathHeightsBySection *heightsBySection) { heightsBySection[indexPath.section][indexPath.row] = @-1; }]; }]; } @try { FDPrimaryCall([self fd_reloadRowsAtIndexPaths:indexPaths withRowAnimation:animation];); } @catch (NSException *exception) { NSLog(@"%@",exception); } @finally { } }
分类中移除通知和KVO 的两种方法
method swizzling
在分类中定义一个帮助类,作为分类的属性
添加属性的简便方法
//定义属性时用__避开大小写 #define lt_interface_property( __type, __name) #define lt_implementation_property( __type, __name)
分类中不能直接添加属性,而能直接添加方法的原因
问题:分类中实现代理,weak属性变量
应用
KVO[self.message lt_addObserver:self forKey:NSStringFromSelector(@selector(text)) withBlock:^(id observedObject, NSString *observedKey, id oldValue, id newValue) { textField.text=newValue; }];
//创建这个KVO类 然后额外的空间(通常为 0) Class kvoClass=objc_allocateClassPair(self.class, kvoClassName.UTF8String, 0); //借用父类self.class方法的签名 方法的实现是父类的class实现 Method clazzMethod=class_getInstanceMethod(self.class, @selector(class)); IMP kvo_classIMP=class_getMethodImplementation(self.superclass, @selector(class)); const char *classType=method_getTypeEncoding(clazzMethod); class_addMethod(kvoClass, @selector(class), kvo_classIMP, classType); //注册 objc_registerClassPair(kvoClass);
static void kvo_setter(id self,SEL _cmd, id newValue){ //获得父类 struct objc_super superclazz={ .receiver=self, .super_class=class_getSuperclass(object_getClass(self)) }; //强转,避免编译器警告 void (*objc_msgSendSuperCasted)(void *,SEL,id)=(void *)objc_msgSendSuper; //调用父类的setterf方法 objc_msgSendSuperCasted(&superclazz,_cmd,newValue); //遍历观察者,调用block NSMutableArray *observers=objc_getAssociatedObject(self, (__bridge void *)kLTKVOAssociatedObservers); }
isa-swizzling
object_setClass(self, clazz);
字典转模型
NSDictionary *dict = @{ @"name" : @"Jack", @"icon" : @"lufy.png", @"age" : @"20", @"height" : @1.55, @"money" : @"100.9", @"sex" : @(0), @"gay" : @"1" }; MJUserModel *userModel=[MJUserModel learn_objectWithKeyValues:dict]; unsigned int outCount=0; objc_property_t *properties=class_copyPropertyList(self.class, &outCount);
项目中实践
上拉加载的提示信息
网络层区分两端
FDTemplateLayoutCell
归档/单例对象赋值/获取私有属性和私有方法
获取网络状态: 2G-3G-4G ( UIApplication-statusBar-foregroundView-UIStatusBarDataNetworkItemView-dataNetworkType)
乱扯
Category的实现GCD
RunLoop
HTML5
c语言
相关文章推荐
- PostgreSQL教程(三):表的继承和分区表详解
- C#中struct和class的区别详解
- Lua面向对象之类和继承浅析
- 浅析Ruby中继承和消息的相关知识
- Java Runtime Environment 5.0 Update 12 下载
- 设计引导--一个鸭子游戏引发的设计理念(多态,继承,抽象,接口,策略者模式)
- C++实现不能被继承的类实例分析
- 深入剖析C++中的struct结构体字节对齐
- C++ 关于STL中sort()对struct排序的方法
- C# 面向对象三大特性:封装、继承、多态
- PHP类的封装与继承详解
- C# Struct的内存布局问题解答
- js继承 Base类的源码解析
- Javascript 面向对象 继承
- JavaScript 继承使用分析
- Javascript面向对象编程(二) 构造函数的继承
- Javascript中的几种继承方式对比分析
- javascript面向对象之Javascript 继承
- JavaScript 对象、函数和继承
- 详述JavaScript实现继承的几种方式(推荐)