《EffectiveObjective-c 2.0》第三章 接口與API設(shè)計(jì)

第15條:用前綴避免命名空間沖突

  1. 選擇與你的公司场仲,應(yīng)用程序或二者皆有關(guān)聯(lián)之名稱作為類名的前綴萌丈,并在所有代碼中使用這以前綴赎瞎,包括純C函數(shù)及全局變量撵渡。前綴應(yīng)該以三個(gè)大寫字母為前綴融柬,用前綴還有一個(gè)好處,就是有些app在混淆代碼的時(shí)候趋距,很方便快捷的混淆自己的iOS代碼粒氧。
  2. 若自己開發(fā)的應(yīng)用程序需要為其他程序提供插件支持,那么自己的開發(fā)的應(yīng)用程序中使用到的第三方插件也需要修改其前綴节腐。
  3. 此條看到了一個(gè)符號表外盯,此表的功能是顯示iOS文件的文件名,函數(shù)名翼雀,行數(shù)等饱苟。由此找到騰訊的Bugly插件,此插件可以在iOSAPP發(fā)布后狼渊,如果APP發(fā)生crash箱熬,或是卡頓等問題,可以及時(shí)查看到問題,定位問題很準(zhǔn)確城须,且還有解決方案蚤认。
    參考地址Bugly

第16條:提供“全能初始化方法”

  1. 對于提供多個(gè)初始化方法的類,應(yīng)該提供一個(gè)全能的初始化方法糕伐,其他初始化方法以此方法為基礎(chǔ)進(jìn)行擴(kuò)展砰琢。
    2 在全能初始化方法里進(jìn)行存儲數(shù)據(jù)等,如果有存儲機(jī)制改變等原有只需修改全能初始化方法即可良瞧。
  2. 若全能初始化方法與超類不同氯析,則需覆寫超類中的對應(yīng)方法。--強(qiáng)調(diào)對應(yīng)的方法莺褒,不是亂調(diào)用方法掩缓。
  3. 如果超類的初始化方法不適用于子類,那么應(yīng)該覆寫這個(gè)超類方法遵岩,并在其中拋出異常你辣。

第17條:實(shí)現(xiàn)description方法

  1. 實(shí)現(xiàn)decription方法返回一個(gè)有意義的字符串,用以描述該實(shí)例尘执。
  2. 若想在調(diào)試時(shí)打印更詳盡的對象描述舍哄,則應(yīng)實(shí)現(xiàn)debugDescription方法。

第18條:盡量使用不可變對象

  1. 在公共接口中(.h文件)聲明屬性的時(shí)候誊锭,盡量使用不可變對象表悬。
  2. 在公共接口中,集合使用不可變對象時(shí)丧靡,盡量使用readonly特征修飾蟆沫,且提供相應(yīng)的增加移除方法,并重寫屬性的get方法温治。

情況一

.h文件

@interface WCCPerson : NSObject
@property (nonatomic, copy) NSString *myName;
@property (nonatomic, copy, readonly)NSArray *friends;

- (instancetype)initWithName:(NSString *)myName;
@end

@interface NSArray (WCCPerson)
- (NSString *)toString;
@end

.m文件

@interface WCCPerson ()
@property (nonatomic, copy, readwrite)NSArray *friends;//將對外的屬性中的readonly饭庞,改成readwrite
@end

@implementation WCCPerson

- (instancetype)initWithName:(NSString *)myName{
    if (self = [super init]) {
        _myName = [myName copy];
       _friends = @[@"json", @"mike"];
    }
    return self;
}

- (NSArray *)friends{
    return _friends;
}

@end

@implementation NSArray (WCCPerson)
- (NSString *)toString{
    NSMutableString *string = [NSMutableString string];
    for (NSUInteger i = 0; i < [self count]; i++) {
        [string appendFormat:@"array[%lu] value is %@, ", (unsigned long)i, self[i]];
    }
    return [string copy];
}
@end

如果按照上面的寫法也是可以的,對象內(nèi)部操作_friends屬性熬荆,對象內(nèi)部對屬性進(jìn)行賦值舟山,只允許外部獲取。但這樣有一些問題卤恳,如果用戶使用如下方式累盗,則該寫法有些漏洞。

WCCPerson *person = [[WCCPerson alloc] initWithName:@"wencun"];
    NSArray *array = @[@1, @2];
    [person setValue:array forKey:@"friends"];
//    person.friends =
    NSLog(@"%@",person.friends.toString);

//輸出
2017-08-18 11:46:09.011585+0800 WCCTestProj[11807:270808] array[0] value is 1, array[1] value is 2,

雖然這樣并不合法突琳,但用戶一旦這樣操作若债,那么將不可避免。
用戶也可能直接用類型信息查詢功能查出屬性所對應(yīng)的實(shí)例變量在內(nèi)存布局中的偏移量本今,以此來認(rèn)為設(shè)置這個(gè)實(shí)例變量的值拆座。這種也不符合規(guī)范主巍。

情況二

.h文件

@interface WCCPerson : NSObject
@property (nonatomic, copy) NSString *myName;
@property (nonatomic, copy, readonly)NSArray *friends;

- (instancetype)initWithName:(NSString *)myName;
- (void)addFriends:(NSArray *)objects;
- (void)removeFriends:(NSArray *)objects;
@end

@interface NSArray (WCCPerson)
- (NSString *)toString;
@end

.m文件

@interface WCCPerson (){
    NSMutableArray *mutableFriends;
}
//@property (nonatomic, copy, readwrite)NSArray *friends;
@end

@implementation WCCPerson

- (instancetype)initWithName:(NSString *)myName{
    if (self = [super init]) {
        _myName = [myName copy];
        mutableFriends = [NSMutableArray new];
    }
    return self;
}

- (void)addFriends:(NSArray *)objects{
    [mutableFriends addObject:objects];
}

- (void)removeFriends:(NSArray *)objects{
    [mutableFriends removeObject:objects];
}

- (NSArray *)friends{
    return [mutableFriends copy];
}
@end

這種寫法可以避免使用setValue:forKey:設(shè)置后,獲取到自己設(shè)置的值挪凑,因?yàn)槿绻皇褂脤ο筇峁┑姆椒?code>addFriends:孕索,是獲取不到用戶自己設(shè)置的正確的值的,這種情況就迫使用戶使用對象提供的方法來設(shè)置值躏碳。
也可以減少用戶對屬性的操作搞旭,起到封裝屬性的作用了。

第19條:使用清晰而協(xié)調(diào)的命名方式

屏幕快照 2017-08-18 15.13.45.png

第20條:為私有方法名加前綴

  1. 給私有方法的名稱加上前綴菇绵,這樣可以很容易地將其同公共方法區(qū)分開
  2. 不要單用一個(gè)下劃線做私有方法的前綴肄渗,因?yàn)檫@種做法是預(yù)留給蘋果公司的。

第21條:理解Object-C錯(cuò)誤模型

  1. 只有發(fā)生了可使整個(gè)應(yīng)用程序崩潰的嚴(yán)重錯(cuò)誤時(shí)咬最,才應(yīng)使用異常翎嫡。此時(shí)無須考慮恢復(fù)的問題,而且應(yīng)用程序此時(shí)也應(yīng)該退出永乌。也就是說不用再編寫“異常安全”代碼了惑申。
id someResource = nil;
    if (1) {
        @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"參數(shù)異常" userInfo:@{}];
    }
    [someResource release];
  1. 在錯(cuò)誤不那么嚴(yán)重的情況下,可以指派“委托方法”(delegate method)來處理錯(cuò)誤翅雏,也可以把錯(cuò)誤信息放在NSError對象里圈驼,經(jīng)由“輸出參數(shù)”返回給調(diào)用者。
  • 在設(shè)計(jì)API時(shí)望几,NSError的第一種常見的用法是通過委托協(xié)議來傳遞此錯(cuò)誤的绩脆,有錯(cuò)誤發(fā)生時(shí),當(dāng)前對象會把錯(cuò)誤信息經(jīng)由協(xié)議中的某個(gè)方法傳遞給委托對象(delegate)橄抹。如下靴迫,NSURLConnection在委托協(xié)議中NSURLConnectionDelegate中定義了如下方法。
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
  • NSError的另外一種常見的用法是:經(jīng)由方法的“輸出參數(shù)”返回給調(diào)用者害碾,如下:
    .h文件
    - (BOOL)doSomething:(NSError *__autoreleasing *)error;

    .m文件

- (BOOL)doSomething:(NSError *__autoreleasing *)error{
    NSLog(@"我在這里了doSomething");
    if (error) {
        *error = [NSError errorWithDomain:NSURLErrorKey code:0 userInfo:@{@"error":@"你錯(cuò)啦....."}];
        return NO;
    }
    return YES;
}

使用ARC時(shí)矢劲,編譯器會把方法簽名中的NSError **轉(zhuǎn)換成NSError *__autoreleasing *,也就是說,指針?biāo)傅膶ο髸诜椒▓?zhí)行完畢后自動(dòng)釋放慌随,這個(gè)對象必須自動(dòng)釋放,因?yàn)樵摲椒ǖ恼{(diào)用者躺同,不能保證他自己會釋放掉此方法創(chuàng)建的NSError,所以必須加入autorelase阁猜。
當(dāng)error為nil時(shí),如果不加判斷會報(bào)錯(cuò)蹋艺。

第22條:理解NSCopying協(xié)議

  1. 若想令自己所寫的對象具有拷貝功能剃袍,則需要實(shí)現(xiàn)NSCopying協(xié)議。
  2. 如果自定義的對象分為可變版本和不可變版本捎谨,那么就要同時(shí)實(shí)現(xiàn)NSCopying與NSMutableCopying協(xié)議民效。
  3. 復(fù)制對象時(shí)需要決定采用深拷貝還是淺拷貝憔维,一般情況下應(yīng)該盡量執(zhí)行淺拷貝。
  4. 如果你所寫的對象需要深拷貝畏邢,那么可考慮新增一個(gè)專門執(zhí)行深拷貝的方法业扒。
    文中一段說:深拷貝的意思是:在拷貝對象自身時(shí),將其底層數(shù)據(jù)也一并復(fù)制過去舒萎。Foundation框架中的所有collection類在默認(rèn)情況下都執(zhí)行淺拷貝程储,也就是說,只拷貝容器對象本身臂寝,而不復(fù)制其中的數(shù)據(jù)章鲤。這樣做的主要原因在于,容器內(nèi)的對象未必都能拷貝咆贬,而且調(diào)用者也未必想在拷貝容器時(shí)一并拷貝其中的每個(gè)對象败徊。
    NSMutableArray *element = [[NSMutableArray alloc] initWithObjects:@"1", nil];
    NSMutableArray *mutableArray = [[NSMutableArray alloc] initWithObjects:element, nil];
//此處復(fù)制過后,確實(shí)指針變成新的了掏缎,似乎是產(chǎn)生了一個(gè)新對象集嵌。
    NSMutableArray *copyMutableArray = [mutableArray mutableCopy];
    NSLog(@"element is %p,mutableArray is %p,copyMutableArray is %p",element, mutableArray, copyMutableArray);
    NSLog(@"element is %@,mutableArray is %@,copyMutableArray is %@",element, mutableArray, copyMutableArray);
//此處復(fù)制后,三個(gè)變量的值都變了
    [element addObject:@"2"];
    NSLog(@"============");
    NSLog(@"element is %p,mutableArray is %p,copyMutableArray is %p",element, mutableArray, copyMutableArray);
    NSLog(@"element is %@,mutableArray is %@,copyMutableArray is %@",element, mutableArray, copyMutableArray);

輸出結(jié)果

2017-08-21 11:49:39.730755+0800 WCCTestProj[1678:161529] element is 0x600000443f90,mutableArray is 0x6000004443b0,copyMutableArray is 0x600000443ff0
2017-08-21 11:49:39.730991+0800 WCCTestProj[1678:161529] element is (
    1
),mutableArray is (
        (
        1
    )
),copyMutableArray is (
        (
        1
    )
)
2017-08-21 11:49:39.731094+0800 WCCTestProj[1678:161529] ============
2017-08-21 11:49:39.731186+0800 WCCTestProj[1678:161529] element is 0x600000443f90,mutableArray is 0x6000004443b0,copyMutableArray is 0x600000443ff0
2017-08-21 11:49:39.731402+0800 WCCTestProj[1678:161529] element is (
    1,
    2
),mutableArray is (
        (
        1,
        2
    )
),copyMutableArray is (
        (
        1,
        2
    )
)

參考集合collection的copy和mutableCopy是淺拷貝

點(diǎn)擊進(jìn)入 第四章

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末御毅,一起剝皮案震驚了整個(gè)濱河市根欧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌端蛆,老刑警劉巖凤粗,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異今豆,居然都是意外死亡嫌拣,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進(jìn)店門呆躲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來异逐,“玉大人,你說我怎么就攤上這事插掂』艺埃” “怎么了?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵辅甥,是天一觀的道長酝润。 經(jīng)常有香客問我,道長璃弄,這世上最難降的妖魔是什么要销? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮夏块,結(jié)果婚禮上疏咐,老公的妹妹穿的比我還像新娘纤掸。我一直安慰自己,他們只是感情好浑塞,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布借跪。 她就那樣靜靜地躺著,像睡著了一般缩举。 火紅的嫁衣襯著肌膚如雪垦梆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天仅孩,我揣著相機(jī)與錄音托猩,去河邊找鬼。 笑死辽慕,一個(gè)胖子當(dāng)著我的面吹牛京腥,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播溅蛉,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼公浪,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了船侧?” 一聲冷哼從身側(cè)響起欠气,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎镜撩,沒想到半個(gè)月后预柒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡袁梗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年宜鸯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片遮怜。...
    茶點(diǎn)故事閱讀 40,680評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡淋袖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出锯梁,到底是詐尸還是另有隱情即碗,我是刑警寧澤,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布涝桅,位于F島的核電站拜姿,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏冯遂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一谒获、第九天 我趴在偏房一處隱蔽的房頂上張望蛤肌。 院中可真熱鬧壁却,春花似錦、人聲如沸裸准。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽炒俱。三九已至盐肃,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間权悟,已是汗流浹背砸王。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留峦阁,地道東北人谦铃。 一個(gè)月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像榔昔,于是被迫代替她去往敵國和親驹闰。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內(nèi)容