《Effective Objective-C 2.0》第二份讀書筆記

聲明:這個(gè)筆記的系列是我每天早上打開電腦第一件做的事情瞳步,當(dāng)然使用的時(shí)間也不是很多因?yàn)檫€有其他的事情去做蟀给,雖然吧自己買了紙質(zhì)的書但是做筆記和看的時(shí)候基本都是看的電子版本冰评,一共52個(gè)Tip每一個(gè)Tip的要點(diǎn)我是完全謄寫下來(lái)的纫普,害怕自己說(shuō)的不明白所以就謄寫也算是加強(qiáng)記憶峭弟,我會(huì)持續(xù)修改把自己未來(lái)遇到的所有相關(guān)的點(diǎn)都加進(jìn)去攀芯,最后希望讀者尊重原著屯断,購(gòu)買正版書籍。PS:不要打賞要喜歡~

GitHub代碼網(wǎng)址侣诺,大大們給個(gè)鼓勵(lì)Star啊殖演。

整個(gè)系列筆記目錄

《Effective Objective-C 2.0》第一份讀書筆記
《Effective Objective-C 2.0》第二份讀書筆記
《Effective Objective-C 2.0》第三份讀書筆記

第四章 協(xié)議與分類

23.通過(guò)委托與數(shù)據(jù)源協(xié)議進(jìn)行對(duì)象間通信

我舉一個(gè)~ 獲取網(wǎng)絡(luò)數(shù)據(jù)的類含有一個(gè)“委托對(duì)象”,在獲取完數(shù)據(jù)之后年鸳,它會(huì)回調(diào)這個(gè)委托對(duì)象趴久。

數(shù)據(jù)結(jié)束委托通知示意圖.png

EOCDataModel對(duì)象就是EOCNetworkFetcher的委托對(duì)象。EOCDataModel請(qǐng)求EOCNetworkFetcher“以異步方式執(zhí)行一項(xiàng)任務(wù)”搔确,而EOCNetworkFetcher在執(zhí)行完這項(xiàng)任務(wù)之后彼棍,就會(huì)通知其委托對(duì)象,也就是EOCDataModel膳算。

這里面代理要用weak修飾座硕。通常情況下,因?yàn)榇韉elegate要對(duì)比TableView做相應(yīng)的操作涕蜂,所以代理delegate要持有TableView這個(gè)對(duì)象华匾,而如果我們用Strong修飾TableView的delegate屬性,就會(huì)引入保留環(huán)(retain cycle)机隙。

如果要在委托對(duì)象上調(diào)用可選方法蜘拉,那么必須提前使用類型信息查詢方法判斷這個(gè)委托對(duì)象是否響應(yīng)相關(guān)選擇子。

NSData * data ;
if([_delegate  respondsToSelector:@selector(networkFetcher: didReceiveData:)]){
    [_delegate  networkFetcher: didReceiveData:];
}

委托模式: 對(duì)象把應(yīng)該對(duì)某個(gè)行為的責(zé)任委托給另一個(gè)類有鹿。
以TableView為例子
委托模式是信息從類流向受委托者也就是讓這個(gè)責(zé)任流向了受委托者旭旭。
數(shù)據(jù)源模式(Data Source Pattern)是數(shù)據(jù)流向TableView,決定TableView的布局印颤。

寫一個(gè)現(xiàn)實(shí)中的例子吧您机。(通過(guò)協(xié)議代理哈,我知道這個(gè)方案更好的方案,只不過(guò)想寫出來(lái)下協(xié)議代理的步驟)际看。(詳細(xì)見第二十三條Demo)咸产。
加入我想通過(guò)一個(gè)類開啟定時(shí)器,然后另一個(gè)類來(lái)監(jiān)控這個(gè)類的定時(shí)器仲闽,當(dāng)這個(gè)定時(shí)器開啟5S之后脑溢,相應(yīng)的做一些事情,首先是被監(jiān)視定時(shí)器的那個(gè)類:

//.h
#import <Foundation/Foundation.h>
@class Thirtyeight;
//首先是協(xié)議代理方式
typedef void(^iSuCompletionHandle)(int five);
@protocol iSuNetworkFetcherDelegate <NSObject>

- (void)netwrokFecher:(Thirtyeight *)networkFetcher didFinishWithData:(int)five;

@end
@interface Thirtyeight : NSObject

@property (nonatomic,weak) id<iSuNetworkFetcherDelegate> delegate;
@property (nonatomic,strong) NSTimer * iSuTimer;
@property (nonatomic,assign)  int iSuNumber;
@property (nonatomic,copy) iSuCompletionHandle iSuCompletion;
- (void)TimerTest;
@end
//.m
@implementation Thirtyeight
- (void)TimerTest{
    self.iSuNumber = 0;
    
  //這個(gè)Block我寫著玩的赖欣,實(shí)際作用不大屑彻,只不過(guò)下面有一個(gè)關(guān)于block的問(wèn)題。
    __weak typeof(self) weakSelf = self;
    self.iSuCompletion = ^(int five) {
        __strong typeof(weakSelf) strongSelf = weakSelf;
        strongSelf.iSuNumber = five;
        NSLog(@"賦值給self.iSuNumber為%i",strongSelf.iSuNumber);
    };
    
    
    __block int num = 0;
    _iSuTimer =[NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
        __strong typeof(weakSelf) strongSelf = weakSelf;
        num++;
        NSLog(@"定時(shí)器里面的變化%d",num);

/*
這邊就是最重要的代碼了顶吮,也就是傳遞給監(jiān)聽對(duì)象數(shù)據(jù)社牲。
*/
        [strongSelf.delegate netwrokFecher:strongSelf didFinishWithData:num];
        if (num == 5) {
            
            strongSelf.iSuNumber = num;
            NSLog(@"現(xiàn)在的數(shù)值為:%d",strongSelf.iSuNumber);
//這邊調(diào)用block的時(shí)候,是不允許我們使用strong.iSuCompletion這樣的操作悴了。
            _iSuCompletion(num);
            [_iSuTimer invalidate];
        };
    }];
}

主動(dòng)監(jiān)聽類:

//.m
@implementation ThirtyeightViewController
interface ThirtyeightViewController ()<iSuNetworkFetcherDelegate>

- (void)netwrokFecher:(Thirtyeight *)networkFetcher didFinishWithData:(int)five{
//這樣就可以監(jiān)聽了搏恤。
    NSLog(@"現(xiàn)在行走的時(shí)間是多少:%d",five);
}
@end
要點(diǎn):
  • 委托模式為對(duì)象提供一套接口,使其可由此將相關(guān)事件告知其他對(duì)象湃交。
  • 將委托對(duì)象應(yīng)該支持的接口定義為協(xié)議熟空,在協(xié)議中把可能需要處理的事件定義成方法。
  • 當(dāng)某對(duì)象需要從另外一個(gè)對(duì)象中獲取數(shù)據(jù)時(shí)搞莺,可以使用委托模式息罗。這種情況下,該模式也成為“數(shù)據(jù)源協(xié)議(data source protocal)”
  • 若有必要才沧,可實(shí)現(xiàn)含有位段的結(jié)構(gòu)體迈喉,將委托對(duì)象是否響應(yīng)相關(guān)協(xié)議方法這一信息緩存到其中。

24.將類的實(shí)現(xiàn)代碼分散到便于管理的數(shù)個(gè)分類之中

分類功能是對(duì)類對(duì)相應(yīng)功能的整理糜工,使得整個(gè)類的條理更加清晰弊添,防止更多不需要的方法在頭文件中導(dǎo)入,影響系統(tǒng)性能捌木。
例如:

//.h
#import <Foundation/Foundation.h>

@interface EOCBengi : NSObject
@property (nonatomic, copy, readonly) NSString * firstName;
@property (nonatomic, copy, readonly) NSString * lastName;
@property (nonatomic, strong, readonly) NSArray * friends;

- (id)initWithFirstName:(NSString *)firstName andLastName:(NSString *)lastName;
@end

@interface EOCBengi(Friendship)

- (void)addFriend:(EOCBengi *)person;
- (void)removeFirend:(EOCBengi *)person;
- (BOOL)isFriendWith:(EOCBengi *)person;
@end

@interface EOCBengi(Work)

- (void)performDaysWork;
- (void)takeVacationFromWork;
@end

@interface EOCBengi(Play)

- (void)goToTheCinema;
- (void)goToSportsGame;
 
@end
//.m
#import "EOCBengi.h"

@implementation EOCBengi

@end

@implementation EOCBengi(Friendship)

@end

@implementation EOCBengi(Work)

@end

@implementation EOCBengi(Play)

@end

要點(diǎn):
  • 使用分類機(jī)制把類的實(shí)現(xiàn)代碼劃為易于管理的小塊。
  • 將應(yīng)該視為“私有”的方法歸為Private的分類中嫉戚,來(lái)隱藏實(shí)現(xiàn)細(xì)節(jié)刨裆。

25.總是為第三方類的分類名稱加前綴

分類機(jī)制通常用于向無(wú)源碼的既有類中新增功能。

要點(diǎn):

  • 向第三方類中添加分類時(shí)彬檀,總應(yīng)給其名稱加上你專用的前綴帆啃。
  • 向第三方磊中添加分類時(shí),總應(yīng)給其中的方法加上你專用的前綴窍帝。

26.勿在分類中聲明屬性

盡管在技術(shù)上講努潘,分類中也是可以聲明屬性的,但這種做法還是要盡量避免的。原因在于疯坤,除了"class-continuation分類"之外报慕,其他分類都無(wú)法向類中新增實(shí)例變量,因此压怠,它們無(wú)法把實(shí)現(xiàn)屬性所需的實(shí)例變量合成出來(lái)眠冈。

如果在分類中聲明了屬性,我們可以通過(guò)運(yùn)行期關(guān)聯(lián)對(duì)象的方式get set數(shù)值菌瘫,但是這樣容易引起內(nèi)存問(wèn)題蜗顽。因?yàn)槲覀冊(cè)跒閷傩詫?shí)現(xiàn)存取方法時(shí),經(jīng)常會(huì)忘記遵守從內(nèi)存管理語(yǔ)義雨让,那么有可能在不經(jīng)意之間就造成了內(nèi)存出現(xiàn)錯(cuò)誤雇盖。(當(dāng)然這個(gè)錯(cuò)誤是自己可以解決的)。

#import <objc/runtime.h>
static const char * kFriendsPropertyKey = “kFriendPropertyKey”
@implemetation EOCPerson(Friendship)

(NSArray*)friends(
     return objc_getAssociatedObject(self, kFriendsPropertyKey);
)

(void)setFriends:(NSArray*)friends{
      objc_setAssociatedObject(self , kFriendsPropertyKey , friends,OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
要點(diǎn)
  • 把封裝數(shù)據(jù)所用的全部屬性都定義在主接口里栖忠。
  • 在”class - continuation分類” 之外的其他分類中崔挖,可以定義存取方法,但盡量不要定義屬性娃闲。

27.使用“class- continuation分類“ 隱藏實(shí)現(xiàn)細(xì)節(jié)

編寫的準(zhǔn)則是

  @interface EOCPerson ()
  //Methods here
   @end 

這個(gè)就是正常的我們創(chuàng)建的.m上面的東西虚汛,就是class- continuation類的延續(xù)。

要點(diǎn):
  • 通過(guò)“ class-continuation分類”向類中新增實(shí)例變量皇帮。
  • 如果某屬性在主接口聲明為“只讀”卷哩,而類的內(nèi)部又要設(shè)置方法修改此屬性,那么就在“calss-continuation分類’中將其擴(kuò)展為“可讀寫”属拾。
  • 把私有方法的原型聲明在“calss-continuation分類”里面。
  • 若要使類所遵循的協(xié)議不被人知道渐白,則可用“class-continuation分類”中聲明尊浓。

28.通過(guò)協(xié)議提供匿名對(duì)象

匿名對(duì)象:以內(nèi)聯(lián)形式所創(chuàng)建出來(lái)的無(wú)名類。
這個(gè)匿名對(duì)象具體表象就是:

@property (nonatomic ,weak) id <EOCDelegate> delegate;

由于該屬性類型是id<EOCDelegate>纯衍,所以實(shí)際上任何類的對(duì)象都能充當(dāng)這一屬性栋齿,即使這個(gè)類不集成與NSObject也是可以的,只要遵守協(xié)議<EOCDelegate>就好了襟诸。相同例子還有字典的存儲(chǔ)瓦堵,我們知道字典對(duì)于key是copy而對(duì)于值為保留的:

- (void)setObject:(id)object forKey:(id<NSCopying>)key;
要點(diǎn):
  • 協(xié)議可在某個(gè)程度上提供匿名類型。具體的對(duì)象類型可以淡化成遵從某協(xié)議的id類型歌亲,協(xié)議里規(guī)定了對(duì)象所實(shí)現(xiàn)的方法菇用。
  • 使用匿名對(duì)象來(lái)隱藏類型名稱(或類名)
  • 如果具體類型不重要,重要的是對(duì)象能夠響應(yīng)(定義在協(xié)議里的)特定方法陷揪,那么可使用匿名對(duì)象來(lái)表示惋鸥。

第五章 內(nèi)存管理

29.理解引用計(jì)數(shù)

在引用計(jì)數(shù)的架構(gòu)下杂穷,每個(gè)對(duì)象都一個(gè)計(jì)數(shù)器,NSObject協(xié)議聲明了下面三個(gè)方法用于操作計(jì)數(shù)器卦绣,以遞增或遞減其值耐量。

Retain 遞增保留計(jì)數(shù)
release 遞減保留計(jì)數(shù)
autorelease 待稍后清理“自動(dòng)釋放池(autorelease pool)”時(shí),再遞減保留計(jì)數(shù)迎卤。

NSMutableArray  * array = [NSMutableArray alloc] init];
NSNumber * number =[NSNumber alloc] initWithInt:1223];
[array  addObject:number];
[number release];
[array release];

如果我們不走[array release]方法拴鸵,那么我們知道number對(duì)象還是會(huì)存在的,因?yàn)閿?shù)組還在持有他蜗搔,但是絕對(duì)不應(yīng)該假設(shè)對(duì)象一定存在劲藐,也就是說(shuō),不要這樣寫代碼:

NSNumber * number = [NSNumber alloc] initWithInt:1337];
[array addObject:number];
[number release];
NSLog(@“ number = %@”,number);

如果我們調(diào)用了release之后樟凄,基于某些原因聘芜,其保留計(jì)數(shù)可能降至0.
為了避免在不經(jīng)意間使用了無(wú)效對(duì)象,一般調(diào)用玩realse之后都會(huì)清空指針缝龄。這就保證了不會(huì)出現(xiàn)可能指向無(wú)效對(duì)象的指針汰现。這種指針通常稱為懸掛指針。比如:

NSNumber * number = [NSNumber  alloc] initWithInt:1337];
[array  addObject:number];
[number release];
number = nil;

不管是數(shù)組叔壤,其他的對(duì)象也可以保留別的對(duì)象瞎饲,這一般都是用過(guò)“屬性”來(lái)實(shí)現(xiàn)。會(huì)用到相關(guān)實(shí)例變量的獲取方法及設(shè)置方法炼绘。若屬性為“strong關(guān)系(string relationship)”嗅战,那么設(shè)置的屬性就會(huì)保留,比方說(shuō)俺亮,有一個(gè)屬性為foo

 - (void)setFoo:(id ) foo {
     [foo retain];
     [_foo release];
     _foo = foo;
}

此方法將保留新值并釋放舊值驮捍,然后更新實(shí)例變量,令其指向新值脚曾。順序很重要东且。加入還未保留新值就先將舊值釋放了,而且兩個(gè)值又指向同一個(gè)對(duì)象本讥,那么珊泳,先執(zhí)行的release操作就可能導(dǎo)致喜用將對(duì)象永久回收。而后續(xù)的retain操作則無(wú)法令這個(gè)已經(jīng)徹底回收的對(duì)象復(fù)生拷沸,于是實(shí)例變量就變成了懸掛指針旨椒。

自動(dòng)釋放池
調(diào)用release會(huì)立刻遞減對(duì)象的保留計(jì)數(shù),然而有些時(shí)候不能可以不調(diào)用release堵漱,改調(diào)用autorelease,此方法會(huì)在稍后遞減計(jì)數(shù)涣仿,通常是在下一次“事件循環(huán)(event loop)時(shí)遞減勤庐,不過(guò)也可能執(zhí)行的更早些”示惊。
此特性很有用,尤其在方法中返回對(duì)象時(shí)更應(yīng)該用它愉镰,在這種情況下:

(NSString*)stringValue{
    NSString * str =[NSString alloc] initWithFormat:@“I am this:%@,self”];
     return str;
}

這個(gè)時(shí)候返回的str對(duì)象比期望的要多1 因?yàn)檎{(diào)用 alloc 會(huì)加1米罚,但是不會(huì)有對(duì)應(yīng)的釋放操作,但是不能在方法內(nèi)部釋放 str,否則沒等方法返回系統(tǒng)就把該方法回收了丈探。這里應(yīng)該用autorelease,它會(huì)稍后釋放對(duì)象录择,從而給調(diào)用者留下足夠長(zhǎng)的時(shí)間,使其可以在需要時(shí)先保留返回?cái)?shù)值碗降,換句話就是保證對(duì)象在跨越“方法調(diào)用邊界(method call boundary)”后一定存活隘竭。

(NSString *)stringValue{
    NSString * str =[NSString  alloc] initWithFormat:@“I am this %@”,self];
    return [str autorelease];
}

保留環(huán)(retain cycle)
就是相互持有

要點(diǎn):
  • 引用計(jì)數(shù)機(jī)制通過(guò)可以遞增遞減的計(jì)數(shù)器來(lái)管理內(nèi)存,對(duì)象創(chuàng)建好之后讼渊,其保留計(jì)數(shù)至少為1动看。若保留計(jì)數(shù)為正,則對(duì)象繼續(xù)存活爪幻。當(dāng)保留計(jì)數(shù)降為0的時(shí)菱皆,對(duì)象就被銷毀了。
  • 在對(duì)象聲明周期中挨稿,其余對(duì)象通過(guò)引用來(lái)保留或釋放此對(duì)象仇轻,保留與釋放操作分別會(huì)遞增或者遞減保留計(jì)數(shù)。

30. 以ARC簡(jiǎn)化引用計(jì)數(shù)

Clang編譯器自帶一個(gè)“靜態(tài)分析器(static analyzer)” 奶甘。用于指明程序里引用計(jì)數(shù)出問(wèn)題的地方篷店。

由于ARC會(huì)自動(dòng)執(zhí)行retain,release甩十,autorelease等操作船庇,所以不能直接調(diào)用retain,release,autorelease,dealloc 。
將內(nèi)存管理語(yǔ)義在方法命中表示出來(lái)早就成了OC的慣例侣监,而ARC則將之確立為硬性規(guī)定鸭轮。這些規(guī)則簡(jiǎn)單的體現(xiàn)在方法名上。若方法名以下列語(yǔ)句開頭橄霉,則其返回的對(duì)象鬼調(diào)用者所有
alloc 窃爷,new ,copy 姓蜂,mutableCopy
對(duì)于ARC和MRC的轉(zhuǎn)換:
ARC:

_myPerson = [EOCPerson  personWithName:@“Bob Smith”];

MRC:

EOCPerson * tmp = [EOCPerson  personWithName:@“Bob Smith”];
_myPerson = [tmp retain];

ARC可以在運(yùn)行期檢測(cè)到這一對(duì)多余的操作按厘,也就是autorelease及緊跟其后的retain。為了優(yōu)化代碼钱慢,在方法中返回自動(dòng)釋放的對(duì)象時(shí)逮京,要執(zhí)行一個(gè)特殊函數(shù)。此時(shí)不直接調(diào)用對(duì)象的autorelease方法束莫,而是改用調(diào)用objc_autoreleaseReturnValue懒棉。此函數(shù)會(huì)檢視當(dāng)前方法之后即將要執(zhí)行的那段代碼草描。若發(fā)現(xiàn)那段代碼要在返回的對(duì)象上執(zhí)行retain操作,則設(shè)置全局?jǐn)?shù)據(jù)結(jié)構(gòu)中的一個(gè)標(biāo)志位策严,而不執(zhí)行autorelease操作穗慕。

如果返回一個(gè)自動(dòng)釋放的對(duì)象,而調(diào)用方法的代碼中保留此對(duì)象妻导,那么此時(shí)不執(zhí)行retain,而改成objc_retainAutoreleasedReturnValue函數(shù)逛绵。此函數(shù)要檢測(cè)剛才提到的那個(gè)標(biāo)志位,若已經(jīng)執(zhí)行retain操作倔韭。設(shè)置并檢測(cè)標(biāo)志位术浪。要比調(diào)用autorelease和retain更快。

要點(diǎn):
  • 有ARC之后狐肢,程序員就無(wú)須擔(dān)心內(nèi)存管理問(wèn)題添吗。使用ARC來(lái)變成,可省去類中很多的“樣板代碼”份名。
  • ARC管理對(duì)象生命期的辦法基本上就是:在合適的地方插入”保留“及”釋放“操作碟联。在ARC環(huán)境下,變量的內(nèi)存管理語(yǔ)義可以通過(guò)修飾符指明僵腺,而原來(lái)則需要手動(dòng)執(zhí)行“保留”及“釋放”操作鲤孵。
  • 由方法所返回的對(duì)象,其內(nèi)存管理語(yǔ)義總是通過(guò)方法名來(lái)體現(xiàn)辰如。ARC將此確定為開發(fā)者必須遵守的規(guī)則普监。
  • ARC只負(fù)責(zé)管理Object-C對(duì)象的內(nèi)存。尤其要注意:CoreFoundation對(duì)象不歸ARC管理琉兜,開發(fā)者必須適時(shí)調(diào)用CFRetain/CFRelease凯正。

31.在dealloc方法中釋放引用并解除監(jiān)聽

如果手動(dòng)管理引用計(jì)數(shù)的話 dealloc中需要調(diào)用 [super dealloc] 而ARC中則不需要調(diào)用[super dealloc]。

要點(diǎn):
  • 在dealloc方法里豌蟋,應(yīng)該做的事情就是釋放指向其他對(duì)象的引用廊散,并取消原來(lái)訂閱的“鍵值觀察“(KVO)或NSNotificationCenter等通知 ,不要做其他的事情梧疲。
  • 如果對(duì)象持有文件描述符等系統(tǒng)資源允睹,那么應(yīng)該專門編寫一個(gè)方法來(lái)釋放此種資源。這樣的類要和其使用者約定:用完資源后必須調(diào)用close方法幌氮。
  • 執(zhí)行異步任務(wù)的方法不應(yīng)在dealloc里調(diào)用缭受;只能在正常狀態(tài)下執(zhí)行的那些方法也不應(yīng)在dealloc里調(diào)用,因此此時(shí)對(duì)象已處于正在回收的狀態(tài)下该互。

32.編寫“異常安全代碼”時(shí)留意內(nèi)存管理問(wèn)題

OC的錯(cuò)誤模型表示米者,異常只有在發(fā)生了嚴(yán)重錯(cuò)誤(21條詳解)的時(shí)候才會(huì)被拋出。
這個(gè)Tip里面我們研究MRC情況下怎么實(shí)現(xiàn)異常處理內(nèi)存宇智,就像C++那樣的塘雳。
我們使用try塊實(shí)現(xiàn)這個(gè)功能:
@finally的作用在于無(wú)論是否拋出異常都會(huì)走這一步陆盘,因?yàn)槲覀儾磺宄绦驎?huì)不會(huì)在dosomeThing中拋出異常,如果拋出異嘲苊鳎可能會(huì)影響下面的動(dòng)作。

    @try {
        ThirtyTwo * object =[[ThirtyTwo alloc]init];
        [object dosomeThing];
        // [object release];
    } @catch (NSException *exception) {
        NSLog(@"拋出異常");
    } @finally {
        // [object release];
    }
要點(diǎn):
  • 捕捉異常時(shí)太防,一定要注意try塊內(nèi)創(chuàng)立的對(duì)象清理干凈妻顶。
  • 在默認(rèn)情況下,ARC不生成安全處理異常所需的清理代碼蜒车。開啟編譯器標(biāo)志后讳嘱,可生成這種代碼,不會(huì)導(dǎo)致應(yīng)用程序變大酿愧,而且降低運(yùn)行效率沥潭。

33.以弱引用避免保留環(huán)

強(qiáng)引用:

#import <Foundation/Foundation.h>

@class EOCClassA;
@class EOCClassB;

@interface EOCClassA :NSObject
@property (nonatomic, strong) EOCClassB * other;
@end 

@interface EOCClassB :NSObject
@porperty (nonatomic, strong) EOCClassA * other;
@end

避免保留環(huán)的最佳方式就是弱引用,用weak或者是unsafe_unretained即可嬉挡。

要點(diǎn):
  • 將某些引用設(shè)置為weak,可避免出現(xiàn)“保留環(huán)”钝鸽。
  • weak引用可以自動(dòng)清空,也可以不自動(dòng)清空庞钢。自動(dòng)清空是隨著ARC而引入的新特性拔恰,由運(yùn)行期系統(tǒng)來(lái)實(shí)現(xiàn)。在具備自動(dòng)清空的弱引用上基括,可以隨意讀取其數(shù)據(jù)颜懊,因?yàn)檫@種引用不會(huì)指向已經(jīng)回收過(guò)的對(duì)象。

34.以“自動(dòng)釋放池塊”降低內(nèi)存峰值

創(chuàng)建自動(dòng)釋放池的方法如下:

@autoreleasepool {

}

當(dāng)數(shù)據(jù)量過(guò)大的時(shí)候我們可以通過(guò)嵌套自動(dòng)釋放池的方法來(lái)降低內(nèi)存峰值风皿。

NSArray * databaseRecorde = /******/;
NSMutableArray * people = [NSMutableArray  new];
for (NSDictionary * record  in  databaseRecords){
  
     @autoreleasepool {
              EOCPerson  * person = [[EOCPerson alloc] initWithRecord:record]; 
               [person  addObject: person];
         }
}

自動(dòng)釋放池機(jī)制就像“棧(stack)”一樣河爹。系統(tǒng)創(chuàng)建好自動(dòng)釋放池之后,就將其推入棧中桐款,而清空自動(dòng)釋放池咸这,則相當(dāng)于將其從棧中彈出。在對(duì)象上執(zhí)行自動(dòng)釋放操作鲁僚,就等于將其放入棧頂?shù)哪莻€(gè)池里炊苫。

之前MRC的時(shí)候有一個(gè)創(chuàng)建釋放池的類NSAutoreleasePool 此對(duì)象更加重量級(jí)(heavyweight) 通常用來(lái)創(chuàng)建偶爾需要清空的池,比方說(shuō):

NSArray * databasRecode = /****/
NSMutableArray  * people = [NSMutableArray new];
int i = 0 ;

NSAutoreleasePool * pool = [NSAutoreleasePool  alloc] init ];
for (NSDictionary  * record  in  databaseRecode ){
        EOCPerson  * person = [EOCPerson  alloc] initWithRecord:record];
        [people  addobject:person];
       
       if (++i  == 10){
       [pool  drain];
          i = 0;
         }
}
[pool  drain];

是否應(yīng)該用池來(lái)優(yōu)化效率冰沙,完全取決于具體的應(yīng)用程序侨艾。首先得監(jiān)控內(nèi)存用量,判斷其中有沒有需要解決的問(wèn)題拓挥,如果沒完成這一步唠梨,那就別急著優(yōu)化。盡管自動(dòng)釋放池塊的開銷不太大侥啤,但畢竟還是有的当叭,所以盡量不要建立額外的自動(dòng)釋放池茬故。

要點(diǎn):
  • 自動(dòng)釋放池排布在棧中,對(duì)象受到autorelease消息后蚁鳖,系統(tǒng)將其放入最頂端的池里磺芭。
  • 合理運(yùn)用自動(dòng)釋放池,可降低應(yīng)用程序的內(nèi)存峰值醉箕。
  • @autoreleasepool 這種新式寫法能創(chuàng)建出更為輕便的自動(dòng)釋放池钾腺。

35.用“僵尸對(duì)象”調(diào)用內(nèi)存管理問(wèn)題

僵尸對(duì)象:?jiǎn)?dòng)這項(xiàng)調(diào)試成功之后,運(yùn)行期系統(tǒng)會(huì)把所有已經(jīng)回收的實(shí)例轉(zhuǎn)化為特殊的“僵尸對(duì)象(Zombie Object)”讥裤,而不會(huì)真正回收他們放棒。這樣就使得我們能夠及時(shí)定位到錯(cuò)誤位置。
打開全局?jǐn)帱c(diǎn)和僵尸對(duì)象調(diào)試功能有兩種方法:
第一種方法:

僵尸對(duì)象第一種生成方法.png

點(diǎn)擊"+"選擇Exception Breakpoint己英。

第二種方法:
點(diǎn)擊上方調(diào)試開關(guān)右邊的程序管理臺(tái)间螟,選擇Edit Scheme。

Edit Scheme位置.png

然后選擇Run - > Diagnostics - > Zombie Objects损肛。

僵尸對(duì)象第二種生成方法.png
要點(diǎn):
  • 系統(tǒng)在回收對(duì)象時(shí)厢破,可以不將其真的回收,而是把它轉(zhuǎn)化為僵尸對(duì)象荧关。通過(guò)環(huán)境變量NSZombieEnabled可開啟此功能溉奕。
  • 系統(tǒng)會(huì)修改對(duì)象的isa指針,令其指向特殊的僵尸類忍啤,從而使該對(duì)象變成僵尸對(duì)象加勤。僵尸類能夠響應(yīng)所有的選擇子,響應(yīng)方式為:打印一條包含消息內(nèi)容及其接收者的消息同波,然后終止應(yīng)用程序鳄梅。

36.不要使用retainCount

要點(diǎn):
  • 對(duì)象的保留計(jì)數(shù)看似有用,實(shí)則不然未檩,因?yàn)槿魏谓o定時(shí)間點(diǎn)上的“絕對(duì)保留計(jì)數(shù)(absolute retain count)”都無(wú)法反應(yīng)對(duì)象生命期的全貌戴尸。
  • 引入ARC之后,retainCount方法就正式廢止冤狡,在ARC下調(diào)用該方法會(huì)導(dǎo)致編譯器報(bào)錯(cuò)孙蒙。

結(jié)尾

自己寫的筆記首先是用Pages寫的,寫完之后放到簡(jiǎn)書里面以為也就剩下個(gè)排版了悲雳,結(jié)果發(fā)現(xiàn)基本上每一個(gè)點(diǎn)的總結(jié)都不讓自己滿意挎峦,但是又想早點(diǎn)放上去,總感覺自己被什么追趕著合瓢,哈哈坦胶,本來(lái)寫完筆記的時(shí)候是2W字的,結(jié)果到第二次發(fā)表的時(shí)候發(fā)現(xiàn)就成了2.5W了,需要改進(jìn)的東西還是太多顿苇,希望朋友們有什么改進(jìn)的提議都可以告訴我峭咒,我會(huì)一直補(bǔ)充這個(gè)筆記,然后抓緊改GitHub上的代碼~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市纪岁,隨后出現(xiàn)的幾起案子凑队,更是在濱河造成了極大的恐慌,老刑警劉巖蜂科,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件顽决,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡导匣,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門茸时,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)馁筐,“玉大人谣旁,你說(shuō)我怎么就攤上這事。” “怎么了沪摄?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)茉兰。 經(jīng)常有香客問(wèn)我泌参,道長(zhǎng),這世上最難降的妖魔是什么签杈? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任瘫镇,我火速辦了婚禮,結(jié)果婚禮上答姥,老公的妹妹穿的比我還像新娘铣除。我一直安慰自己,他們只是感情好鹦付,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布尚粘。 她就那樣靜靜地躺著,像睡著了一般敲长。 火紅的嫁衣襯著肌膚如雪郎嫁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天祈噪,我揣著相機(jī)與錄音泽铛,去河邊找鬼。 笑死钳降,一個(gè)胖子當(dāng)著我的面吹牛厚宰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼铲觉,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼澈蝙!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起撵幽,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤灯荧,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后盐杂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體逗载,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年链烈,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了厉斟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡强衡,死狀恐怖擦秽,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情漩勤,我是刑警寧澤感挥,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站越败,受9級(jí)特大地震影響触幼,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜究飞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一置谦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧噪猾,春花似錦霉祸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至坪蚁,卻和暖如春奔穿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背敏晤。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工贱田, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人嘴脾。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓男摧,卻偏偏與公主長(zhǎng)得像蔬墩,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子耗拓,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

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