從 C++ 到 Objective-C 的快速指南
當(dāng)我開始為iOS寫代碼的時(shí)候,我意識(shí)到,作為一個(gè)C++開發(fā)者,我必須花費(fèi)更多的時(shí)間來弄清楚Objective-C中怪異的東西。這就是一個(gè)幫助C++專家的快速指南,能夠使他們快速的掌握Apple的iOS語言。
請(qǐng)注意這絕不是一個(gè)完整的指南,但是它讓你避免了閱讀100頁(yè)的手冊(cè)。除此之外,我知道你喜歡我的寫作風(fēng)格。
背景
需要C++的技能,我會(huì)比較C++和Objective-C的東西。此外,COM編程也是有用的,因?yàn)镺bjective-C有類似于IUnkown的東西,因此基礎(chǔ)的COM編程是有幫助的(但不是必須的)
Objective C++是C++和Objective C的組合。你也能使用任何C++的東西混合到Objective C中,但是記住重新命名你的文件從.m到.mm
鐺 - 鐺!
我們馬上就開始我們的教程. 首先我會(huì)介紹 Objective-C 的東西,然后是C++中與它對(duì)等的東西.
成員函數(shù)
- // Objective-C
- - (int) foo : (int) a : (char) b {}
- + (int) foo : (int) a : (char) b {}
- // C++
- int foo(int a,char b) {}
- static int foo(int a,char b) {}
- // Objective-C
- - (void) foo2 val1:(int) a; // named argument
- // <span id="22_nwp" style="width: auto; height: auto; float: none;"><a id="22_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=18&is_app=0&jk=b2645dbfe197c88d&k=call&k0=call&kdi0=0&luki=1&n=10&p=baidu&q=06011078_cpr&rb=0&rs=1&seller_id=1&sid=8dc897e1bf5d64b2&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1922429&u=http%3A%2F%2Fwww%2Eadmin10000%2Ecom%2Fdocument%2F4400%2Ehtml&urlid=0" target="_blank" mpid="22" style="text-decoration: none;"><span style="color:#0000ff;font-size:14px;width:auto;height:auto;float:none;">call</span></a></span>
- [obj foo2 val1:5]; // merely helper: You remember that 5 is assigned to param name val1.
- 表示的是一個(gè)一般的成員函數(shù)(通過一個(gè)對(duì)象實(shí)體訪問), 而 + 則表示一個(gè)靜態(tài)成員函數(shù), 不需要使用實(shí)體就能訪問. 當(dāng)然,像C++, 靜態(tài)成員不能訪問實(shí)體變量.
此外,Objective-C函數(shù)函數(shù)可以有賦予了名稱的參數(shù),這樣讓什么參數(shù)獲得什么值會(huì)更一目了然. 理論上,被賦予了名稱的參數(shù)允許程序員按任何順序傳入?yún)?shù),但是Objective-C卻規(guī)定要按聲明的順序傳參.
通過一個(gè)指針或者一個(gè)靜態(tài)成員調(diào)用一個(gè)成員
- // Objective-C
- NSObject* ptr = ...; // some pointer
- [ptr foo:5:3]; // <span id="19_nwp" style="width: auto; height: auto; float: none;"><a id="19_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=18&is_app=0&jk=b2645dbfe197c88d&k=call&k0=call&kdi0=0&luki=1&n=10&p=baidu&q=06011078_cpr&rb=0&rs=1&seller_id=1&sid=8dc897e1bf5d64b2&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1922429&u=http%3A%2F%2Fwww%2Eadmin10000%2Ecom%2Fdocument%2F4400%2Ehtml&urlid=0" target="_blank" mpid="19" style="text-decoration: none;"><span style="color:#0000ff;font-size:14px;width:auto;height:auto;float:none;">call</span></a></span> foo member with arguments 5 and 3
- [NSObject staticfoo:5:3]; // call static function of NSOBject with arguments 4 and 3
- // C++
- CPPObject* ptr = ...; // some pointer
- ptr->foo(5,3);
- CPPObject::staticfoo(5,3);
Objective-C 使用 [ ] 來調(diào)用成員函數(shù)并傳入用:分割開的參數(shù), 其對(duì)于ObjectiveC中ptr為nil的情況非常友好,在這種情況下“調(diào)用”將會(huì)被忽略掉(而在C++中,這種情況會(huì)拋出一個(gè)指針沖突異常 ). 這使得消除對(duì)nil對(duì)象的檢查成為可能.
協(xié)議VS接口
- // Objective-C
- @protocol foo
- - (void) somefunction;
- @end
- @interface c1 : NSObject<foo>
- @end
- @implementation c1
- - (void) somefunction { ... }
- @end
- // C++
- class foo
- {
- virtual void somefunction() = 0;
- };
- class c1 : public NSObject, public foo
- {
- void somefunction() { ... }
- }
協(xié)議= 抽象類. Objective-C 和 C++ 之間的區(qū)別在于,在 Objective-C 中, 函數(shù)并不是必須要被實(shí)現(xiàn)的. 你可以讓一個(gè)可選的方法被動(dòng)的被聲明,而這僅僅只是向編譯器發(fā)出暗示而已,并不是編譯必須的.檢查一個(gè)方法是否被實(shí)現(xiàn)了
- / Objective-C
- NSObject* ptr = ...; // some pointer
- [ptr somefunction:5:3]; // NSObject 不必一定為其編譯而實(shí)現(xiàn)somefunction. 如果沒有被實(shí)現(xiàn)的話,會(huì)引發(fā)異常.
- // C++
- CPPObject* ptr = ...; // some pointer
- ptr->somefunction(5,3); // CPPObject 必須實(shí)現(xiàn) somefunction() 否則程序根本就不會(huì)被編譯.
Objective-C 成員函數(shù)就是(Smalltalk中的) "消息" 而在Objective-C中時(shí),我們則說接收者 (即指針) 會(huì)向一個(gè)選擇器做出回應(yīng), 這意味著其實(shí)現(xiàn)了我們嘗試去調(diào)用的虛函數(shù). 當(dāng)有一個(gè)接口是, C++ 對(duì)象必須實(shí)現(xiàn)其所有的成員函數(shù). 而在 Objective-C 中這并不是必須的,因此我們可以向并不必須要實(shí)現(xiàn)它的某個(gè)地方發(fā)送一個(gè)”消息“ (如此就會(huì)引發(fā)一個(gè)異常).
// Objective-C
NSObject* ptr = ...; // some pointer
if ([ptr respondsToSelector:@selector(somefunction::)]
[ptr somefunction:5:3];
現(xiàn)在我們就可以確定接收者向選擇器做出回應(yīng), 我們因此就可以調(diào)用它了. 在 C++ 中不需要這樣的檢查, 因?yàn)閷?shí)現(xiàn)必須常常”向選擇器做出回應(yīng)“, 否則源代碼根本就不會(huì)被編譯. 請(qǐng)注意我們必須知道選擇器獲取了多少個(gè)參數(shù)(因此在該@selector中是2個(gè) ::s
向下轉(zhuǎn)型
- // Objective-C
- NSObject* ptr = ...; // some pointer
- if ([ptr isKindOfClass:[foo class]]
- [ptr somefunction:5:3];
- // C++
- CPPObject* ptr = ...; // some pointer
- foo* f = dynamic_cast<foo*>(ptr);
- if (f)
- f->somefunction(5,3);
現(xiàn)在只有使用NSObject的"isKindOfClass"助手——所有Object-C類的基礎(chǔ),才能像在C++中那樣向下轉(zhuǎn)型.
符合協(xié)議?
- // Objective-C
- NSObject* ptr = ...; // some pointer
- if ([ptr conformsToProtocol:@protocol(foo)]
- [ptr somefunction:5:3];
- // C++
- CPPObject* ptr = ...; // 某個(gè)也繼承自foo的指針
- foo* f = ptr; // 或者<span id="15_nwp" style="width: auto; height: auto; float: none;"><a id="15_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=18&is_app=0&jk=b2645dbfe197c88d&k=%B1%E0%D2%EB%C6%F7&k0=%B1%E0%D2%EB%C6%F7&kdi0=0&luki=8&n=10&p=baidu&q=06011078_cpr&rb=0&rs=1&seller_id=1&sid=8dc897e1bf5d64b2&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1922429&u=http%3A%2F%2Fwww%2Eadmin10000%2Ecom%2Fdocument%2F4400%2Ehtml&urlid=0" target="_blank" mpid="15" style="text-decoration: none;"><span style="color:#0000ff;font-size:14px;width:auto;height:auto;float:none;">編譯器</span></a></span>會(huì)警告我們說ptr不能同foo兼容.
- f->somefunction(5,3);
現(xiàn)在我們要檢查接收器是否 符合一個(gè)協(xié)議 (或者說,在C++就是實(shí)現(xiàn)一個(gè)接口), 以便我們可以發(fā)送這個(gè)協(xié)議包含的消息. 嘿嘿,它像極了Java的類和接口,而在C++中,完全被實(shí)現(xiàn)的類和一個(gè)“接口”之間沒有技術(shù)上的差別.
- void* 、 id 或者 SEL?
- // Objective-C
- id ptr = ...; // some pointer
- if ([ptr conformsToProtocol:@protocol(foo)]
- [ptr somefunction:5:3];
- SEL s = @selector(foo:); // a pointer to a function foo that takes 1 parameter
- // C++
- void* ptr = ...; // some pointer
- foo* f = dynamic_cast<foo*>(ptr);
- if (f)
- f->somefunction(5,3);
id 是通用的用于Objective-C類的類似于 void* 的東西. 你只能使用id而不是 void* 因?yàn)閕d可以通過ARC(稍后會(huì)詳細(xì)介紹到它)編程一個(gè)可被管理的指針,而因此編譯器需要在元指針類型和Objective-C指針之間做出區(qū)分. SEL 是一個(gè)用于選擇器(C++函數(shù)指針)的通用類型,而你一般可以通過使用關(guān)鍵字@selector帶上函數(shù)名字和:::::s的一個(gè)數(shù)字來創(chuàng)建一個(gè)選擇器, 這取決于可以傳入多少參數(shù). 選擇器實(shí)際上就是一個(gè)字符串,它會(huì)在運(yùn)行時(shí)綁定到一個(gè)方法識(shí)別器.
類定義,方法,數(shù)據(jù),繼承
- // Objective C
- @class f2; // forward declaration
- @interface f1 : NSOBject // Objective-C supports only public and single inheritance
- {
- int test; // default = protected
- @public
- int a;
- int b;
- f2* f;
- }
- - (void) foo;
- @end
- @implementation f1
- - (void) foo
- {
- a = 5; // ok
- self->a = 5; // ok
- super.foo(); // parent <span id="11_nwp" style="width: auto; height: auto; float: none;"><a id="11_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=18&is_app=0&jk=b2645dbfe197c88d&k=call&k0=call&kdi0=0&luki=1&n=10&p=baidu&q=06011078_cpr&rb=0&rs=1&seller_id=1&sid=8dc897e1bf5d64b2&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1922429&u=http%3A%2F%2Fwww%2Eadmin10000%2Ecom%2Fdocument%2F4400%2Ehtml&urlid=0" target="_blank" mpid="11" style="text-decoration: none;"><span style="color:#0000ff;font-size:14px;width:auto;height:auto;float:none;">call</span></a></span>
- }
- @end
- // C++
- class f1 : public CPPObject
- {
- int test; // default = private
- public:
- class f2* f; // forward declaration
- int a;
- int b;
- void foo();
- }
- void f1 :: foo()
- {
- a = 5; // ok
- this->a = 5; // ok
- CPPOBject::foo(); // parent call
- }
Objective-C中的實(shí)現(xiàn)范圍在@implementation/@end 標(biāo)記 (在 C++ 中我們可以將實(shí)現(xiàn)放在任何帶有::范圍操作符的地方)之中. 它使用@class關(guān)鍵字用于事先聲明. Objective-C 默認(rèn)帶有 私有(private)保護(hù), 但僅用于數(shù)據(jù)成員(方法必須是公共的). Objective-C 使用 self 而不是 this ,并且它還可以通過super關(guān)鍵字調(diào)用它的父類.
構(gòu)造器和析構(gòu)器
- // Objective-C
- NSObject* s = [NSObject alloc] init]; // can return nil if construction failed
- [s retain]; // Increment the ref count
- // C++
- CPPObject* ptr = new CPPObject(); // can throw
- ptr->AddRef();
- // Objective-C
- NSObject* s = [NSObject alloc] initwitharg:4];
- [s release];
- // C++
- CPPOBject* ptr = new CPPOBject(4);
- ptr->Release();
Objective-C中的內(nèi)存分配是通過靜態(tài)成員方法alloc來實(shí)現(xiàn)的,所有 (做為NSObject后裔)的對(duì)象都有這個(gè)方法. self 在Objective-C中是可以被賦值的,而如果構(gòu)建失敗的話它就會(huì)設(shè)置成nil(而在C++中則會(huì)被拋出一個(gè)異常). 內(nèi)存分配之后實(shí)際被構(gòu)造器調(diào)用的是一個(gè)公共的成員函數(shù),在Objective-C中默認(rèn)的是init方法.
Objective-C 使用同COM益陽的引用計(jì)數(shù)方法, 而它也使用 retain 和 release (等同于IUnknown的 AddRef() 和 Release() 方法). 當(dāng)引用計(jì)數(shù)到了0,則對(duì)象會(huì)從內(nèi)存中被移除掉.
多線程
- // Objective C
- @interface f1 : NSOBject // Objective-C supports only public and single inheritance
- {
- }
- - (void) foo;
- - (void) threadfunc :(NSInteger*) param;
- - (void) mt;
- @end
- @implementation f1
- - (void) threadfunc : (NSInteger*) param
- {
- [self performSelectorOnMainThread: @selector(mt)];
- }
- - (void) mt
- {
- }
- - (void) foo
- {
- [self performSelectorInBackground: @selector(thradfunc:) withObject:1 waitUntilDone:false];
- <div></div>}
- @end
Objective-C 有一些針對(duì)NSObject的內(nèi)建功能,可以在另外一個(gè)線程中操作一個(gè)選擇器 (== 調(diào)用一個(gè)成員), 在主線程中,等待一次調(diào)用等等 . 在NSObject 參見更多信息.
內(nèi)存和ARC
@end -(void)foo { NSObject*s = [NSObject alloc] init]; // 如果構(gòu)造失敗的話會(huì)返回nil // use s // end. Hooraah! Compiler will automati<span id="9_nwp" style="width: auto; height: auto; float: none;"><a id="9_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=18&is_app=0&jk=b2645dbfe197c88d&k=call&k0=call&kdi0=0&luki=1&n=10&p=baidu&q=06011078_cpr&rb=0&rs=1&seller_id=1&sid=8dc897e1bf5d64b2&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1922429&u=http%3A%2F%2Fwww%2Eadmin10000%2Ecom%2Fdocument%2F4400%2Ehtml&urlid=0" target="_blank" mpid="9" style="text-decoration: none;"><span style="color:#0000ff;font-size:14px;width:auto;height:auto;float:none;">call</span></a></span>y call[s release] for us! }
- // Objective-C
- @interface f1 : NSObject
- {
- }
- @property (weak) NSAnotherObject* f2; // 當(dāng)沒有其它強(qiáng)引用存在的時(shí)候,它將會(huì)被自動(dòng)設(shè)置成
這里需要你忘記自己良好的 C++ 習(xí)慣. OK Objective-C 使用了一個(gè)垃圾收集機(jī)制,這種東西我們C++很討厭,因?yàn)樗苈?huì)讓我們想到Java. 但是 ARC (自動(dòng)進(jìn)行引用計(jì)算) 是一種 編譯時(shí)間 特性,它會(huì)告訴編譯器 "這里是我的對(duì)象:請(qǐng)幫我算算啥時(shí)候它們才要被銷毀吧". 使用ARC你就不需要發(fā)送 retain/release 消息給你的對(duì)象了; 編譯器會(huì)自動(dòng)幫你代勞的.
為了能幫助編譯器決定保留一個(gè)對(duì)象多長(zhǎng)時(shí)間,你還要一個(gè)弱引用指向一個(gè)變量. 默認(rèn)的,所有的變量都是強(qiáng)引用(==只要強(qiáng)引用還存在,被引用的對(duì)象就會(huì)存在下去) . 你也可以獲取一個(gè)弱引用,它會(huì)隨著每個(gè)強(qiáng)引用消失而失去它的值. 這在類成員從XCode的Builder Interface(像RC 編輯器)處獲取它們的值時(shí),會(huì)很有用,當(dāng)類被銷毀時(shí),那些成員也會(huì)失去它們的值.
Strings
- // Objective-C
- NSString* s1 = @"hello";
- NSString* s2 = [NSString stringWithUTF8String:"A C String"];
- sprintf(buff,"%s hello to %@","there",s2);
- const char* s3 = [s2 UTF8String]
;
NSString 是一個(gè)Objective-C字符串的不可變表示. 你可以使用其一個(gè)靜態(tài)方法,或者是一個(gè)帶有@前綴的字符串文本來創(chuàng)建NSString. 你也可以使用 %@ 來向printf家族函數(shù)來表示一個(gè)NSString,
數(shù)組
- // Objective-C
- NSArray* a1 = [NSArray alloc] initWithObjects: @"hello",@"there",nil];
- NSString* first = [a1 objectAtIndex:0];
NSArray和NSMutableArray是在Objective-C中處理數(shù)組的 兩個(gè)類(兩者的差異是,NSArray元素構(gòu)造時(shí)必須通過構(gòu)造函數(shù),而NSMutableArray可以在之后更改)。典型構(gòu)造函數(shù)的生效,你必須通過nil去作為“結(jié)尾元素”。排序/搜索/插入函數(shù)對(duì)于NSArray和NSMutableArray來說是一樣的,在第一行中的例子它返回一個(gè)新的NSArray,而在NSMutableArray的例子里,它修改的是一個(gè)存在的對(duì)象。
分類
- // C++
- class MyString : public string
- {
- public:
- void printmystring() { printf("%s",c_str()); }
- };
- // Objective-C
- @interface MyString (NSString)
- - (void) printmystring;
- @end
- @implementation MyString (NSString)
- - (void) printmystring
- {
- printf("%@",self);
- }
- @end
- // C++
- MyString s1 = "hi";
- s1.printmystring(); // ok
- string s2 = "hello";
- s2.printmystring(); // error, we must change s2 from string to MyString
- // Objective-C
- NSString* s2 = @"hello";
- [s2 printmystring]; // valid. We extended NSString without changing types.
C++依賴 繼承機(jī)制來實(shí)現(xiàn)一個(gè)已知的類。這是很麻煩的,因?yàn)樗杏脩舻膶?shí)現(xiàn)類必須使用另外的類型名稱(在例子中,MyString用來代替string)。Object-C通過使用 分類(Categories)允許擴(kuò)展一個(gè)已知的類內(nèi) 同型(same type )。上面鏈接中所有源代碼在extension.h文件 (具有代表性的是像NSString+MyString.h這樣的)中可以查看,上面例子中,我們立即就有可以調(diào)用新的成員函數(shù),而不需要改變NSString類型為MyString。
塊 和 Lambda
- // Objective-C
- // member function
- -(void)addButtonWithTitle:(NSString*)title <span id="4_nwp" style="width: auto; height: auto; float: none;"><a id="4_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=18&is_app=0&jk=b2645dbfe197c88d&k=block&k0=block&kdi0=0&luki=3&n=10&p=baidu&q=06011078_cpr&rb=0&rs=1&seller_id=1&sid=8dc897e1bf5d64b2&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1922429&u=http%3A%2F%2Fwww%2Eadmin10000%2Ecom%2Fdocument%2F4400%2Ehtml&urlid=0" target="_blank" mpid="4" style="text-decoration: none;"><span style="color:#0000ff;font-size:14px;width:auto;height:auto;float:none;">block</span></a></span>:(void(^)(AlertView*, NSInteger))block;
- // <span id="5_nwp" style="width: auto; height: auto; float: none;"><a id="5_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=18&is_app=0&jk=b2645dbfe197c88d&k=call&k0=call&kdi0=0&luki=1&n=10&p=baidu&q=06011078_cpr&rb=0&rs=1&seller_id=1&sid=8dc897e1bf5d64b2&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1922429&u=http%3A%2F%2Fwww%2Eadmin10000%2Ecom%2Fdocument%2F4400%2Ehtml&urlid=0" target="_blank" mpid="5" style="text-decoration: none;"><span style="color:#0000ff;font-size:14px;width:auto;height:auto;float:none;">call</span></a></span>
- [object addButtonWithTitle:@"hello" block:[^(AlertView* a, NSInteger i){/*DO SOMETHING*/}];
塊 是Objective-C 用來模擬lambda功能的一種方式. 查看Apple的文檔,從AlertView的示例 (使用塊的UIAlertView)可以獲得更多有關(guān)塊的技術(shù).
C++ 開發(fā)者使用 Objective-C 和 ARC 的重要提示
- // C++
- class A
- {
- public:
- NSObject* s;
- A();
- };
- A :: A()
- {
- s = 0; // 可能會(huì)奔潰,這是常發(fā)生在發(fā)布模式下!
- }
你已經(jīng)知道給所有的顧客都打兩折對(duì)你而言有多痛苦了,因?yàn)槟鉨ug重重的軟件會(huì)在發(fā)布模式下奔潰,而在調(diào)試模式下總是妥妥的. 沒有用戶會(huì)理解程序員,是不是?
讓我們來看看這里發(fā)生了什么. s = 0 這一行將 0 賦值給了一個(gè)變量,而因此不管這個(gè)變量之前取值是什么,首先都會(huì)被釋放掉,所以編譯器在賦值之前執(zhí)行了一次 [s release] . 如果 s 之前已經(jīng)是 0 了,假設(shè)是在調(diào)試構(gòu)建的話,不會(huì)發(fā)生任何不好的事情; 如果 s 是一個(gè)nil的話,使用[s release] 是再好也不過的. 然而,在發(fā)布模式下, s可能是一個(gè)野指針,所以它可能在被“初始化”為0之前包含任何值(這很危險(xiǎn)是不是?).
在C++中,這并不是一個(gè)問題,因?yàn)樗锩媸遣淮嬖贏RC的. 而在Objective-C中編譯器并沒有辦法了解這是一次"賦值" 還是一次 "初始化" (如果是后者,它就不會(huì)發(fā)送發(fā)布消息).
下面是正確的方式:
- // C++
- class A
- {
- public:
- NSObject* s;
- A();
- };
- A :: A() :s(0) // 現(xiàn)在編譯器就知道確定 it's 是一次初始化了, 一次就不存在 [s release]
- {
- }
現(xiàn)在編譯器就不會(huì)去嘗試調(diào)用一個(gè) [s release] 因?yàn)樗浪沁@個(gè)對(duì)象的第一次初始化. 請(qǐng)小心!
從Objective-C 對(duì)象到 C++ 類型的轉(zhuǎn)換
- // Objective-C
- NSObject* a = ...;
- void* b = (__bridge void*)a; // 你必須在Objective-C和C類型支架使用 __bridge
- void* c = (__bridge_retained void*)a; // 現(xiàn)在是一個(gè)+1的保留計(jì)數(shù),而你必須在稍后釋放這個(gè)對(duì)象
- NSObject* d = (__bridge_transfer NSObject*)c; // 現(xiàn)在ARC取得了對(duì)象c的”擁有權(quán)“, 將其裝換成一個(gè)ARC管理的NSObject.
我可以分析這一切,而我的建議是簡(jiǎn)單的. 不要 將ARC類型和非ARC類型混在一起. 如果你必須轉(zhuǎn)換一些Objective-C對(duì)象的話,使用id而不是void*. 否則,你將會(huì)遇到嚴(yán)重的內(nèi)存故障.
Objective-C 有而 C++ 沒有的
分類Categories
基于NSObject的操作
YES 和 NO (等價(jià)于true和false)
NIL 和 nil (等價(jià)于0)
可命名的函數(shù)參數(shù)
self (等價(jià)于 this) 而其可以在一個(gè)構(gòu)造器中被改變
C++ 有而 Objective-C 沒有的
靜態(tài)對(duì)象. Objective-C 中的對(duì)象不能被初始化成靜態(tài)的,或者是存在于棧中. 只能是指針.
多重繼承
命名空間
模板
操作符重載
STL 和算法 ;
方法可以是受保護(hù)的( protected )或者私有的( private ) (在Obj-C中,只能是公共的)
const/mutable 項(xiàng)
friend 方法
引用
匿名函數(shù)簽名 (沒有變量名稱)