簡介
Objective-C是一門古老的語言煎饼,但是是一門動態(tài)性的語言,因?yàn)樗膭討B(tài)性趴泌,使其又有了強(qiáng)大的生命力告组,在蘋果生態(tài)系統(tǒng)的平臺應(yīng)用廣泛,可謂互相成全了對方煤伟,Objective-C的動態(tài)性隨處可見,當(dāng)子類覆寫父類方法的時候木缝,總是在執(zhí)行前才決定該執(zhí)行什么便锨,不像C在編譯時就已經(jīng)決定了代碼的執(zhí)行,能讓Objective-C有強(qiáng)大動態(tài)性的就是Runtime類庫我碟。
原理
Runtime的核心就是消息轉(zhuǎn)發(fā)放案,當(dāng)對象調(diào)用方法是,程序執(zhí)行[object doSomething]時矫俺,會向消息接收者(object)發(fā)送一條消息(doSomething)吱殉,runtime會根據(jù)消息接收者是否能響應(yīng)該消息而做出不同的反應(yīng)。
簡單的說主要有這幾點(diǎn):
1.消息傳遞(Messaging)
2.動態(tài)方法解析和轉(zhuǎn)發(fā)
原理這一塊兒我并沒有寫的很詳細(xì)厘托,大家可以看這幾篇原理博客的詳細(xì)介紹友雳。
使用
1.在使用delegate的時候我們在判斷代理是否遵守協(xié)議的時候,會發(fā)送一條消息,當(dāng)消息沒有被響應(yīng)的時候铅匹,會拋出異常押赊。
//這里就是發(fā)送了一條消息,看代理是否能夠響應(yīng)到伊群,響應(yīng)到的時候執(zhí)行方法
if ([self.delegate respondsToSelector:@selector(dosomething:)]) {
[self.delegate dosomething:@""];
}
2.給對象添加category的時候是沒有辦法給之間添加property方法的考杉,需要使用runtime進(jìn)行動態(tài)綁定,這個可以參考AFNetwortking里面的寫法
@interface UIView (category)
//聲明
@property (nonatomic,copy) NSString *text;
@end
#import "UIView+category.h"
#import <objc/runtime.h>
//設(shè)置key
static char textKey;
@implementation UIView (category)
//設(shè)置關(guān)聯(lián)
-(void)setText:(NSString *)text{
objc_setAssociatedObject(self, &textKey, text, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
//獲取關(guān)聯(lián)的值
-(NSString *)text{
return objc_getAssociatedObject(self, &textKey);
}
@end
3.Method Swizzling
我覺得這才是Runtime運(yùn)用場景最為廣泛的地方,java有反射機(jī)制舰始,可以設(shè)置動態(tài)代理,實(shí)現(xiàn)AOP編程咽袜,但是Objective-C的Runtime則更為強(qiáng)大丸卷。
下面來看一段代碼
void swizzleMethod(Class class, SEL originalSelector, SEL swizzledSelector) {
//原始方法指針
originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
// 給類添加方法指針
didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod),method_getTypeEncoding(swizzledMethod));
if (didAddMethod)
{
//將原始的方法實(shí)現(xiàn)賦給swizzledSelector
class_replaceMethod(class, swizzledSelector,method_getImplementation(originalMethod),method_getTypeEncoding(originalMethod));
} else {
//交換方法實(shí)現(xiàn)
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
上面是一段比較常見的方法交叉代碼,但是我們在開發(fā)中用的是Aspects這個第三方的開源庫,用這個開源庫你可以實(shí)現(xiàn)自己的一些埋點(diǎn)統(tǒng)計或者判斷UI刷新询刹。
埋點(diǎn)統(tǒng)計
+ (void)load
{
[UIViewController aspect_hookSelector:@selector(viewWillAppear:)
withOptions:AspectPositionAfter
usingBlock:^(id<AspectInfo> aspectInfo) {
NSString *className = NSStringFromClass([[aspectInfo instance] class]);
DebugLog(@"%@ class tpo appear",className);
} error:NULL];
[UIViewController aspect_hookSelector:@selector(viewWillDisappear:)
withOptions:AspectPositionAfter
usingBlock:^(id<AspectInfo> aspectInfo) {
NSString *className = NSStringFromClass([[aspectInfo instance] class]);
DebugLog(@"%@ class tpo disappear",className);
} error:NULL];
}
判斷子線程UI刷新
+(void)load{
#if DEBUG
[UIView aspect_hookSelector:@selector(setNeedsLayout)
withOptions:AspectPositionAfter
usingBlock:^(id<AspectInfo> aspectInfo) {
NSString *className = NSStringFromClass([[aspectInfo instance] class]);
className = [NSString stringWithFormat:@"%@ can't use in background",className];
NSAssert([NSThread isMainThread],className);
} error:NULL];
[UIView aspect_hookSelector:@selector(setNeedsDisplay)
withOptions:AspectPositionAfter
usingBlock:^(id<AspectInfo> aspectInfo) {
NSString *className = NSStringFromClass([[aspectInfo instance] class]);
className = [NSString stringWithFormat:@"%@ can't use in background",className];
NSAssert([NSThread isMainThread],className);
} error:NULL];
[UIView aspect_hookSelector:@selector(setNeedsDisplayInRect:)
withOptions:AspectPositionAfter
usingBlock:^(id<AspectInfo> aspectInfo) {
NSString *className = NSStringFromClass([[aspectInfo instance] class]);
className = [NSString stringWithFormat:@"%@ can't use in background",className];
NSAssert([NSThread isMainThread],className);
} error:NULL];
#else
//不在release的時候添加是因?yàn)楹蚸spatch有沖突
#endif
}
hotfix
其實(shí)熱修復(fù)有很多方案,原理都是Method Swizzling,比較常見的選擇方案是JSPatch,但是我覺得JSPatch和Aspects沖突引發(fā)崩潰的問題應(yīng)該有JSPatch的作者bang來解決谜嫉,不應(yīng)該由開發(fā)者自己解決,雖然bang團(tuán)隊(duì)給出過解決方案凹联。
愛生活沐兰,愛運(yùn)動,熱愛交流蔽挠,歡迎討論住闯!