《Effective Objective-C 2.0》—(第15-22條)—介面與API設計、深拷貝、淺拷貝

來源:互聯網
上載者:User

標籤:nscopying   深拷貝   錢拷貝   description   

第15條:用首碼避免命名空間衝突

Objective-C沒有其他語言內建的命名空間(namespace)機制。如果發生命名衝突程式串連時候,出現以下錯誤:

duplicate symbol _OBJC_METACLASS_$_EOCTheClass in:

build/something.o

build/something_else.o

duplicate symbol _OBJC_CLASS_$_EOCTheClass in:

build/something.o

build/something_else.o

錯誤的原因在於,應用程式中的兩份代碼都實現了EOCTheClass的類。避免此問題的唯一辦法變相命名空間。

在使用Cocoa建立應用程式的時候一定要注意,Apple宣稱其保留使用所有“兩個字母首碼”,所以你自己選用的首碼應該是三個或以上。


第16條:提供“全能初始化方法”第17條:實現description方法偵錯工具時,經常需要列印並查看對象資訊。一種辦法是編寫代碼把對象的全部屬性都輸出到日誌中。不過最常用的做法還是像下面這樣:
NSLog(@"object =%@",object);
如果object是NSArray那麼列印出來的就是數組所有內容,如果object是自訂的類對象,那麼結果確是記憶體位址。除非在自己類裡覆寫description方法。具體列印什麼欄位根據需要編寫。NSObject協議中還有個方法要注意那就是debugDescription,用於調試時候的輸出。例如:我們在控制台輸入po命令,輸出:EOCTest[640:c07] person = <EOCPerson: ox712ad0,"Bob Smith">請注意,控制台控制台“(EOCPerson*)$1=0x712a4d0”是由調試器添加的,後面的內容才是debugDescription返回的資訊,同理,如果你需要在調試的時候列印自訂類的更多資訊可以重寫debugDescription方法
第18條:盡量使用不可變對象設計類的時候,應充分運用屬性來封裝資料。而在使用屬性時,則可將其聲明為“唯讀”(read-only)。預設情況下屬性“既可讀又可寫”● 盡量建立不可變的對象● 若某屬性僅可於對象內部修改,則在“class-continuation分類”中將其由readonly屬性擴充為readwrite屬性● 不要把可變的collection作為屬性公開,而應提供相關方法,一次修改對象中的可變collection。
第19條:使用清晰而協調的命名方式NSString這個類就展示了良好的命名習慣。
● +string//用於建立新的Null 字元串● +stringWithString//Factory 方法,用於根據某字串建立新的字串● +localizedStringWithFormat://Factory 方法,格式化本地字串● -lowercaseString//把字串中的大寫字母全部轉化位小寫● -intValue//將字串解析為整數● -length//擷取字串長度● -lengthOfBytesUsingEncoding://若字串是以給定的編碼格式● -getCharacters:range://擷取字串給定範圍的字元● -(void)getCharacters:(unichar*)buffer range:(NSRange)aRange//首個參數應該指向一個足夠大的數組,以便容下請求範圍內的那些字串● -hasPrefix://是否有某個首碼● -isEqualToString://判斷字串是否相等


第20條:為私人方法名加首碼第21條:理解Objective-C錯誤模型NSError對象封裝了三條資訊:● Error domain(錯誤範圍,string)錯誤發生的範圍。也就是產生錯誤的根源,通常用一個特有的全域變數來定義。比如說:“處理URL的子系統”在從URL中解析擷取得資料時候,如果出錯了,那麼就會使用NSURLErroeDomain來表示錯誤範圍。● Error code(錯誤碼,int)● User info(使用者資訊,dictionary)在錯誤不那麼嚴重的情況下,可以指派“委託方法”來處理錯誤,也可以把錯誤資訊放到NSError對象裡,經由“輸出參數”返回給調用者。第22條:理解NSCopying協議使用對象時經常需要拷貝它。在Objective-C中,此操作通過copy方法完成。如果想令自己的類支援拷貝操作,那麼就要實現NSCopying協議,該協議只有一個方法:
-(id)copyWithZone:(NSZone*)zone
為何會出現NSZone呢?因為以前開發程式時,會根據把記憶體分成不同的“區”(zone),而對象會建立在某個去裡面。現在不用了,每隔程式只有一個區:“預設區”。所以說,儘管去實現這個方法,但是你不必擔心其中的zone參數
#import<Foundation/Foundation.h>@interface EOCPerson :NSObject<NSCopying>@propetry (nonatomic,copy,readonly) NSString *firstName;@propetry (nonatomic,copy,readonly) NSString *lastName;-(id) initWithFirstName:(NSString*)firstName andLastName:(NSString*)lastName;-(void)addFriend:(EOCPerson*) person;-(void)removeFriend:(EOCPerson*)person;@end@implementation EOCPerson{NSMutableSet *_friends;}-(id) initWithFirstName:(NSString*)firstName andLastName:(NSString*)lastName{    if((self = [super init])){        _firstName = [firstName copy];        _lastName = [lastName copy];        _friends = [NSMutableSet new];    }    return self}-(void)addFriend:(EOCPerson*)person{    [_friends addObject:person];}-(void) removeFriend:(EOCPerson*)person{    [_friends removeObject:person];}-(id)copyWithZone:(NSZone)zone{    EOCPerson *copy =[[[self class]allocWithZone:zone] initWithFirstName:_firstName andLastName:_lastName];    copy->_friends = [_friends mutableCopy];    return copy}@end
copyWithZone實現了1. copy 一份EOCPerson,2. 它把本地的_friends執行個體變數複製了一份,令copy對象的_friends執行個體變數指向這個複製過的set。注意,這裡使用->文法,因為_friends並非屬性。如果_friends是不可變的數組,則不需要複製一份。    在編寫拷貝方法時,還要決定一個問題,就是應該“深拷貝”還是“淺拷貝”。深拷貝的意思就是:在拷貝對象自身時,將底層資料也一併複製過去。Foundation架構中的所有collection類在預設情況下都執行錢拷貝,也就是說,只拷貝容器物件本身,而不複製其中的資料。對於容器類
以NSSet為例,該類提供了下面的初始化方法,用以執行深拷貝
-(id)initWithSet:(NSArray*)array copyItems:(BOOL)copyItems
因為沒有專門定義深拷貝的協議,所以其具體執行方式由每個類來決定,你只需要決定自己所寫的類是否要提供深拷貝方法即可。對於非容器類的copy以NSString為例
   // 非容器類對象    NSString *str = @"origin string";    NSString *strCopy = [str copy];    NSMutableString *mstrCopy = [str mutableCopy];    [mstrCopy appendString:@"??"];
str和strCopy指向的是同一塊記憶體地區(淺拷貝),我們稱之為弱引用(weak reference)。而mstrCopy是真正的複製(深拷貝)
 NSMutableString *mstr = [NSMutableString stringWithString:@"origin"];    NSString *strCopy = [mstr copy];    NSMutableString *mstrCopy = [mstr copy];    NSMutableString *mstrMCopy = [mstr mutableCopy];    //[mstrCopy appendString:@"1111"];  //error    [mstr appendString:@"222"];    [mstrMCopy appendString:@"333"];
以上四個對象所分配的記憶體都是不一樣的。而且對於mstrCopy,它所指向的其實是一個imutable對象,是不可改變的,所以會出錯。這點要注意,好好理解。
對於非容器類對象,有:
● 如果對一個不可變對象複製,copy是指標複製,即淺拷貝;而mutableCopy則是對象複製,即深拷貝。
● 如果是對可變對象複製,都是深拷貝,但copy複製返回的對象是不可變的。

【本章要點】

● 若想令自己寫的對象具有拷貝功能,則需要實現NSCopying協議。● 如果自訂的對象分為可變版本與不可變版本,那麼就要同時實現NSCopying與NSMutableCopying協議。● 複製對象時需要決定採用淺拷貝還是深拷貝,盡量執行淺拷貝。● 如果你所寫的對象需要深拷貝,那麼可以考慮新增一個專門執行深拷貝的方法。
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.