為了學習Runtime武花,我們應該需要從幾個方面入手:
- 是什么?
- 為什么會出現(xiàn)杈帐?
- 怎么做体箕?
- 分享
- 能干嘛?
是什么挑童? 為什么會出現(xiàn)干旁?
C語言是靜態(tài)語言,決定階段是在編譯期炮沐,而我們偉大的Apple工程師(其實Objective-C不是Apple發(fā)明的,這里姑且這么算吧)把Objective-C定義為了動態(tài)語言回怜。那要讓Objectiive-C具有動態(tài)語言的特性大年,就必須有一個東西承載這種特性,而這種特性就是Runtime玉雾。個人理解翔试,如有偏頗見諒!
具體其他定義可Google搜索复旬,會看到有很多資料垦缅,不多說了。
怎么做驹碍?
在Objective-C中一個類其實主要分幾個部分:
- protocol
- Ivar
- property
- method
今天我們就來研究一下這主要的幾個部分壁涎。
先上一個隨便寫的類:
#import <Foundation/Foundation.h>
@protocol RuntimeBaseProtocol <NSObject>
@optional
- (void)doBaseAction;
@end
@protocol RuntimeProtocol <NSObject>
@required
- (void)doRequiredAction;
@optional
- (void)doOptionalAction;
@end
@interface RuntimeObject : NSObject <RuntimeProtocol,RuntimeBaseProtocol>
{
NSString *name;
NSString *kind;
}
@property (nonatomic, strong) NSString *value;
@property (nonatomic, assign) int age;
+ (void)doClassMethod;
@end
簡答解釋一下,我們定義了一個叫RuntimeObject的類志秃,類里面定義了一些東西:
- 實現(xiàn)了RuntimeProtocol和RuntimeBaseProtocol協(xié)議
- name怔球、kind兩個實例變量
- value、age兩個property
- doClassMethod函數(shù)
接下來就是我們今天真正的主題浮还,如何通過Runtime動態(tài)性的獲取到這些東西竟坛?
其一,我們先Get下Protocol:
unsigned int count;
__unsafe_unretained Protocol **protocols = class_copyProtocolList([RuntimeObject class], &count);
for (unsigned int i = 0; i < count; i++) {
const char *name = protocol_getName(protocols[i]);
printf("%s\n",name);
}
我們發(fā)現(xiàn)真的準確的輸出了呃钧舌!看:
RuntimeProtocol
RuntimeBaseProtocol
其二担汤,我們再來試試Get下Property:
unsigned int count;
objc_property_t *propertys = class_copyPropertyList([RuntimeObject class], &count);
for (unsigned int i = 0; i < count; i++) {
const char *name = property_getName(propertys[i]);
printf("%s\n",name);
}
輸出如下:
value
age
hash
superclass
description
debugDescription
提示:hash、superclass洼冻、description崭歧、debugDescription是從NSObject來的
我們再一次
接下來我們Get下Ivar、Method均告完美碘赖,哈哈哈<萑佟M夤埂!
分享
其實我們往上翻翻代碼不難看出播掷,Runtime給我們提供了一組函數(shù)审编,這些函數(shù)的形式主要為class_copyXXXX。這組函數(shù)就是用來獲取Ivar歧匈、Method垒酬、Property、Protocol的件炉,他們分別是:
- class_copyIvarList
- class_copyPropertyList
- class_copyProtocolList
- class_copyMethodList
能干嘛勘究?
如果你看到了這些,首先我先感謝你的支持斟冕!
?? 但是我們還是得要討論下能用來干嘛呢口糕?有什么鳥用?上面所有的代碼都是在我自己寫的class基礎之上測試的磕蛇,我都已經(jīng)有我寫的代碼景描,何必多此一舉去獲取Method、Property等等吶秀撇?
騷年超棺,不急!我們假設哈呵燕,如果某天你的主管要求你把他手機上所有安裝過的手機的Bundle ID提取出來棠绘,然后用Excel表統(tǒng)計給他,你怎么搞再扭?你是不是想拿榔頭砸他-去你Y的氧苍,什么JB玩意。但是騷年霍衫,我們不要忘記了候引,我們是coder啊敦跌!我們難道就沒有辦法嗎澄干?
直接上解決方法:
Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace");
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
NSObject *workspace = [LSApplicationWorkspace_class performSelector:@selector(defaultWorkspace)];
NSLog(@"Installed apps:%@",[workspace performSelector:@selector(allApplications)]);
#pragma clang diagnostic pop
你調(diào)試一下就知道了,這段代碼可以提取到所有已經(jīng)安裝過的App列表柠傍,包含Bundle ID喔麸俘!它就是通過Runtime去獲取workspace類,然后performSelector函數(shù)惧笛!
后記
好了从媚,Runtime先到這吧。其實它很簡單患整,也就是Apple提供了一堆函數(shù)給你拜效,然后讓你可以操作Ivar喷众、Protocol、Property紧憾、Method到千,也就僅此而已!
附帶:
- 一張截圖
就截這么多吧赴穗,剩下的都一樣
:
- 通過Class獲取鏈接庫名稱
Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace");
const char *name = class_getImageName(LSApplicationWorkspace_class);
printf("%s\n",name);
- 記錄Objective-C中所有消息(也是因為Runtime憔四,新版本SDK已無法直接調(diào)用那個函數(shù),但是可通過extern騙過編譯器0忝肌)
http://blog.csdn.net/justinjing0612/article/details/9053961
落幕
所有測試代碼如下簡書也不能上傳附件了赵,不上GitHub了,太簡單了
:
{ // Ivar
unsigned int count;
Ivar *ivars = class_copyIvarList([RuntimeObject class], &count);
for (unsigned int i = 0; i < count; i++) {
Ivar ivar = ivars[i];
const char *name = ivar_getName(ivar);
printf("%s\n",name);
}
}
printf("\n\n\n");
{ // property
unsigned int count;
objc_property_t *propertys = class_copyPropertyList([RuntimeObject class], &count);
for (unsigned int i = 0; i < count; i++) {
const char *name = property_getName(propertys[i]);
printf("%s\n",name);
}
}
printf("\n\n\n");
{ // protocol
unsigned int count;
__unsafe_unretained Protocol **protocols = class_copyProtocolList([RuntimeObject class], &count);
for (unsigned int i = 0; i < count; i++) {
const char *name = protocol_getName(protocols[i]);
printf("%s\n",name);
}
}
printf("\n\n\n");
{ // method
unsigned int count;
Method *methods = class_copyMethodList([RuntimeObject class], &count);
for (unsigned int i = 0; i < count; i++) {
SEL sel = method_getName(methods[i]);
printf("%s\n",sel_getName(sel));
}
}
printf("\n\n\n");
{ // Get dynamic framework name
Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace");
const char *name = class_getImageName(LSApplicationWorkspace_class);
printf("%s\n",name);
}
printf("\n\n\n");
{ // Installed apps
Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace");
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
NSObject *workspace = [LSApplicationWorkspace_class performSelector:@selector(defaultWorkspace)];
NSLog(@"Installed apps:%@",[workspace performSelector:@selector(allApplications)]);
#pragma clang diagnostic pop
}