自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Ruby開(kāi)發(fā)者如何享受Objective-C

移動(dòng)開(kāi)發(fā) iOS
Ruby 和 Objective-C 這兩種語(yǔ)言看上去好像天南地北:一種是動(dòng)態(tài)語(yǔ)言,另一種則是靜態(tài)語(yǔ)言;一種是解釋型語(yǔ)言,另一種是編譯型語(yǔ)言;一種有簡(jiǎn)潔的語(yǔ)法,另一種則是有點(diǎn)冗長(zhǎng)的語(yǔ)法。從優(yōu)雅的角度來(lái)看,Ruby似乎更能給我們一種自由的編程體驗(yàn),所以很多人都放棄了Objective-C。

Ruby 和 Objective-C 這兩種語(yǔ)言看上去好像天南地北:一種是動(dòng)態(tài)語(yǔ)言,另一種則是靜態(tài)語(yǔ)言;一種是解釋型語(yǔ)言,另一種是編譯型語(yǔ)言;一種有簡(jiǎn)潔的語(yǔ)法,另一種則是有點(diǎn)冗長(zhǎng)的語(yǔ)法。從優(yōu)雅的角度來(lái)看,Ruby似乎更能給我們一種自由的編程體驗(yàn),所以很多人都放棄了Objective-C。

[[110989]]

但這是一個(gè)不幸的笑話。Objective-C其實(shí)并不像別人認(rèn)為的那樣是件緊身衣,它和Ruby一樣都受Smalltalk影響,它擁有很多 Ruby開(kāi)發(fā)者都喜愛(ài)的語(yǔ)言功能–動(dòng)態(tài)方法查找、鴨子類型、開(kāi)放的類和通常情況下高度可變的runtime等這些功能在Objective-C中同樣存在,即使那些不出名的技術(shù)也是一樣。Objective-C的這些功能都要?dú)w功于它的IDE和編譯器,但也是因?yàn)樗鼈儾攀鼓悴荒茏杂傻鼐帉?xiě)代碼。

但是等一下,怎么能說(shuō)Objective-C是動(dòng)態(tài)語(yǔ)言呢?難道它不是建立在C語(yǔ)言的基礎(chǔ)上?

你可以在Objective-C代碼中包含任何C或C++的代碼,但這不意味著Objective-C僅限于C或C++代碼。Objective- C中所有有意思的類操作和對(duì)象內(nèi)省都是來(lái)自于一個(gè)叫Objective-C Runtime的東西。這個(gè)Objective-C Runtime可以和Ruby解釋器相媲美。它包含了強(qiáng)大的元編程里所需要的所有重要特性。

其實(shí)C語(yǔ)言和Ruby一樣是支持這些特性的,用property_getAttributesmethod_getImplementation方法就能將selector對(duì)應(yīng)到具體實(shí)現(xiàn)(一個(gè)selector處理一個(gè)方法),并判斷這個(gè)對(duì)象能否對(duì)這個(gè)selector做出反應(yīng),再遍歷子類樹(shù)。在Objective-C的眾多方法中,最重要的就是objc_msgSend方法,是它推動(dòng)了應(yīng)用中的每次消息發(fā)送。

消息的傳遞

Smalltalk才是實(shí)至名歸的***種面向?qū)ο笳Z(yǔ)言,它用“從一個(gè)對(duì)象發(fā)送信息給另一個(gè)對(duì)象”的新概念取代了“調(diào)用函數(shù)”的舊概念,對(duì)后面的語(yǔ)言發(fā)展產(chǎn)生了深遠(yuǎn)的影響。

你可以在Ruby中通過(guò)這樣寫(xiě)來(lái)實(shí)現(xiàn)消息的發(fā)送:

  1. receiver.the_message argument 

Objective-C的實(shí)現(xiàn)方式和Ruby的差不多:

  1. [receiver theMessage:argument]; 

這些消息實(shí)現(xiàn)了鴨子類型的方式,也就是說(shuō)關(guān)注的不是這個(gè)對(duì)象的類型或類本身,而是這個(gè)對(duì)象能否對(duì)一個(gè)消息做出反應(yīng)。

發(fā)送消息真的是非常棒的事,但是只有當(dāng)消息在傳送數(shù)據(jù)時(shí),它的價(jià)值才會(huì)被發(fā)揮地更大:

  1. receiver.send(:the_message, argument) 

  1. [receiver performSelector:@selector(theMessage:) 
  2. withObject:argument]; 

正如Ruby中方法需要symbol支持一樣,Objective-C中selector也需要string來(lái)支持。(在Objective-C中沒(méi)有symbol。)這樣就可以讓你通過(guò)動(dòng)態(tài)的方式使用一個(gè)方法。你甚至可以通過(guò)NSSelectorFromString方法來(lái)使用string創(chuàng)建一個(gè)selector,并在一個(gè)對(duì)象里執(zhí)行它。同樣的,我們可以在Ruby中也可以創(chuàng)建一個(gè)string或symbol,并把傳給Object#send方法。

當(dāng)然,無(wú)論是哪種語(yǔ)言,一旦你將一個(gè)消息發(fā)送給不能處理該消息的對(duì)象,那么默認(rèn)情況下就會(huì)拋出一個(gè)異常,還會(huì)導(dǎo)致應(yīng)用的崩潰。

當(dāng)你想在調(diào)用一個(gè)方法前判斷一下這個(gè)對(duì)象是否能夠執(zhí)行這個(gè)方法,你可以用Ruby中的respond_to?方法來(lái)檢查:

  1. if receiver.respond_to? :the_message 
  2.   receiver.the_message argument 
  3. end 

Objective-C中也有差不多的方法:

  1. if ([receiver respondsToSelector:@selector(theMessage:)]) { 
  2.     [receiver theMessage:someThing]; 

變得越來(lái)越動(dòng)態(tài)

如果你想在一個(gè)不能修改的類(像系統(tǒng)類)中添加你想要的方法,那么Objective-C里的category一定不會(huì)讓你失望 — 很像Ruby中的“開(kāi)放類”。

舉個(gè)例子,如果你想將Rails中的to_sentence方法添加到NSArray類中,我們只需要對(duì)NSArray這個(gè)類進(jìn)行擴(kuò)展就好了:

  1. @interface NSArray (ToSentence) 
  2. - (NSString *)toSentence; 
  3. @end 
  4.  
  5. @implementation NSArray (ToSentence) 
  6. - (NSString *)toSentence { 
  7.     if (self.count == 0) return @""
  8.     if (self.count == 1) return [self lastObject]; 
  9.     NSArray *allButLastObject = [self subarrayWithRange:NSMakeRange(0, self.count-1)]; 
  10.     NSString *result = [allButLastObject componentsJoinedByString:@", "]; 
  11.     BOOL showComma = self.count > 2; 
  12.     result = [result stringByAppendingFormat:@"%@ and ", showComma ? @"," : @""]; 
  13.     result = [result stringByAppendingString:[self lastObject]]; 
  14.     return result; 
  15. @end 

Category是在編譯的時(shí)候?qū)⒎椒ㄌ砑拥匠绦蛑?— 讓我們?cè)趓untime中動(dòng)態(tài)捕捉它們?cè)趺礃樱?/p>

有些消息可以嵌套數(shù)據(jù),就像Rails的dynamic finders。Ruby通過(guò)對(duì)method_missing 和 respond_to這兩個(gè)方法的重寫(xiě),先匹配模式,再將新方法的定義添加到這個(gè)對(duì)象中。

Objective-C中的流程是差不多,但我們不是重寫(xiě)doesNotRecognizeSelector:方法(相當(dāng)于Ruby中的method_missing方法),而是在resolveClassMethod:方法中捕捉Category添加的方法。假設(shè)我們有一個(gè)叫+findWhere:equals:的類方法,它可以得到property的名稱和值,那么通過(guò)正則表達(dá)式就可以很容易實(shí)現(xiàn)找到property的名字,并通過(guò)block來(lái)注冊(cè)這個(gè)selector。

  1. + (BOOL)resolveClassMethod:(SEL)sel { 
  2.     NSString *selectorName = NSStringFromSelector(sel); 
  3.   
  4.     NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^findWhere(\\w+)Equals:$" options:0 error:nil]; 
  5.     NSTextCheckingResult *result = [regex firstMatchInString:selectorName options:0 range:NSMakeRange(0, selectorName.length)]; 
  6.     if (result) { 
  7.         NSRange propertyNameRange = [result rangeAtIndex:1]; 
  8.         NSString *propertyName = [selectorName substringWithRange:propertyNameRange]; 
  9.   
  10.         IMP implementation  = imp_implementationWithBlock((id) ^(id self, id arg1) { 
  11.             return [self findWhere:propertyName equals:arg1]; 
  12.         }); 
  13.   
  14.         Class metaClass = object_getClass(self); 
  15.   
  16.         class_addMethod(metaClass, sel, implementation, "@@:@@"); 
  17.         return YES; 
  18.     } 
  19.   
  20.     return [super resolveClassMethod:sel]; 

這個(gè)方法的優(yōu)點(diǎn)就是我們不需要去重寫(xiě)respondsToSelector:,因?yàn)槊總€(gè)在類中注冊(cè)過(guò)的selector都會(huì)去調(diào)用這個(gè)方法?,F(xiàn)在讓我們調(diào)用[RGSong findWhereTitleEquals:@“Mercy”]。當(dāng)findWhereTitleEquals:***次被調(diào)用的時(shí)候,runtime并不知道這個(gè)方法,所以它會(huì)調(diào)用resolveClassMethod:,這時(shí)我們就將findWhereTitleEquals:這個(gè)方法動(dòng)態(tài)添加進(jìn)去,當(dāng)?shù)诙握{(diào)用findWhereTitleEquals:的時(shí)候,因?yàn)樗呀?jīng)被添加過(guò)了,所以就不會(huì)再調(diào)用resolveClassMethod:了。

這里還有一些別的方法來(lái)實(shí)現(xiàn)捕捉動(dòng)態(tài)方法。你可以通過(guò)重寫(xiě)resolveClassMethod: 和 resolveInstanceMethod:方法(就像上面的一樣),可以將消息傳遞給不同的對(duì)象或全權(quán)接管這個(gè)“調(diào)用”,并在消息傳遞之前,做你想這個(gè)消息要完成的任何事。這些方法都會(huì)導(dǎo)致運(yùn)行成本的增加,特別在-forwardInvocation:中會(huì)達(dá)到頂峰,在這種情況下我們必須要實(shí)例化一個(gè)對(duì)象才能去執(zhí)行它們。-forwardInvocation:方法中默認(rèn)調(diào)用doesNotRecognizeSelector方法,這導(dǎo)致了應(yīng)用的頻繁異?;虮罎?。

內(nèi)省

動(dòng)態(tài)方法決議并不只是像Ruby和Objective-C這樣的語(yǔ)言的技術(shù)支持。你也可以通過(guò)在runtime中用一種有意思的方式去操作這些對(duì)象。

就像在Ruby中調(diào)用MyClass#instance_methods一樣,你可以在Objective-C中調(diào)用class_copyMethodList([MyClass class], &numberOfMethods)來(lái)得到一個(gè)對(duì)象中方法的列表。你還可以通過(guò)class_copyPropertyList方法得到一個(gè)類中property的列表,它能在你的模型中實(shí)現(xiàn)不可思議的內(nèi)省。比如在這個(gè)Rap Genius應(yīng)用中,我們用這個(gè)功能來(lái)將JSON中的字典映射到本地對(duì)象上。

(如果你非常喜歡Ruby中的mixin,那么Objective-C強(qiáng)大的動(dòng)態(tài)支持也能能實(shí)現(xiàn)同樣的效果。 Vladimir Mitrovic有一個(gè)叫Objective-Mixin的庫(kù),它能在runtime時(shí)將一個(gè)類中的實(shí)現(xiàn)復(fù)制到另一個(gè)類中。)

現(xiàn)學(xué)現(xiàn)用

所有的動(dòng)態(tài)工具都可以用來(lái)創(chuàng)建像Core Data這樣的東西,Core Data是一個(gè)有點(diǎn)像ActiveRecord的持久化對(duì)象圖。在Core Data中,relationship是“有缺陷的”,也就是說(shuō)他們只有在被別的對(duì)象訪問(wèn)時(shí),才會(huì)被加載。每個(gè)property的accessor和 mutator在runtime中都被重寫(xiě)(使用的就是我們上面提到的動(dòng)態(tài)方法決議)。如果我們?cè)L問(wèn)了一個(gè)還沒(méi)有被加載的對(duì)象時(shí),框架就會(huì)從持久性儲(chǔ)存中 動(dòng)態(tài)加載這個(gè)對(duì)象并將它返回。它保持了內(nèi)存的低利用率,避免了在任何一個(gè)物體被獲取時(shí),實(shí)體對(duì)象圖表都要被加載到內(nèi)存中這樣情況的發(fā)生。

當(dāng)Core Data實(shí)體中的mutator被調(diào)用時(shí),系統(tǒng)會(huì)將那個(gè)對(duì)象標(biāo)記為需要清理,不需要去重寫(xiě)每個(gè)property的getter和setter。

這就是元程序,羨慕吧!

什么是編譯器?

很明顯,Objective-C和Ruby并不是同一種語(yǔ)言,目前為止***的不同就是Objective-C是一種編譯型語(yǔ)言。

這就是這些技術(shù)中最需要注意的地方。在編譯時(shí),編譯器會(huì)先確定你應(yīng)用使用的每個(gè)selector是不是都在應(yīng)用中。如果你處理的這個(gè)對(duì)象有類型信息,那么編譯器也會(huì)檢查確保這個(gè)selector在頭文件有聲明過(guò),這樣做就是為了防止在對(duì)象中調(diào)用未聲明的selector。有些方法可以繞過(guò)這些討厭的限制,包括關(guān)閉相關(guān)的編譯警告。這里就是實(shí)踐元程序化的Objective-C***的練習(xí)。

你可以通過(guò)將selector的類型儲(chǔ)存為不知道的類型或id來(lái)從對(duì)象中刪除這些類型信息。因?yàn)榫幾g器不認(rèn)識(shí)這個(gè)類型,所以它只能假設(shè)你的程序可以接受發(fā)給它的任何消息(假設(shè)這些消息在應(yīng)用中的其他地方被聲明了,并且相關(guān)的編譯標(biāo)識(shí)已經(jīng)打開(kāi))。

善意的忠告:如果我們關(guān)掉編譯器標(biāo)識(shí)和把對(duì)象保存成id類型,那么將會(huì)非常危險(xiǎn)的事!其實(shí)Objective-C中***的東西之一就是編譯器(是的,比元程序還要好)。類型檢查保證了我們更快的寫(xiě)和重構(gòu)代碼,也是我們?cè)诰幊虝r(shí)少犯錯(cuò)誤。因?yàn)闆](méi)有人會(huì)關(guān)掉那些警告,所以你很難去分享你那些id類型的代碼。大部分Objective-C開(kāi)發(fā)者還是更愿意使用更強(qiáng)的類型而不是元程序。

事實(shí)證明Objective-C更受束縛–但因?yàn)榫幾g器能提高更多的安全性和速度,所以我們只能選擇這樣并承擔(dān)后果。

事實(shí)再次告訴我們,這些語(yǔ)言都是差不多的,Ruby開(kāi)發(fā)者應(yīng)該享受Objective-C,即使那些中括號(hào)讓我們望而卻步。

原文鏈接: Soroush Khanlou   翻譯:墨日陽(yáng)光

譯文鏈接: http://blog.jobbole.com/63628/

責(zé)任編輯:閆佳明 來(lái)源: blog.jobbole
相關(guān)推薦

2010-11-24 10:35:40

Objective-C

2014-04-15 11:27:50

C++開(kāi)發(fā)者Objective-C核心語(yǔ)法

2014-04-01 10:50:42

iOS開(kāi)發(fā)runtimeObjective-C

2011-04-08 10:51:17

Objective-CiOS

2011-08-03 16:22:05

Objective-C CodeBlocks

2011-08-10 18:07:29

Objective-C反射

2013-03-27 12:54:00

iOS開(kāi)發(fā)Objective-C

2011-05-11 11:20:26

Objective-C

2011-05-11 15:58:34

Objective-C

2013-06-20 10:40:32

Objective-C實(shí)現(xiàn)截圖

2011-07-29 15:47:21

iPhone開(kāi)發(fā) Objective- C

2011-08-16 17:43:47

Objective-C內(nèi)存管理Autorelease

2011-07-27 16:18:42

Objective-c 協(xié)議

2011-08-04 15:55:50

Windows 編譯 Objective-

2014-09-26 09:49:48

SwiftObjective-C

2010-09-01 09:19:33

Objective-CiPhone開(kāi)發(fā)iPhone

2011-07-28 15:11:23

iOS Objective-

2011-07-25 17:31:49

iPhone Objective-

2012-04-23 11:00:56

iOS開(kāi)發(fā)Objective-CJavaScript

2011-07-07 17:04:33

iPhone Action Objective-
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)