為什么Objecive-C中的很多類名都是NS開頭的呢?
我保證在你第一次給別人介紹Objective-C的時候肯定會聽到這句話店乐。
就像父母要向孩子解釋什么是死亡或者圣誕老人是不存在的問題一樣窝革,父母總是寄希望時間會讓孩子自己找到答案敛腌。
你既然這么問了昭雌,實際上NS代表了NeXTSTEP(好吧,其實是代表NeXTSTEP/Sun硫狞,我們只是做個簡單的介紹),它被用于...
你越解釋,你會發(fā)現(xiàn)對方越失望*残吩,接下來财忽,他們不在只是隨便問問了,他們開始問一些你更難解釋的問題--在Objective-C中@是什么泣侮?
命名一直是Objective-C的硬傷即彪,和那些優(yōu)雅的語言相比,Objective-C缺乏標(biāo)識符容器這點引來了很多不切實際的批評家活尊。
他們總是說:Objective-C不像其他流行語言一樣提供模塊化機制來避免類名和方法名的沖突隶校。
相反地,Objective-C 依靠前綴來確保APP中的方法名不會影響其他有相同名字的代碼酬凳。
插入一個關(guān)于類型系統(tǒng)的題外話之后我們會繼續(xù)進入關(guān)于命名的討論惠况。
C和Objective-C中的類型
我曾在這個博客上多次提過Objective-C是直接建立在C語言之上的,一個重要的原因是Objective-C和C語言共用一個類型系統(tǒng)宁仔,他們都要求標(biāo)識符是全局唯一的稠屠。
你可以自己定義一個和@interface同名的靜態(tài)變量,編譯之后你會得到一個錯誤:
@interfaceXXObject:NSObject@endstaticchar*XXObject;//將“XXObject”重新定義為不同的符號
也就是說翎苫,Objective-C的runtime在C語言的類型系統(tǒng)上又創(chuàng)建了一個抽象層权埠,它甚至可以允許下面這段代碼被編譯:
@protocolFoo@end@interfaceFoo:NSObject{idFoo;}@propertyidFoo;+(id)Foo;-(id)Foo;@end@interfaceFoo(Foo)@end@implementationFoo@synthesizeFoo;+(id)Foo{idFoo=@"Foo";returnFoo;}@end
通過Objective-C的環(huán)境,程序能區(qū)別所有相同名字的類煎谍,協(xié)議攘蔽,類別,實例變量呐粘,實例方法和類方法满俗。
一個變量能重新調(diào)整一個已經(jīng)存在的方法也是得益與C語言的類型系統(tǒng)(這個有點像一個變量能夠隱藏它的隱藏功能)
前綴
在Objective-C應(yīng)用中的所有類名都必須是全局唯一的。由于很多不同的框架中會有一些相似的功能作岖,所以在名字上也可能會有重復(fù)(users唆垃, views, requests / responses 等等)痘儡,所以蘋果官方文檔規(guī)定類名需要有2-3個字母作為前綴辕万。
類前綴
蘋果官方建議兩個字母作為前綴的類名是為官方的庫和框架準(zhǔn)備的,而對于作為第三方開發(fā)者的我們沉删,官方建議使用3個或者更多的字母作為前綴去命名我們的類渐尿。
一個資深的Mac或iOS開發(fā)者可能會記得下面大部分的縮寫標(biāo)識符:
PrefixFrameworks
ABAddressBook / AddressBookUI
ACAccounts
ADiAd
ALAssetsLibrary
AUAudioUnit
AVAVFoundation
CACoreAnimation
CBCoreBluetooth
CFCoreFoundation / CFNetwork
CGCoreGraphics / QuartzCore / ImageIO
CICoreImage
CLCoreLocation
CMCoreMedia / CoreMotion
CVCoreVideo
EAExternalAccessory
EKEventKit / EventKitUI
GCGameController
GLK*GLKit
JSJavaScriptCore
MAMediaAccessibility
MCMultipeerConnectivity
MFMessageUI*
MIDI*CoreMIDI
MKMapKit
MPMediaPlayer
NKNewsstandKit
NSFoundation, AppKit, CoreData
PKPassKit
QLQuickLook
SCSystemConfiguration
Sec*Security*
SKStoreKit / SpriteKit
SLSocial
SSSafari Services
TWTwitter
UIUIKit
UTMobileCoreServices
第三方類前綴
直到最近,由于CocoaPods的出現(xiàn)和大量新的iOS開發(fā)者的涌現(xiàn)矾瑰,開源代碼的遍布砖茸,第三方代碼在很大程度上對蘋果和其余的Objective-C開發(fā)社區(qū)來說已經(jīng)不是問題了。最近蘋果官方的命名指南也發(fā)生了變化脯倚,它將三個字母作為前綴的建議只是做為一個習(xí)慣做法渔彰。
正因為這樣嵌屎,那些已經(jīng)存在的第三方庫依然使用2個字母作為前綴,你可以參考一些那些在GitHub上得到很多start的Objective-C的倉庫恍涂。
PrefixFrameworks
AFAFNetworking("Alamofire")
RKRestKit
GPUGPUImage
FMFMDB("Flying Meat")
JKJSONKit
FUIFlatUI
NINimbus
我們已經(jīng)看到在在這個第三方庫的前綴已經(jīng)和我的AFNetworking一樣了宝惰,所以最好還是要在你的代碼中遵守要三個字母以上的作為類前綴的規(guī)定(https://github.com/AshFurrow/AFTabledCollectionView)。
對于那些針對特殊功能而寫的第三方庫的作者再沧,可以考慮在下一次主要升級時使用@compatibility_alias來為那些使用者們提供一個天衣無縫的轉(zhuǎn)移路徑尼夺。
方法前綴
不僅是類容易造成命名沖突,selectors也很容易造成命名沖突炒瘸,甚至方法比類會有更多的問題淤堵。 考慮一下這個category:
@interfaceNSString(PigLatin)-(NSString*)pigLatinString;@end
如果-pigLatinString方法被另一個category實現(xiàn)了(或者以后版本的iOS或者OS X 在NSString類中也添加了同樣名字的方法),那么調(diào)用這個方法就會得到未定義的行為錯誤顷扩,因為我們不能保證在runtime中哪個方法會先被定義拐邪。
我們可以通過在方法名前加前綴來避免這個問題,就像加這個類名一樣(在類別名前加前綴也是個好辦法):
@interfaceNSString(XXXPigLatin)-(NSString*)xxx_pigLatinString;@end
蘋果官方建議所有category方法都要使用前綴隘截,這個建議比類名需要加前綴的規(guī)定更加廣為人知和接受扎阶。
很多開發(fā)者都在熱情地討論著這個規(guī)定的某一方面。然而婶芭,無論是通過成本角度還是效益角度來衡量命名沖突風(fēng)險的可能性都是是不全面的:
category的主要功能是通過語法糖將一些有用的功能包裹進原來的類中东臀。任何一個category方法都可以被選擇性實現(xiàn),你也可以把他當(dāng)做是self的一個隱型功能方法犀农。
當(dāng)我在編譯器的環(huán)境參數(shù)中將OBJC_PRINT_REPLACED_METHODS這個參數(shù)設(shè)置為YES惰赋,那我們就能在編譯的時候檢測方法名是否有沖突。實際上呵哨,方法名的沖突是很少發(fā)生的赁濒,而且在發(fā)生的時候,他們通常會得到一個needlessly duplicated across dependencies的提示孟害。即使發(fā)生最壞的情況流部,程序在運行是出現(xiàn)異常,那么很可能是兩個方法名一樣纹坐,那么他們做的事情也是一樣的,所以結(jié)果也不會有什么變化舞丛。就像Swiss Army Knife寫了一個category耘子,他定義了NSArray中的-firstObject這個方法,那么只要蘋果官方?jīng)]有在NSArray中加這個方法的話球切,那么這個類別方法一直有效的谷誓。
在蘋果官方的編程指南中有很多嚴肅又松散的解釋。這里沒有固定的文檔吨凑,他們可能一直變化捍歪』瑁看到這里,如果你還是懸而未決糙臼,那么你只需要把的category方法名加上前綴庐镐,如果你還是選擇不去做任何改變,那么你就等著自食其果吧变逃。
Swizzling
在Swizzling時必逆,方法名加前綴或者后綴也是非常有必要的,這個我在上周關(guān)于swizzling的文章中提到過揽乱。
@implementationUIViewController(Swizzling)-(void)xxx_viewDidLoad{[selfxxx_viewDidLoad];// Swizzled implementation}
我們真的需要命名空間么名眉?
在最近關(guān)于Objective-C替換、改造和重塑的討論中凰棉,我可以明顯地發(fā)現(xiàn)命名空間是未來的一個趨勢损拢。但是它到底給我們帶來了什么呢?
美學(xué)撒犀?除了IETE成員和軍事人員福压,我想沒有人會喜歡CLAs的視覺審美,但是用::绘证,/或者另外的.這些符號真的能讓我們覺得更好么隧膏?你真的想要以后把NSArray叫做"Foundation Array"?(那我這個NSHipster.com這個博客不是也得改名字了?!)
語義學(xué)嚷那?讓我們比較一下其他的語言胞枕,看看他們是怎么用命名空間的,那么你就會意識到命名空間不能解決所有不明確的問題魏宽「海可能在某些額外環(huán)境的情況下,那些命名空間會出現(xiàn)更多問題队询。
你還是不贊同派桩,那么你想象一下Objective-C的命名空間的實現(xiàn)可能會像這個樣子,你會覺得怎么樣:
@namespaceXX@implementationObject@usingF:Foundation;-(void)foo{F:Array*array=@[@1,@2,@3];// ...}@end@end
雖然Objective-C有繁瑣的代碼但也有容易理解的明顯優(yōu)點蚌斩。我們作為開發(fā)者去討論NSString的時候铆惑,我們不會把它理解成別的意思,編譯器也是一樣送膳。當(dāng)我們在閱讀代碼時员魏,我們不需要過多地去考慮這些代碼是什么作用的。并且最重要的是叠聋,NSString這個類名在google這些搜索引擎中很容易就可以找到撕阎, 你不會得到其他結(jié)果。
不管怎樣碌补,如果你對這個討論感興趣的話虏束,我強烈建議你看一下Kyle Sluder的this namespace feature proposal棉饶。非常值得一看。
轉(zhuǎn):原文鏈接