国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

Objective-C 與 Runtime:為什么是這樣?

移動開發
筆者非常高興能為Objective-C寫寫自己的理解和總結,不僅僅因為是筆者是Objective-C多年的重度開發者,更是因為這是一門有獨特想法的,有創造性的,有優美語法的,有歷史地位的編程語言。如果說對本文有什么預期的話,筆者希望能把一些類似“為什么是這樣”的問題說清楚。

[[148060]]

筆者非常高興能為Objective-C寫寫自己的理解和總結,不僅僅因為是筆者是Objective-C多年的重度開發者,更是因為這是一門有獨特想法的,有創造性的,有優美語法的,有歷史地位的編程語言。如果說對本文有什么預期的話,筆者希望能把一些類似“為什么是這樣”的問題說清楚。

Objective-C發明于上世紀80年代,Objective-C的作者——Brad Cox和Tom Love,在接觸到SmallTalk語言之后,一方面受到SmallTalk的啟發,另一方面也是看好C語言有著巨大影響力和廣闊前景,因此選擇在C語言的基礎上引入SmallTalk語言面向對象和消息派發的概念。最初的版本以C語言的擴展的形式實現的,在C編譯器中編寫支持Objective-C的預處理模塊,預處理會先將Objective-C語法代碼轉化為C代碼,再繼續C代碼的編譯過程。1988年,以企業為目標客戶的NeXT公司購買Objective-C的使用授權,接著擴展著名開源編譯器GCC,使其支持Objective-C,并且開發了AppKit和FoundationKit等基礎庫,Objective-C成為了NeXTSTEP系統(工作站)上“標準”的應用程序開發語言。1996年,Apple公司收購了NeXT公司,NeXTSTEP/OPENSTEP系統成為Apple新一代操作系統OS X的研發基礎。 2005年,Apple引入了Chris Lattner以及他的LLVM技術團隊,Objective-C新特性和編譯優化***次得到高水平編譯器***優先級的支持,先從后端的代碼優化和生成開始,逐步擴展到前端的語法解析(Clang)。如今(2015),Objective-C已經擁有GCC之外更為適合更為優異的編譯器套裝選擇——LLVM編譯器,LLVM包括完整的前后端模塊,***版本6.1(2015)。

Objective-C是面向對象的,這是Objective-C最基本的的概念。關于面向對象,把一定的算法(函數)和數據(變量)因某種內在的聯系綁定在一起,形成最基本的程序結構單元,這些結構單元即是經常談及的對象,加上抽象二字,我們稱呼它為抽象對象,術語簡稱類;通過對變量的賦值(筆者認為不僅是變量,邏輯運算如閉包也是可以用于賦值)則會構成實體對象,術語簡稱對象(Objective-C一般也稱作實例)。對象和對象之間不是完全獨立的,通過巧妙的方式,它們之間能建立緊密的聯系,比如繼承、派生,對事物的抽象以及對代碼的復用有著微妙而重大的價值。Brad Cox和Tom Lov出版的***本正式Objective-C著作,書名即為《Object-Oriented Programming, An Evolutionary Approach》。那么,為什么要對象,為什么要面向對象?這是個好問題,觀察人類普遍的思維,我們理解這個世界使用最多的概念就是物體,我們擅長把感知到的一切抽象為一個個的物體,通過了解物體的構成,以及物體之間的作用關系,實現對這個世界的認知和作用的目的。這一直是非常奏效的!面向對象就是把人類的思維的天賦和積累的思想財富應用于編程,這樣,程序對于增強生產能力/提高生活品質的效率和能力方面會大大提高。

blob.png

/* 上圖為FoundationKit中支持的集合對象——(不可變)數組,繼承于根類NSObject,支持實現NSCopying在內的一系列協議(接口),count代表著有一個只讀變量,- (id)objectAtIndex:(NSUInteger)index等表示數組支持的可供使用的方法(函數) */

消息派發是Objective-C函數(Objective-C實際稱方法)調用的模式,前文亦有提及,概念繼承于Smalltalk。Objective-C的對象相互調用函數,被看做是向目標對象傳遞消息,消息的發送者稱作sender,消息的接收者稱作receiver,消息中間傳遞的字符串稱作selector(選擇子)。

blob.png

/* 上圖的代碼表示至少有兩個明顯receiver,self.view為其中一個消息接收者,傳遞的消息(字符串/選擇子)為 “setBackgroundColor:“,UIColor表示一個類,類也是可以作為消息的接收者,字符串/選擇子為 “yellowColor” */

消息的處理就是需要先確定實際執行的方法然后跳轉過去并執行,我們理解為這是對該消息的回應,編譯期間,單從一句”派發消息”的語法是無法確定實際執行的結果。只有在程序運行期間,實際執行的結果才能得到確定。這種在運行期間才確定實際執行的方法,Objective-C稱為動態綁定。消息派發這種工作機制明顯區別另一著名面向對象編程語言——C++。C++調用對象的函數,函數與對象之間的關系,在編譯期間就必須嚴格確定,如果car里面沒有定義函數名為fly的函數,編譯器不會通過,而是會報錯。Objective-C如果向car發送字符串為”fly”的selector,即使car沒有實現fly方法,編譯器依然能夠通過,但是運行期間則會因為獲取不到實際執行的方法而拋出異常。這也就是說,消息派發的設計使得編譯期間Objective-C非常包容對象所屬的類。如上述,相同對象有相同的定義,稱為類,類本身還可以看作對象——“類”對象,可以對“類”對象進行“類”的定義,比如比較運算,哈希,描述,類名等,總之一切皆為對象。C++里面我們可以基于稱之為模板的方式實現對“類”的自定義,Objective-C通過統一基類比如NSObject(不僅僅只有NSObject,還可以是各類根協議)方式對所有類新增定義。你可以向任何包括空指針nil在內的對象發你想發的消息。消息派發的機制使得在不重新編譯的情況下,在運行期間,干預或者說hook原來的target(方法、變量等)變得更易于實現,更有實際應用價值。這個是需要依賴于消息派發和動態綁定的實現機制——Runtime,但是Runtime并不僅僅為消息派發和動態綁定而work,它也是Objective-C面向對象、內存模型等特性的實現者。

在正式介紹Runtime之前,我們先繼續介紹Objective-C的另外一個重要概念,筆者要說是Objective-C內存管理模型,程序運行時,創建一個對象總是要占用內存的,而內存總大小總歸有限,所以當一個對象不再被需要時,應當及時回收它所占用的內存資源用于新的對象,Objective-C的內存管理原理,簡單說就是“引用計數”機制。如果有模塊需要引用一個對象,引用時會讓對象統計用的引用計數值加1,并記錄在對象的結構信息當中,當模塊不再需要該對象的時候則減1,而當該對象的引用計數值為0時,就可以認為該對象不再被需要,及時銷毀釋放內存(回收資源)。Objective-C對象的內存空間僅分配在“堆空間”(heap space)中,肯定是不會分配在“棧”(stack)上。我們知道,“棧”的占用和回收是有嚴格的數據操作規則,簡稱“先入后出”。函數執行時,傳入的變量(當然包括對象變量)會按照確定的序列規則自動壓入“棧”(占有內存資源),函數執行結束時,這些變量又會按照相反的序列規則自動彈出(釋放內存資源)。因此,我們可以看出,“棧”其實是無法實施“引用計數”機制的,Objective-C否定使用“棧”存儲對象的設想。在語法上,Objective-C也無法像C++那樣直接聲明并創建一個對象變量,更無法直接操作該對象,Objective-C都是需要以類似C語言申請堆內存塊的語法(alloc)那樣創建一個對象變量,并且必須通過對象指針作為訪問句柄,這跟C語言申請堆內存塊非常類似。Objective-C這一“任性”的設計,也使得對象嵌套(一個對象作為另一個對象的成員變量)時,對象基于引用計數機制,其成員變量也必須遞歸地遵循引用計數機制。因為成員變量實際都是一枚枚對象指針,很可能是與其它對象共享同一個對象(指針都指向同一塊內存),引用計數機制正是適合用于支持這種“共享”內存的管理。需要特別說明,如果可以像C++那樣創建一個對象變量做成員變量,那么該成員變量會被存儲在該對象所在的一塊連續內存塊,該對象銷毀時能夠自動把成員變量的占有的內存塊全部釋放收回,這與引用計數的機制并不太符合,所以,在Objective-C中對象變量不被支持也進一步得到理解。

blob.png

blob.png

/* 上圖的接口(方法)是Objective-C中內存管理相關的接口 (方法)*/

Runtime(component)譯名一般稱為運行期組件,一個純C語言寫成的基礎庫(lib),Objective-C編寫出來的程序必須得到Runtime的運行才能正常work,在Java、PHP或者Flash之類的編程語言當中,大家對于Runtime并不會太陌生,Objective-C的Runtime其實也是一回事。正是Runtime實現了Objective-C許多的特性,Objective-C面向對象、消息派發、動態綁定和內存管理都與Runtime的息息相關。那么,在Objective-C當中,對象、類、函數(方法)都是如何被構造并發揮作用的?前文提及,面向對象中的類,被看作抽象了的對象,Runtime也是秉持這一理念。Runtime是純C寫成,用struct結構體來描述對象(實體對象)和類(抽象對象)。

blob.png

blob.png

對象的struct比較簡單,用*id作為結構體objc_object的指針別名,***struct成員isa是Class類型的指針變量,正是該變量確定了對象所屬的類。Class類型也是struct,是結構體objc_class的指針別名,用于描述類構成的struct,***成員isa也是Class類型的指針變量(由兩個結構體的***成員均為Class類型的指針變量的設計使得我們能進一步體會到Runtime中,類的確有著和對象相同的看待),類的isa會指向稱之為metaclass(元類)的struct,metaclass抽象了類的特性,metaclass的***成員自然也是isa的Class類型的指針變量,不同的是元類的isa最終指向的是它自身,由此我們可以觀察到,類struct是一種遞歸嵌套的設計,它正體現了面向對象***抽象的理念,最終實現上指向自己則是實際工程處理的需要。一般我們還認為objc_class這個struct存放類的metadata(元數據),例如類的實例方法、類的實例變量以及類的超類指針等。

blob.png

Runtime還允許我們通過標準的接口(C函數)對所有Objective-C類的變量、方法、屬性以及協議等等作查詢和動態擴展,從而達到我們豐富項目中語言和類庫特性的目標。

blob.png

/* 上圖的通過標準的Runtime API(C函數)打印UIKit中UIView的所有變量、屬性以及方法*/

Runtime的另外一個重要的特性實現即為消息派發,objc_msgSend是消息派發最核心最基礎的入口函數,除此之外還有objc_msgsend_stret,objc_msgSend_fpret,objc_msgSendSuper等函數,然而它們的重要性和作用遠不及objc_msgSend。objc_msgSend函數會依據receiver和selector的來調用適當的方法。為了完成此操作,該函數需要在recevier所屬的類中搜尋其“方法列表”,如果能找到與selector字符串名稱相符的方法,就跳轉至該方法。若是找不到,那就沿著繼承體系繼續向上查找,等找到合適的方法之后再跳轉。如果最終還是找不到相符的方法,那就執行“消息轉發”操作。由此,我們可以看到,調用一個方法似乎需要相當的步驟。每一個步驟都是開銷,是否會導致Objective-C有性能問題?所幸obj_msgSend會將匹配到得結果緩存在“快速映射表”(fast map),每個類都有這樣一塊緩存,若是后面還需要向該類發送和相同的selector消息,執行起來將會快許多。當然,這種“快速執行路徑”(fast path)還是不如“靜態綁定函數調用”(statically bound function call)那樣快,不過通過匯編等優化技術,映射表的查詢開銷已非常小,可以說,即使相比較C++的靜態綁定,Objective-C的消息派發機制已經不是性能瓶頸所在。如果說以上的消息派發機制就是Objective-C動態綁定的全部內容,其實并不完全。當對象查詢不到相關的方法,消息無法正確回應時,還會啟動“消息轉發”機制。是的,在支持“動態增加和替換”的方法列表之外,我們還能夠提供其它的正常響應方式。消息轉發還分為幾個階段,***,先詢問receiver或者說是它所屬的類,看其是否能動態添加方法,以處理當前這個“未知選擇子”(unkonwn selector),這叫做“動態方法解析”(dynamic method resolution),Runtime會通過回調一個類方法來尋求動態添加方法的支持。如果Runtime完成動態添加方法的詢問之后,receiver仍然無法正常響應,則Runtime會繼續向receiver詢問是否有其它對象即其它receiver能處理這條消息,若返回能夠處理的對象,Runtime會把消息轉給返回的對象,消息轉發流程也就結束。若無對象返回,Runtime會把消息有關的全部細節都封裝到NSInvocation對象中,再給receiver***一次機會,令其設法解決當前還未處理的這條消息。消息轉發的流程可以歸納到以下圖表:

blob.png

由圖表可以看出,receiver在每一步中均有機會處理消息,步驟越往后,處理消息累計開銷就越大。所以,***能在***步就處理完,這樣的話,Runtime還可以把方法進行緩存,在一步到位的同時進一步降低***查詢這樣的開銷。需要注意的是在***一個階段,需要由兩個接口一起完成,先要通過- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector接口返回格式化的方法對象,下一個接口- (void)forwardInvocation:(NSInvocation *)anInvocation中傳入參數NSInvocation對象對此方法對象是有依賴,***步的NSMethodSignature對象返回nil,則消息轉發流程即告結束。

***利用消息轉發機制,我們實現一個讓NSString類支持NSArray實例方法的例子,這對于降低程序的Crash率很有幫助:

我們先實現一個方法替換的接口swizzle method,幫助我們在不需要繼承的情況下,實現對父類方法的代碼注入

blob.png

通過swizzle方式(class_addMethod、class_replaceMethod、method_exchangeImplementations),在NSString類的resolveInstanceMethod:中,動態方法解析的方式注入3個NSArray的實例方法:

blob.png

測試用例:

blob.png

測試結果:

blob.png

結尾,筆者用了很大的篇幅和代碼片段嘗試去解釋Objective-C最基本的一些概念,包括面向對象、消息派發、內存管理等等,并且也討論了這些概念在Rumtime上的實現,這當中還不包括屬性、分類、類族、協議等Objective-C中同樣重要的feature,也沒有深入闡述其中的一些編碼細節(有關編碼,通過搜索引擎,總能獲取許多令人滿意的答案)。筆者更多地是希望在有限的篇幅中幫助讀者快速理解Objective-C,理解它為什么是這樣而不是那樣,并且對于想進一步學習和使用Objective-C的開發者和工程師能有所幫助。

參考鏈接(部分):

責任編輯:倪明 來源: springox的博客
相關推薦

2012-03-07 13:43:59

Objective-C

2014-04-01 10:50:42

iOS開發runtimeObjective-C

2014-07-14 09:58:18

Objective-CiOS學習

2015-07-08 10:51:27

Objective-CRuntime

2011-08-04 13:38:01

Objective-C C++

2011-08-10 18:07:29

Objective-C反射

2013-06-20 10:40:32

Objective-C實現截圖

2013-03-27 12:54:00

iOS開發Objective-C

2011-05-11 11:20:26

Objective-C

2011-05-11 15:58:34

Objective-C

2011-08-16 13:43:40

Objective-C文件cocoa

2014-09-24 11:15:05

Objective-CSwift

2017-02-10 09:55:53

SwiftObjective-C

2011-08-17 11:15:22

Objective-C語法

2011-08-04 11:15:46

Objective-C 構造函數 構造方法

2011-08-04 14:58:37

Objective-C Cocoa NSString

2011-08-02 13:16:36

Objective-C 語法 函數

2011-05-11 15:45:50

內存管理Objective-C

2011-05-11 13:54:08

Objective-C

2013-08-21 14:57:42

objective-c問題
點贊
收藏

51CTO技術棧公眾號

日韩 欧美 视频| 福利视频在线看| 一本色道久久综合亚洲精品不| 久久久精品国产网站| mm视频在线视频| 欧美精品乱码久久久久久| 亚洲国产精华液| 日韩理论片在线| 男女午夜刺激视频| 国产精品毛片大码女人| 久久精品.com| 福利电影一区二区| 免费看欧美一级片| 成人免费视频国产在线观看| 中文字幕中文字幕在线中心一区| 丝袜美腿亚洲一区| 日韩理论片在线观看| 蜜臀久久久99精品久久久久久| 欧美一区二区视频17c| 模特精品在线| 亚洲欧美久久234| 久久精品国产在热久久| 午夜在线视频免费观看| 激情国产一区二区| 日本大胆人体视频| 99精品国产热久久91蜜凸| 91精品91久久久中77777老牛| 99久久国产综合精品色伊| 日本精品久久久久中文字幕| 久久精品亚洲精品国产欧美 | 国产免费内射又粗又爽密桃视频| 石原莉奈在线亚洲二区| 色综合666| 丁香五精品蜜臀久久久久99网站| 日韩欧美一级在线| 日本一区二区视频在线| 欧美性猛交p30| 欧美精品在欧美一区二区少妇| av免费在线观看网址| 亚洲护士老师的毛茸茸最新章节| 台湾佬成人网| 欧美国产日韩精品| 国产精品久久久久久久| 日本视频一区二区不卡| 国产精品亚洲成人| 激情四房婷婷| 日韩欧美精品三级| 9999在线精品视频| 欧美一级大胆视频| 欧美大片aaaa| 日韩国产欧美精品| 久久久噜噜噜久噜久久综合| 视频黄页在线| 亚洲二区在线播放视频| 99精品中文字幕在线不卡 | 新呦u视频一区二区| 97aⅴ精品视频一二三区| 免费福利片在线观看| 欧美视频三区在线播放| 涩涩视频在线| 日韩女优人人人人射在线视频| 伊人激情综合| 国产在线青青草| 色天天综合久久久久综合片| 亚洲美女久久精品| 国产精品成人播放| 强制捆绑调教一区二区| 99.玖玖.com| 精品国产不卡一区二区三区| 加勒比色老久久爱综合网| 欧美精品一区三区在线观看| 国产欧美日韩在线看| av男人的天堂在线| 色综合导航网站| 国产日韩欧美| 亚洲无吗一区二区三区| 日韩一区二区精品在线观看| 成人在线视频www| 精品国产一二| 国产精品美女久久久久久| 爱看av在线入口| 国产精品一区二区3区| 国产91精品入口| a黄色在线观看| 国内精品久久久久伊人av| 蜜桃视频第一区免费观看| 亚州黄色一级| 日韩中文字幕免费看| 国产麻豆综合| 亚洲精品视频在线免费| 欧美成人免费观看| 国产一区高清在线| 欧美激情黑人| 成人免费网站在线| 国产精品婷婷午夜在线观看| 神马久久资源| 亚洲欧美精品| 91麻豆精品国产综合久久久久久| 日韩在线视屏| 上原亚衣加勒比在线播放| 中文字幕日韩av综合精品| 香蕉久久a毛片| 亚洲成av人影片在线观看| 亚洲91av视频| 成人三级在线视频| av福利导福航大全在线| 黑人中文字幕一区二区三区| 婷婷一区二区三区| 美女亚洲一区| 99青春婷婷视频| 欧美xxxx做受欧美| av不卡在线播放| 国产成人精品一区二三区在线观看 | 伪装者在线观看完整版免费| 国内免费精品永久在线视频| 黑人巨大精品欧美一区| 成人短视频在线| 亚洲自拍偷拍福利| 亚洲午夜精品在线| 国产影视一区| 原千岁中文字幕| 国产91色在线|| 亚洲免费看黄网站| 久久久久影视| 色视频www在线播放国产人成| 欧美极品欧美精品欧美视频| 99精品视频在线观看| 日本欧美不卡| 中文字幕制服丝袜在线| 欧美本精品男人aⅴ天堂| 国产日韩一区二区三区在线播放 | 国产精品国产三级国产普通话蜜臀 | 成人国产免费电影| 欧美日韩一区二区三区在线观看免 | 国产日韩三级在线| 在线日韩三级| 国产精品wwwww| 韩国三级电影久久久久久| 国产精品免费视频观看| 日韩人体视频| 久草电影在线| 99re视频在线| 欧美va亚洲va香蕉在线| 国产麻豆精品一区二区| 成人短视频软件网站大全app| 999香蕉视频| 国产99久久精品一区二区| 开心激情综合| 国产视频第一页在线观看| 男人天堂新网址| 国产极品jizzhd欧美| 日韩在线观看免费全集电视剧网站| 欧美日韩亚洲天堂| 精品乱人伦小说| 亚洲美女自拍视频| 国产mv久久久| 免费日韩av电影| 黄色www在线观看| 亚洲欧美久久久久一区二区三区| 欧美这里只有精品| 另类av导航| 久久精品国产第一区二区三区最新章节 | 一本久道久久综合婷婷鲸鱼| av丝袜在线| 欧美亚洲精品一区二区| 国产香蕉精品视频一区二区三区| 波多野结衣中文字幕一区 | 国产精品一区二区99| 在线观看视频污| 一级黄色特级片| 国产精品入口免费软件| 麻豆精品传媒视频| 久久精品视频一| 亚洲第一综合色| 亚洲欧洲午夜| 成人影院在线播放| 成全视频在线播放大地| 成人综合av| 黄色一级免费大片| 亚洲网站情趣视频| 成人免费在线小视频| 国产精品成av人在线视午夜片| 国产精品久久久久久久久免费相片| 在线成人激情| 成年人在线免费观看| 一道本在线免费视频| 国产一区二区三区四区三区四| 午夜羞羞小视频在线观看| 自拍视频在线| 黄色一级大片免费| 91麻豆精品国产自产在线观看一区 | 国产在线观看www| 天堂中文视频在线| 国产精品免费一区二区三区在线观看| 亚洲人成伊人成综合网久久久| 亚洲一级二级三级在线免费观看| 久久国产免费看| 免费av手机在线观看| 91精品视频观看| 神马国产精品影院av|