西西軟件下載最安全的下載網(wǎng)站、值得信賴的軟件下載站!

首頁編程開發(fā)其它知識 → 從C++轉(zhuǎn)型做Objective-C 蘋果應用開發(fā)筆記

從C++轉(zhuǎn)型做Objective-C 蘋果應用開發(fā)筆記

相關(guān)軟件相關(guān)文章發(fā)表評論 來源:西西整理時間:2013/3/24 11:09:19字體大小:A-A+

作者:西西點擊:0次評論:0次標簽: Objective-C

1、Objective-C是一門語言,而 Cocoa 是這門語言用于 MacOS X 開發(fā)的一個類庫。它們的關(guān)系類似于 C++ 和 Qt,Java和 Spring 一樣。

2、每一個對象都是每一個對象都是 id類型的。 id 是一個指針。

3、nil等價于指向?qū)ο蟮?nbsp;NULL 指針。

4、Nil等價于指針 nil 的類。

5、SEL用于存儲選擇器 selector的值。所謂選擇器,就是不屬于任何類實例對象的函數(shù)標識符。這些值可以由 @selector獲取。選擇器可以當做函數(shù)指針,但實際上它并不是一個真正的指向函數(shù)的指針。

6、我們前面看到的類 NSObject,NSString都有一個前綴 NS。這是 Cocoa框架的前綴(Cocoa 開發(fā)公司是 NeXTStep)。

7、[object doSomething];

這并不是方法調(diào)用,而是發(fā)送一條消息?瓷先ゲ]有什么區(qū)別,實際上,這是Objective-C的強大之處。例如,這種語法允許你在運行時態(tài)添加方法。

8、嚴格說來,每一個類都應該是 NSObject的子類。

9、id類型是動態(tài)類型檢查的,相比來說,NSObject *則是靜態(tài)類型檢查。

10、Objective-C里面沒有泛型,那么,我們就可以使用 id很方便的實現(xiàn)類似泛型的機制了。

11、在 Objective-C里面,屬性 attributes被稱為實例數(shù)據(jù) instance data,成員函數(shù)member functions被稱為方法 methods。

12、實例方法以減號 -開頭,而 static 方法以 + 開頭。

13、在 Objective-C中,只有成員數(shù)據(jù)可以是 private,protected和 public 的,默認是 protected 。方法只能是 public 的。

14、Objective-C中的繼承只能是 public 的,不可以是 private 和 protected 繼承。

15、Objective-C中不允許聲明 static 屬性。

16、Objective-C中可以向任何對象發(fā)送任何消息。如果目標對象不能處理這個消息,它就會將消息忽略(這會引發(fā)一個異常,但不會終止程序)。

17、self指當前對象(類似 C++ 的 this),super指父對象。

18、重載的情況。C++和 Objective-C 使用截然不同的兩種方式去區(qū)分:前者使用參數(shù)類型,后者使用參數(shù)標簽。

19、@selector的值是在編譯器決定的,因此它并不會減慢程序的運行效率。

20、嚴格說來,選擇器并不是一個函數(shù)指針。它的底層實現(xiàn)是一個 C字符串,在運行時被注冊為方法的標識符。

21、最后,你應該記得我們曾經(jīng)說過 Objective-C 里面的 self 指針,類似于 C++ 的this 指針,是作為每一個方法的隱藏參數(shù)傳遞的。其實這里還有第二個隱藏參數(shù),就是_cmd。_cmd 指的是當前方法。

-(void) f:(id)parameter //等價于 C 函數(shù) void f(id self, SEL _cmd, id parameter)

22、代理 delegation是 Cocoa 框架中 UI 元素的一個很常見的部分。代理可以將消息轉(zhuǎn)發(fā)給一個未知的對象。通過代理,一個對象可以將一些任務(wù)交給另外的對象。

23、Objective-C也有繼承的概念,但是不能多重繼承。協(xié)議 protocol和分類categories模擬實現(xiàn)多重繼承。

24、在 Objective-C中,所有方法都是虛的。

25、純虛方法則是使用正式協(xié)議 formal protocols來實現(xiàn)

26、混合使用協(xié)議、分類和子類的唯一限制在于,你不能同時聲明子類和分類。不過,你可以使用兩步來繞過這一限制:

@interface Foo1 : SuperClass //ok

@end @interface Foo2 (Category) //ok

@end

// 下面代碼會有編譯錯誤

@interface Foo3 (Category) : SuperClass

@end

// 一種解決方案

@interface Foo3 : SuperClass //第一步

@end

@interface Foo3 (Category) //第二步

@end

27、在 Objective-C中,所有對象都是動態(tài)分配的。

重點關(guān)注:

28、self = [super init...]

在上一篇提到的代碼中,最不可思議的可能就是這句 self = [super init...];叵胍幌,self是每個方法的一個隱藏參數(shù),指向當前對象

。因此,這是一個局部變量。那么,為什么我們要改變一個局部變量的值呢?事實上,self必須要改變。我們將在下面解釋為什么要這樣做

。

[super init] 實際上返回不同于當前對象的另外一個對象。單例模式就是這樣一種情況。然而,有一個 API可以用一個對象替換新分配的

對象。Core Data(Apple提供的 Cocoa 里面的一個 API)就是用了這種 API,對實例數(shù)據(jù)做一些特殊的操作,從而讓這些數(shù)據(jù)能夠和數(shù)據(jù)庫

的字段關(guān)聯(lián)起來。當繼承 NSManagedObject類的時候,就需要仔細對待這種替換。在這種情形下,self就要指向兩個對象:一個是 alloc

返回的對象,一個是 [super init]返回的對象。修改 self 的值對代碼有一定的影響:每次訪問實例數(shù)據(jù)的時候都是隱式的。正如下面的代

碼所示:

@interface B : A {

    int i;

}

@end


@implementation B

-(id) init {

    // 此時,self 指向 alloc返回的值

    // 假設(shè) A 進行了替換操作,返回一個不同的

    self id newSelf = [super init];

    NSLog(@"%d", i); //輸出 self->i 的值

    self = newSelf; //有人會認為 i 沒有變化

    NSLog(@"%d", i); //事實上,此時的 self->i, 實際是 newSelf->i,

    // 和之前的值可能不一樣了

    return self;

}

@end

...

B* b = [[B alloc] init];

self = [super init] 簡潔明了,也不必擔心以后會引入 bug。然而,我們應該注意舊的 self指向的對象的命運:它必須被釋放。第一規(guī)則

很簡單:誰替換 self指針,誰就要負責處理舊的 self指針。在這里,也就是 [superinit]負責完成這一操作

29、初始化錯誤

初始化出錯可能發(fā)生在三個地方:

1. 調(diào)用 [super init...]之前:如果構(gòu)造函數(shù)參數(shù)非法,那么初始化應該立即停止;

2. 調(diào)用 [super init...]期間:如果父類調(diào)用失敗,那么當前的初始化操作也應該停止;

3. 調(diào)用 [super init...]之后:例如資源分配失敗等。

在上面每一種情形中,只要失敗,就應該返回 nil;相應的處理應該由發(fā)生錯誤的對象去完成。這里,我們主要關(guān)心的是1, 3情況。要釋放當

前對象,我們調(diào)用 [self release]即可。

30、在調(diào)用 dealloc之后,對象的析構(gòu)才算完成。因此,dealloc的實現(xiàn)必須同初始化方法兼容。事實上,alloc將所有的實例數(shù)據(jù)初始化成 0

是相當有用的。

@interface A : NSObject {

    unsigned int n;

}

-(id) initWithN:(unsigned int)value;

@end

@implementation A

-(id) initWithN:(unsigned int)value {

    // 第一種情況:參數(shù)合法嗎?

    if (value == 0) //我們需要一個正值

    {

        [self release];

        return nil;

    }

    // 第二種情況:父類調(diào)用成功嗎?

    if (!(self = [super init])) //即是 self 被替換,它也是父類

        return nil; //錯誤發(fā)生時,誰負責釋放 self?

    // 第三種情況:初始化能夠完成嗎?

    n = (int)log(value);

    void* p = malloc(n); //嘗試分配資源

    if (!p) // 如果分配失敗,我們希望發(fā)生錯誤

    {

        [self release];

        return nil;

    }

}

@end

31、有三種方法可以增加引用計數(shù)器,也就意味著僅僅有有限種情況下才要使用release釋放對象:

使用 alloc顯式實例化對象;

使用 copy[WithZone:]或者 mutableCopy[WithZone:]復制對象(不管這種克隆是偽);

使用 retain retainretainretain。

32、直接指定(完整代碼)

-(void) setString:(NSString*)newString {

    // 沒有強鏈接,舊值被改變了

    self->string = newString; //直接指定

}

33、使用 retain指定(完整代碼)

// ------ 不正確的實現(xiàn) ------

-(void) setString:(NSString*)newString

{

    self->string = [newString retain];

    // 錯誤!內(nèi)存泄露,沒有引用指向舊的"string",因此再也無法釋放

}

-(void) setString:(NSString*)newString

{

    [self->string release];

    self->string = [newString retain];

    // 錯誤!如果 newString == string(這是可能的),

    // newString引用是 1,那么在 [self->string release]之后

    // 使用 newString 就是非法的,因為此時對象已經(jīng)被釋放

}

-(void) setString:(NSString*)newString

{

    if (self->string != newString)

        [self->string release]; //正確:給 nil 發(fā)送 release是安全的

    self->string = [newString retain]; //錯誤!應該在 if 里面

    // 因為如果 string == newString,

    // 計數(shù)器不會被增加

}

// ------ 正確的實現(xiàn) ------

// 最佳實踐:C++程序員一般都會"改變前檢查"

-(void) setString:(NSString*)newString

{

    // 僅在必要時修改

    if (self->string != newString) {

        [self->string release]; //釋放舊的

        self->string = [newString retain]; // retain新的

    }

}

// 最佳實踐:自動釋放舊值

-(void) setString:(NSString*)newString

{

    [self->string autorelease]; //即使 string == newString也沒有關(guān)系,

    // 因為 release 是被推遲的

    self->string = [newString retain];

    //... 因此這個 retain 要在 release之前發(fā)生

}

// 最佳實踐:先 retain在 release

-(void) setString:(NSString*)newString

{

    [self->newString retain]; //引用計數(shù)器加 1(除了 nil)

    [self->string release]; // release時不會是 0

    self->string = newString; //這里就不應該再加 retain 了

}

34、復制(完整代碼)

無論是典型的誤用還是正確的解決方案,都和前面使用 retain指定一樣,只不過把retain換成 copy。

35、當返回實例數(shù)據(jù)指針時,外界就可以很輕松地修改其值。這可能是很多 getter不希望的結(jié)果,因為這樣一來就破壞了封裝性。

@interface Button

{

    NSMutableString* label;

}

-(NSString*) label;

@end

@implementation Button

-(NSString*) label

{

    return label; //正確,但知道內(nèi)情的用戶可以將其強制轉(zhuǎn)換成NSMutableString,

    // 從而改變字符串的值

}

-(NSString*) label

{

    // 解決方案 1 :

    return [NSString stringWithString:label];

    // 正確:實際返回一個新的不可變字符串

    // 解決方案 2 :

    return [[label copy] autorelease];

    // 正確:返回一個不可變克隆,其值是一個 NSString(注意不是 mutableCopy)

}

@end

36、循環(huán)retain

必須緊身避免出現(xiàn)循環(huán) retain。如果對象 A retain對象 B,B和 C 相互 retain,那么B和 C 就陷入了循環(huán) retain:

A → B←→ C

如果 A release B,B不會真正釋放,因為 C 依然持有 B。C也不能被釋放,因為 B 持有 C。因為只有 A能夠引用到 B,所以一旦 A release B,就再也沒有對象能夠引用這個循環(huán),這樣就不可避免的造成內(nèi)存泄露。這就是為什么在一個樹結(jié)構(gòu)中,一般是父節(jié)點 retain 子節(jié)點,而子節(jié)點不 retain父節(jié)點。

37、如果開啟垃圾收集器,retain、release和 autorelease 都被重定義成什么都不做

38、異常處理

Objective-C 中使用 @try…@catch…@finally

Cocoa 中有一個 NSException類,推薦使用此類作為一切異常類的父類。因此,catch(NSException *e)相當于 C++ 的 catch(…)。

39、線程安全

@synchronized

由 @synchronized(…)包圍的塊會自動加鎖,保證一次只有一個線程使用。在處理并發(fā)時,這并不是最好的解決方案,但卻是對大多數(shù)關(guān)鍵塊的最簡單、最輕量、最方便的解決方案

@implementation MyClass

-(void) criticalMethod:(id) anObject {

    @synchronized(self) {

        // 這段代碼對其他 @synchronized(self) 都是互斥的

        // self 是同一個對象

    }

    @synchronized(anObject) {

        // 這段代碼對其他 @synchronized(anObject) 都是互斥的

        // anObject是同一個對象

    }

}

@end

40、字符串

Objective-C 中唯一的 static對象

41、如果沒有給出屬性的參數(shù),那么將使用默認值;否則將使用給出的參數(shù)值。這些參數(shù)值可以是:

readwrite(默認)或者readonly:設(shè)置屬性是可讀寫的(擁有g(shù)etter/setter)或是只讀的(只有g(shù)etter);

assign(默認),retain或copy:設(shè)置屬性的存儲方式;

nonatomic:不生成線程安全的代碼,默認是生成的(沒有atomic關(guān)鍵字);

getter=…,setter=…:改變訪問器默認的名字。

42、對于 setter,默認行為是 assign;retain或者 copy 用于數(shù)據(jù)成員被修改時的操作。

43、RTTI(Run-TimeTypeInformation)

RTTI 即運行時類型信息,能夠在運行的時候知道需要的類型信息。

對象在運行時獲取其類型的能力稱為內(nèi)省。

class, superclass, isMemberOfClass, isKindOfClass

conformsToProtocol

respondsToSelector, instancesRespondToSelector

    相關(guān)評論

    閱讀本文后您有什么感想? 已有人給出評價!

    • 8 喜歡喜歡
    • 3 頂
    • 1 難過難過
    • 5 囧
    • 3 圍觀圍觀
    • 2 無聊無聊

    熱門評論

    最新評論

    發(fā)表評論 查看所有評論(0)

    昵稱:
    表情: 高興 可 汗 我不要 害羞 好 下下下 送花 屎 親親
    字數(shù): 0/500 (您的評論需要經(jīng)過審核才能顯示)
    推薦文章

    沒有數(shù)據(jù)