1.程序是怎樣運(yùn)行起來的布朦?(以C語言以及VC運(yùn)行環(huán)境為例)
- 編輯
- (把程序代碼輸入煞烫,交給計(jì)算機(jī))。
- 編譯(成目標(biāo)程序文件.obj)
- 編譯就是把高級(jí)語言變成計(jì)算機(jī)可以識(shí)別的2進(jìn)制語言猴鲫,計(jì)算機(jī)只認(rèn)識(shí)1和0对人,編譯程序把人們熟悉的語言換成2進(jìn)制的。
- 編譯程序把一個(gè)源程序翻譯成目標(biāo)程序的工作過程分為五個(gè)階段:詞法分析拂共;語法分析牺弄;語義檢查和中間代碼生成;代碼優(yōu)化宜狐;目標(biāo)代碼生成势告。主要是進(jìn)行詞法分析和語法分析,又稱為源程序分析抚恒,分析過程中發(fā)現(xiàn)有語法錯(cuò)誤咱台,給出提示信息。
- 鏈接(成可執(zhí)行程序文件.exe)俭驮。
- 鏈接是將編譯產(chǎn)生的.obj文件和系統(tǒng)庫連接裝配成一個(gè)可以執(zhí)行的程序回溺。
- 為何要將源程序翻譯成可執(zhí)行文件的過程分為編譯和鏈接兩個(gè)獨(dú)立的步驟,不是多此一舉嗎混萝?之所以這樣做遗遵,主要是因?yàn)椋涸谝粋€(gè)較大的復(fù)雜項(xiàng)目中,有很多人共同完成一個(gè)項(xiàng)目(每個(gè)人可能承擔(dān)其中一部分模塊)逸嘀,其中有的模塊可能是用匯編語言寫的车要,有的模塊可能是用VC寫的,有的模塊可能是用VB寫的崭倘,有的模塊可能是購買(不是源程序模塊而是目標(biāo)代碼)或已有的標(biāo)準(zhǔn)庫模塊屯蹦,因此,各類源程序都需要先各自編譯成目標(biāo)程序文件(2進(jìn)行機(jī)器指令代碼)绳姨,再通過鏈接程序?qū)⑦@些目標(biāo)程序文件連接裝配成可執(zhí)行文件登澜。
- 運(yùn)行(可執(zhí)行程序文件)。
- 上述四個(gè)步驟中飘庄,其中第一步的編輯工作是最繁雜而又必須細(xì)致地由人工在計(jì)算機(jī)上來完成脑蠕,其余幾個(gè)步驟則相對(duì)簡(jiǎn)單,基本上由計(jì)算機(jī)來自動(dòng)完成。
2. 動(dòng)態(tài)語言和靜態(tài)語言的在程序不同階段是怎樣處理的谴仙?
編程語言有靜態(tài)和動(dòng)態(tài)之分迂求。
靜態(tài)語言就是,在程序運(yùn)行前決定了所有的類型判斷晃跺,類的所有成員揩局,方法在編譯階段就確定好了內(nèi)存地址,也就意味著所有的類對(duì)象只能訪問屬于自己的成員變量和方法掀虎,否則編譯器直接報(bào)錯(cuò)凌盯。如:java,C++,C
動(dòng)態(tài)語言,類型的判斷烹玉、類的成員變量驰怎、方法的內(nèi)存地址都是在程序的運(yùn)行階段才最終確定,并且還能動(dòng)態(tài)的添加成員變量和方法二打。也就意味著你調(diào)用一個(gè)不存在的方法時(shí)县忌,編譯也能通過,甚至一個(gè)對(duì)象它是什么類型并不是表面我們所看到的那樣,只有運(yùn)行之后才能決定其真正的類型继效。相比于靜態(tài)語言症杏,動(dòng)態(tài)語言具有較高的靈活性和可訂閱性。而OC瑞信,正是一門動(dòng)態(tài)語言鸳慈。
3. runtime
運(yùn)行時(shí):
就是程序在運(yùn)行時(shí)做的一些事。
runtime :
runtime 是OC底層的一套C語言的API喧伞,它是一個(gè)C和匯編寫的動(dòng)態(tài)庫,將OC和C緊密關(guān)聯(lián)绩郎。編譯器最終都會(huì)將OC代碼轉(zhuǎn)化為運(yùn)行時(shí)代碼潘鲫。
runtime這個(gè)系統(tǒng)主要做兩件事 :
1、封裝C語言的結(jié)構(gòu)體和函數(shù)肋杖,讓開發(fā)者在運(yùn)行時(shí)創(chuàng)建溉仑、檢查或者修改類、對(duì)象和方法等等状植。
2浊竟、傳遞消息,找出方法的最終執(zhí)行代碼津畸。
在OC中振定,如果想要某個(gè)對(duì)象傳遞消息,那么就會(huì)使用動(dòng)態(tài)綁定機(jī)制來決定需要調(diào)用的方法肉拓。在底層后频,所有的方法都是普通的C語言函數(shù),然而對(duì)象收到消息之后,究竟該調(diào)用哪個(gè)方法則完全取決于運(yùn)行期決定卑惜,甚至在運(yùn)行時(shí)改變膏执,這些特性使得OC成為一門真正的動(dòng)態(tài)的語言。
OC中的重要工作都由“運(yùn)行期組件”而不是編譯器來完成露久,使用OC面向?qū)ο筇匦运璧娜繑?shù)據(jù)結(jié)構(gòu)及函數(shù)都在運(yùn)行期組件里面更米。例如:運(yùn)行期組件中含有全部的內(nèi)存管理的方法。
在提高性能的方面:只需要更新運(yùn)行期組件毫痕,即可提升應(yīng)用程序的性能征峦。而在那種許多的工作都在編譯期完成的語言,若想要獲得類似的性能提升镇草,則要重新編譯應(yīng)用程序代碼眶痰。
4.要了解運(yùn)行時(shí),我們得先了解OC的消息機(jī)制
4.1 消息發(fā)送(Messaging):是 Runtime 通過 selector(選擇子) 快速查找 IMP 的過程梯啤,有了函數(shù)指針就可以執(zhí)行對(duì)應(yīng)的方法實(shí)現(xiàn)竖伯;
id returnValue = [someObject messageName: parameter];
調(diào)用的runtime函數(shù):
原型:void objc_msgSend(id self, SEL cmd, . . . )
id returnValue = objc_msgSend(someObject,@ selector(messageName:), parameter);
解釋:objc_msgSend函數(shù)會(huì)根據(jù)接受者和選擇子的類型來調(diào)用適當(dāng)?shù)姆椒ā榱私邮胀瓿蛇@個(gè)操作因宇,該方法需要在接收者(someObject)所屬的類中搜尋其“方法列表”七婴,如果能找到就跳轉(zhuǎn)到實(shí)現(xiàn)代碼,若不能察滑,就沿著繼承體系向上查找打厘,找到后在跳轉(zhuǎn),如果最終都找不到贺辰,就執(zhí)行“消息轉(zhuǎn)發(fā)”户盯。
4.2 消息轉(zhuǎn)發(fā)(Message Forwarding):是在查找 IMP 失敗后執(zhí)行一系列轉(zhuǎn)發(fā)流程的慢速通道,如果不作轉(zhuǎn)發(fā)處理饲化,則會(huì)打日志和拋出異常莽鸭。
當(dāng)對(duì)象接受到無法解讀的消息的時(shí)候,就會(huì)啟動(dòng)“消息轉(zhuǎn)發(fā)”機(jī)制吃靠,程序員可以經(jīng)由此過程告訴對(duì)象該如何處理這個(gè)消息硫眨。
消息轉(zhuǎn)發(fā)分為2大階段:
- 第一階段先征詢接受者,所屬的類巢块,看是否能動(dòng)態(tài)的添加方法礁阁,以處理當(dāng)前這個(gè)“未知的選擇子”,這叫做動(dòng)態(tài)方法解析族奢。
-
第二階段涉及“完整的消息轉(zhuǎn)發(fā)機(jī)制”姥闭,當(dāng)運(yùn)行期系統(tǒng)已經(jīng)將第一階段執(zhí)行完了,那么系統(tǒng)會(huì)請(qǐng)求接受者以其他的手段來處理與消息相關(guān)的方法調(diào)用越走。1.請(qǐng)接收者看看有沒有備援的接受者可以處理這個(gè)消息泣栈,若有,消息轉(zhuǎn)發(fā)結(jié)束,若還是沒有就啟動(dòng)完整的消息轉(zhuǎn)發(fā)機(jī)制南片,運(yùn)行期系統(tǒng)會(huì)把與消息有關(guān)的全部信息封裝到NSInvocation對(duì)象中去掺涛,在給接受者最后一次機(jī)會(huì),令其設(shè)法解決當(dāng)前未處理的這條信息疼进。
屏幕快照 2017-12-12 15.39.00.png
5.runtime的主要應(yīng)用
(1)替換系統(tǒng)方法
#import "UIImage+ImageLoad.h"
#import <objc/runtime.h>
@implementation UIImage (ImageLoad)
//自定義方法中最后一定要再調(diào)用一下系統(tǒng)的方法薪缆,讓其有加載圖片的功能,但是由于方法交換伞广,系統(tǒng)的方法名已經(jīng)變成了我們自定義的方法名,這就實(shí)現(xiàn)了系統(tǒng)方法的攔截拣帽!
+(UIImage *)xh_imageNamed:(NSString *)name {
double version = [[UIDevice currentDevice].systemVersion doubleValue];
if (version >= 7.0) {
name = [name stringByAppendingString:@"_ios7"];
}
return [UIImage xh_imageNamed:name];
}
//分類中重寫UIImage的load方法,實(shí)現(xiàn)方法的交換嚼锄,
+(void)load {
//獲取2個(gè)類的方法
Method m1 = class_getClassMethod([UIImage class], @selector(imageNamed:));
Method m2 = class_getClassMethod([UIImage class], @selector(xh_imageNamed:));
//交換
method_exchangeImplementations(m1, m2);
}
@end
(2)實(shí)現(xiàn)分類關(guān)聯(lián)屬性
#import "UIButton+BtnImageView.h"
#import <objc/runtime.h>
@implementation UIButton (BtnImageView)
-(UIImageView *)btnImageView
{
// return objc_getAssociatedObject(self, @selector(isClicked));
return objc_getAssociatedObject(self, &kbtnImageView);
}
//set
static char kbtnImageView;
-(void)setBtnImageView:(UIImageView *)btnImageView
{
//如果是指針類型
return objc_setAssociatedObject(self, &kbtnImageView, btnImageView, OBJC_ASSOCIATION_RETAIN);
//1 源對(duì)象self
//2 關(guān)鍵字 唯一靜態(tài)變量key isClicked
//3 關(guān)聯(lián)的對(duì)象
//4 關(guān)鍵策略 OBJC_ASSOCIATION_RETAIN_NONATOMIC
//objc_setAssociatedObject(self, @selector(isClicked), @(isClicked), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
(3)字典轉(zhuǎn)model
(4)歸檔
(5) 萬能控制器跳轉(zhuǎn)
- (void)push:(NSDictionary *)params
{
// 類名
NSString *class =[NSString stringWithFormat:@"%@", params[@"class"]];
const char *className = [class cStringUsingEncoding:NSASCIIStringEncoding];
// 從一個(gè)字串返回一個(gè)類
Class newClass = objc_getClass(className);
if (!newClass)
{
// 創(chuàng)建一個(gè)類
Class superClass = [NSObject class];
newClass = objc_allocateClassPair(superClass, className, 0);
// 注冊(cè)你創(chuàng)建的這個(gè)類
objc_registerClassPair(newClass);
}
// 創(chuàng)建對(duì)象
id instance = [[newClass alloc] init];
// 對(duì)該對(duì)象賦值屬性
NSDictionary * propertys = params[@"property"];
[propertys enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
// 檢測(cè)這個(gè)對(duì)象是否存在該屬性
if ([self checkIsExistPropertyWithInstance:instance verifyPropertyName:key]) {
// 利用kvc賦值
[instance setValue:obj forKey:key];
}
}];
// 獲取導(dǎo)航控制器
UITabBarController *tabVC = (UITabBarController *)self.window.rootViewController;
UINavigationController *pushClassStance = (UINavigationController *)tabVC.viewControllers[tabVC.selectedIndex];
// 跳轉(zhuǎn)到對(duì)應(yīng)的控制器
[pushClassStance pushViewController:instance animated:YES];
}
//檢測(cè)是否存在這個(gè)屬性
- (BOOL)checkIsExistPropertyWithInstance:(id)instance verifyPropertyName:(NSString *)verifyPropertyName
{
unsigned int outCount, i;
// 獲取對(duì)象里的屬性列表
objc_property_t * properties = class_copyPropertyList([instance
class], &outCount);
for (i = 0; i < outCount; i++) {
objc_property_t property =properties[i];
// 屬性名轉(zhuǎn)成字符串
NSString *propertyName = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
// 判斷該屬性是否存在
if ([propertyName isEqualToString:verifyPropertyName]) {
free(properties);
return YES;
}
}
free(properties);
return NO;
}
(7)插件開發(fā)