您的位置:首页 > 其它

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语言
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  struct 继承 runtime