筆記2

?OC的動(dòng)態(tài)性:會(huì)把編譯和鏈接是需要執(zhí)行的邏輯延遲到運(yùn)行時(shí),例如使用 id 所修飾的變量會(huì)在運(yùn)行的時(shí)候才確定具體類型是什么,runtime 的方法交換等。


循環(huán)引用:當(dāng)一個(gè)對(duì)象間接或直接地持有另一個(gè)對(duì)象,而這個(gè)對(duì)象又有強(qiáng)指針指向該對(duì)象,就會(huì)引起循環(huán)應(yīng)用無法釋放的問題。

1.block的使用 使用 weakSelf處理

2.delegate 作為屬性用weak修飾,也可以防止野指針的出現(xiàn)

3.NSTimer 最為成員變量。解決方式

在程序中除了在 dealloc方法去明確使用 invalid 然后賦值為nil

如果無法明確知道什么時(shí)候才可以停止,可以添加了一個(gè)類別讓原來的通過@selector執(zhí)行任務(wù)的方式轉(zhuǎn)換為block的方式。

+ (NSTimer *)xx_scheduledTimerWithTimeInterval:(NSTimeInterval)interval

block:(void(^)())block

repeats:(BOOL)repeats

{

return [self scheduledTimerWithTimeInterval:interval

target:self

selector:@selector(xx_blockInvoke:)

userInfo:[block copy]

repeats:repeats];

}

+ (void)xx_blockInvoke:(NSTimer *)timer {

void (^block)() = timer.userinfo;

if(block) {

block();

}

}

然后當(dāng)控制釋放的時(shí)候,停止定時(shí)器就可以

-(void)dealloc{

NSLog(@"dealloc");

[self.timer invalidate];

self.timer = nil;

NSLog(@"timer:%@",self.timer);

}


屬性修飾

assign:基本數(shù)據(jù)類型,結(jié)構(gòu)體

weak:delegate(野指針,循環(huán)引用),IB引進(jìn)來的UI控件(視圖層級(jí)結(jié)構(gòu))

copy:不可變類型(指向不同對(duì)象),block(保證是放在堆上)

strong:修飾對(duì)象,強(qiáng)引用

retain:和strong類似,在修飾block的時(shí)候作用相當(dāng)于assign


類別作用:

在保持原有類的情況下,增加其方法(UIScrollView,圖片緩存裁剪處理)

講一個(gè)龐大的類根據(jù)作用分解到不同的類別中,便于維護(hù)


static修飾的變量并不會(huì)改變作用范圍,改變的只是內(nèi)存分配方式(存放在靜態(tài)區(qū)在整個(gè)運(yùn)行期間一直存在)


數(shù)據(jù)持久化:原理都是數(shù)據(jù)保存到本地文件中

1.屬性列表:一般使用NSUserDefaults操作(沙盒l(wèi)ibrary/preference)

2.對(duì)象歸檔:將對(duì)象轉(zhuǎn)化為NSData寫入帶本地文件,對(duì)象需要實(shí)現(xiàn)NSCoding協(xié)議

[NSKeyedArchiver archiveRootObject:self toFile:fileName];

3.SQLite3:FMDB封裝庫

4.Core Data:對(duì)SQLite基于面向?qū)ο蟮姆庋b


棧區(qū)(stack)由編譯器自動(dòng)分配釋放,存放方法(函數(shù))的參數(shù)值,局部變量的值等,是一塊連續(xù)的內(nèi)存的區(qū)域。即棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預(yù)先規(guī)定好的。

堆區(qū)(heap)一般由程序員分配釋放,是不連續(xù)的內(nèi)存區(qū)域,從而堆獲得的空間比較靈活。有我們?nèi)ew/alloc來創(chuàng)建的對(duì)象,就是放在堆下面。


棧區(qū)(stack)由編譯器自動(dòng)分配釋放,存放方法(函數(shù))的參數(shù)值,局部變量的值等,是一塊連續(xù)的內(nèi)存的區(qū)域。即棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預(yù)先規(guī)定好的。

堆區(qū)(heap)一般由程序員分配釋放,是不連續(xù)的內(nèi)存區(qū)域,從而堆獲得的空間比較靈活。有我們?nèi)ew/alloc來創(chuàng)建的對(duì)象,就是放在堆下面。


結(jié)構(gòu)體:

struct CGPoint {

CGFloat x;

CGFloat y;

};

typedef struct CGPoint CGPoint;


TableViewCell \ 頁面優(yōu)化:

1.盡量減少透明圖層的使用來減少渲染次數(shù),opaque = YES

2.減少對(duì)象的創(chuàng)建或者使用更為輕的對(duì)象,如當(dāng)視圖元素不需要響應(yīng)用戶的觸摸事件使用CALayer代替UIView

3.當(dāng)大量文字需要顯示,cpu需要耗費(fèi)比較多的資源去進(jìn)行渲染和排版,所以這個(gè)時(shí)候可以選擇CoreText 來處理

4.避免大圖使用,程序解碼比較耗時(shí)

5.復(fù)雜布局使用autoLayout會(huì)影響性能,更好的是選擇手動(dòng)布局

6.使用CoreGraphics進(jìn)行繪制的時(shí)候,如果繪制比較耗時(shí),可以異步處理后再返回主線程顯示

7.TableViewCell的重用,避免在heightForCell方法進(jìn)行較多的處理,將動(dòng)態(tài)高度的緩存

7.離屏渲染(系統(tǒng)會(huì)在屏幕緩沖外開辟新的緩沖去處理),設(shè)置shadow時(shí)候不設(shè)置shadowPath,在設(shè)置圓角不同時(shí)使用 maskToBound和cornerRdius有時(shí)會(huì)導(dǎo)致,或者使用CAShapeLayer 和BezierPath結(jié)合的的方式繪制圓角。

7.如果不需要要顯示透明圖層,那么將試圖的opaque設(shè)置為YES(默認(rèn)),會(huì)讓系統(tǒng)會(huì)將試圖作為不透明去處理而加快渲染。

但如果需要使用到透明,則設(shè)置為NO。

8.減少視圖的層級(jí)結(jié)構(gòu)

4.可以根據(jù)需要是使用預(yù)加載或者延遲加載。

8.使用Instrument工具去檢測


線程加鎖 : 解決多線程同時(shí)訪問同一資源導(dǎo)致的問題,一般通過加鎖處理或者使用串行隊(duì)列處理:

//串行隊(duì)列

dispatch_queue_create("", DISPATCH_QUEUE_SERIAL), ^ {

}

1.GCD信號(hào)量

+(NSString*)getContacts{

//獲取通訊錄權(quán)限

ABAuthorizationStatus authStatus = ABAddressBookGetAuthorizationStatus();

if(authStatus != kABAuthorizationStatusAuthorized)

{

//是否有通訊錄權(quán)限

__block BOOL accessGranted = NO;

ABAddressBookRef tmpAddressBook = ABAddressBookCreateWithOptions(NULL,NULL);

dispatch_semaphore_t sema=dispatch_semaphore_create(0);//創(chuàng)建信號(hào)量 為0

ABAddressBookRequestAccessWithCompletion(tmpAddressBook, ^(bool granted,CFErrorRef error){

accessGranted = granted;

dispatch_semaphore_signal(sema);//信號(hào)量 +1

});

//當(dāng)信號(hào)量 > 0 才繼續(xù)運(yùn)行,并且信號(hào)量 - 1

dispatch_semaphore_wait( sema, DISPATCH_TIME_FOREVER);

if(accessGranted ==NO){

return @"[]";

}

}

//讀取聯(lián)系人----------此處省略聯(lián)系人讀取步驟-------------------}


2.NSLock *lock = [NSLock alloc]init];

[lock lock];

.....

[lock unlock];


3.條件鎖(基于信號(hào)量)

NSConditionLock *conditionLock = nil;

BOOL canLock = [conditionLock tryLockWhenCondition:kCondition_A];

if (canLock) {

FDLog(@"線程A lock, 請(qǐng)等待");

[conditionLock unlock];

}else{

FDLog(@"線程A 條件不滿足,未加lock");

}


4.NSRecursiveLock 遞歸鎖,同一個(gè)線程可以多次加鎖,但是不會(huì)引起死鎖,如果是NSLock,則會(huì)導(dǎo)致崩潰

- (void)reverseDebug:(NSUInteger )num lock:(NSRecursiveLock *)lock

{

? ? ?[lock lock];

? ? if (num<=0) {

? ? ? ? ?FDLog(@"結(jié)束");

? ? ? ? ?return;

? ? }

? ? [self reverseDebug:num-1 lock:lock];//遞歸

? ? [lock unlock];//還是需要解鎖

}


5.@synchronized(self) { ? ? ? ?

? ? ? ...

}

6.atomic的線程安全只限于setter和getter方法。會(huì)在setter方法里面加鎖。


當(dāng)我們?nèi)?dòng) RunLoop,系統(tǒng)會(huì)自動(dòng)在內(nèi)部創(chuàng)建自動(dòng)釋放池。


數(shù)組遍歷

當(dāng)使用block的方式進(jìn)行遍歷,會(huì)阻塞線程,直到遍歷結(jié)束。




UIView的 drawRect,layoutSubviews 方法調(diào)用時(shí)機(jī):

兩者都是在視圖將要顯示(viewWillAppear之后,viewDidAppear之前調(diào)用,layoutSubviews只要addSubviews就可以調(diào)用,但是drawRect方法必須設(shè)置了frame才能調(diào)用,否則就不會(huì)被調(diào)用)

layoutSubviews

1、init初始化不會(huì)觸發(fā)layoutSubviews。

2、addSubview會(huì)觸發(fā)layoutSubviews

3、設(shè)置view的Frame會(huì)觸發(fā)layoutSubviews,當(dāng)然前提是frame的值設(shè)置前后發(fā)生了變化

4、滾動(dòng)一個(gè)UIScrollView會(huì)觸發(fā)layoutSubviews

5、旋轉(zhuǎn)Screen會(huì)觸發(fā)父UIView上的layoutSubviews事件

6、改變一個(gè)UIView大小的時(shí)候也會(huì)觸發(fā)父UIView上的layoutSubviews事件

7、調(diào)用setNeedsLayout(延時(shí)到下個(gè)更新周期調(diào)用)


drawRect(在調(diào)用前會(huì)先調(diào)用sizeToFit方法,可以再這個(gè)方法計(jì)算坐標(biāo)處理)

1.在UIView初始化時(shí)設(shè)置rect大小,drawRect 就會(huì)自動(dòng)調(diào)用(在視圖將要顯示時(shí)候調(diào)用,只調(diào)用一次,viewDidLoad兩方法之后掉用的),否則不被自動(dòng)調(diào)用。

2.調(diào)用setNeedsDisplay(異步執(zhí)行)


layoutSubviews:UIView 需要對(duì)子控件進(jìn)行手動(dòng)的布局,則可以重寫此方法。只有在autoresizing和constraint-based behaviors of subviews不能提供我們想要的布局結(jié)果的時(shí)候,我們才應(yīng)該重寫此方法。

layoutSubviews方法調(diào)用先于drawRect



MVC優(yōu)點(diǎn):

體現(xiàn)在低藕性與重用性:

數(shù)據(jù)層與視圖層的互相獨(dú)立,可單獨(dú)地對(duì)某一模塊進(jìn)行改變,而不會(huì)影響到其余模塊,也可以根據(jù)實(shí)際需要靈活地重用各個(gè)模塊。



NSOperation與GCD區(qū)別:

GCD是基于C語言的一套api;而NSOperaion底層是基于GCD開發(fā),因此效率方面GCD更好。

而NSOperation更適用于一些復(fù)雜的任務(wù):

1.可以對(duì)隊(duì)列暫停,恢復(fù),取消操作(NSOperationQueue cancelAllOperations setSuspended),不過這里暫停并不是暫停當(dāng)前的任務(wù)而是下一個(gè)任務(wù),恢復(fù)會(huì)從第一個(gè)沒有執(zhí)行的任務(wù)開始。

2.可以建立任務(wù)間的依賴關(guān)系(NSOperation setDependency)

3.NSBlockOperation NSInvocationOperation可以設(shè)置任務(wù)的優(yōu)先級(jí)(setQueuePriority),

而GCD只可以設(shè)置隊(duì)列的優(yōu)先級(jí).



TCP三次握手:

客戶端向服務(wù)端發(fā)送請(qǐng)求 - 服務(wù)端返回?cái)?shù)據(jù)包給客戶端 - 客戶端返回響應(yīng)包給服務(wù)端,連接建立

TCP釋放連接四次握手:

客戶端向服務(wù)端發(fā)送斷開請(qǐng)求 - 服務(wù)端接收到請(qǐng)求后先返回響應(yīng)給客戶端,然后連接斷開后再返回一次數(shù)據(jù)包給客戶端- 客戶端收到服務(wù)端的返回,返回響應(yīng)給服務(wù)端。



9.CoreData多線程安全處理

CoreData包含(實(shí)體對(duì)象,模型對(duì)象,上下文,持久化存儲(chǔ)協(xié)調(diào)器)

線程注意點(diǎn):

1.manageObject,manageObjectContext只能在自己的線程處理,不能跨線程

2.對(duì)于持久化存儲(chǔ)協(xié)調(diào)器(NSPersistentStoreCoordinator)可以多線程共享

3.magageObject的線程間傳遞通過id,并且通過objectWithID來獲取

解決方法:

共同使用一個(gè) NSPersistentStoreCoordinator,以及兩個(gè)獨(dú)立的 Contexts,一個(gè)context 負(fù)責(zé)主線程與UI協(xié)作,一個(gè)context在后臺(tái)負(fù)責(zé)耗時(shí)的處理,用Notifications的方式通知主線程的NSManagedObjectContext進(jìn)行mergeChangesFromContextDidSaveNotification 對(duì)變化進(jìn)行合并處理。

//這個(gè)通知是系統(tǒng)定義的通知

[[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextDidSaveNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *note) {

if (note.object == self.privateContext) {

dispatch_async(dispatch_get_main_queue(), ^{

//返回主線程合并處理,這里的note.object不能再主線程進(jìn)行使用,需要合并處理

[self.mainContext performBlock:^{

[self.mainContext mergeChangesFromContextDidSaveNotification:note];

}];

});

}

}];




14.網(wǎng)絡(luò)安全:

1.為了防止非法使用api,在每次向服務(wù)器請(qǐng)求的使用,將appKey和加密后的appSecret也發(fā)送給服務(wù)器,服務(wù)器根據(jù)appKey找到對(duì)應(yīng)的appSecret與從客戶端傳遞過來進(jìn)行比對(duì),一致的話就是合法請(qǐng)求。(appkey 和 secret key相當(dāng)于當(dāng)前賬戶的另外一套賬號(hào)和密碼機(jī)制)

2.使用https協(xié)議。



82.常見的crash情況

1.訪問野指針,比如訪問一個(gè)已經(jīng)釋放的對(duì)象的屬性方法(解決方式是當(dāng)一個(gè)指針?biāo)赶虻膶?duì)象如果已被釋放,則將指針置nil)

2.訪問數(shù)組類對(duì)象越界或插入了空對(duì)象

3.訪問了不存在的方法

4.當(dāng)某個(gè)對(duì)象會(huì)被多個(gè)線程修改(加鎖處理)

5.NSNotification KVO的非對(duì)稱添加刪除(訪問野指針)


數(shù)據(jù)庫事務(wù)處理

當(dāng)我們對(duì)數(shù)據(jù)庫進(jìn)行更新操作時(shí),默認(rèn)會(huì)將操作一條條地往數(shù)據(jù)庫提交。而使用事務(wù)處理,則是將所有的操作一次性提交給數(shù)據(jù)庫,當(dāng)處理的過程中出現(xiàn)問題,則可以進(jìn)行回滾操作不進(jìn)行任何修改,保證數(shù)據(jù)的完整性。

所以當(dāng)需要對(duì)大量的數(shù)據(jù)進(jìn)行更新操作時(shí),使用事務(wù)在效率和安全性都會(huì)大大提高。



16.斷點(diǎn)續(xù)傳

//使用HEAD方法,僅獲取目標(biāo)文件的信息,而不做實(shí)際的下載工作。

//[request setHTTPMethod:@"HEAD"];

/**

設(shè)置斷點(diǎn)續(xù)傳的思路:

HeaderField:頭域(請(qǐng)求頭部的字段)

可以通過指定range的范圍逐步地下載指定范圍內(nèi)的數(shù)據(jù),待下載完成后,再將這些數(shù)據(jù)拼接成一個(gè)文件。

1根據(jù)HEAD方法獲取到要下載的文件的總大小、

2在磁盤上建立一個(gè)臨時(shí)的緩沖文件,該文件的大小與目標(biāo)文件大小一致


3緩沖文件中所有字節(jié)都是默認(rèn)為0

4開啟多線程,分別加載不同的range頭指定的數(shù)據(jù)塊,待數(shù)據(jù)塊加載完成以后,將其分別寫入對(duì)應(yīng)的偏移地址。

5所有數(shù)據(jù)下載完成以后,表示文件下載完成,將臨時(shí)文件名更改為目標(biāo)文件。

開發(fā)的難點(diǎn):

0在寫入文件之前,首先要建立一個(gè)同等大小的文件。

1文件的讀寫問題,在oc里默認(rèn)是覆蓋,追加,如果要指定位置,需要用seek方法,移動(dòng)文件指針。

2在多線程寫入文件時(shí),文件的鎖定操作是一個(gè)問題。

*/

[request setValue:@"bytes=0-499" forKeyPath:@"range"];//表di示只讀取數(shù)據(jù)的第0個(gè)字節(jié)到第499個(gè)字節(jié)。




線程間通信:

1.performSelectorOnMainThread,去主線程執(zhí)行

? ?performSelectorInBackground ,后臺(tái)線程執(zhí)行

2.通過NSMachPort端口

將端口添加到當(dāng)前線程的runloop里,通過這個(gè)端口與其他線程進(jìn)行消息的發(fā)送接收(通過delegate 來進(jìn)行消息接受的回調(diào),通過回調(diào)方法傳遞過來的參數(shù),獲取對(duì)方的端口,通過端口就可以發(fā)送消息)。

NSPort *myPort = [NSMachPort port];

//2. 設(shè)置port的代理回調(diào)對(duì)象myPort.delegate=self;

//3. 把port加入runloop,接收port消息

[[NSRunLoop currentRunLoop] addPort:myPort forMode:NSDefaultRunLoopMode];

- (void)handlePortMessage:(NSMessagePort*)message{

//

NSPort*localPort = [message valueForKeyPath:@"localPort"];

NSPort*remotePort = [message valueForKeyPath:@"remotePort"];

//使用端口發(fā)送消息

[remotePort sendBeforeDate:[NSDatedate]

msgid:kMsg2

components:nilfrom:localPort

reserved:0];

}



APP通信方式:

1.URL Scheme:App1通過openURL的方法跳轉(zhuǎn)到App2,并且在URL中帶上想要的參數(shù)(需要在info.plist中配置好URL types),常用于 分享到微信朋友圈微博等功能。

2.Keychain:微信登陸,使用同一個(gè)賬號(hào)平臺(tái),實(shí)現(xiàn)自動(dòng)登錄其他的平臺(tái)。每個(gè)程序都有一個(gè)獨(dú)立的keychain存儲(chǔ),只需要使用對(duì)應(yīng)的登錄SDK,通過共享keychain中的數(shù)據(jù),那么就可以實(shí)現(xiàn)統(tǒng)一賬戶登錄了。(比如密碼、證書等等,就需要使用更為安全的keychain了。keychain里保存的信息不會(huì)因App被刪除而丟失,在用戶重新安裝App后依然有效,數(shù)據(jù)還在。它是一個(gè)sqlite數(shù)據(jù)庫,其保存的所有數(shù)據(jù)都是加密過的。)

3.UIPasteboard(剪切板功能):在淘寶app中將鏈接自定義成淘口令,引導(dǎo)用戶進(jìn)行復(fù)制,并去QQ好友對(duì)話中粘貼。然后QQ好友收到消息進(jìn)行粘貼后后再打開自己的淘寶app,淘寶app每次從后臺(tái)切到前臺(tái)時(shí),就會(huì)檢查系統(tǒng)剪切板中是否有淘口令,如果有淘口令就進(jìn)行解析并跳轉(zhuǎn)到對(duì)于的商品頁面。



繪制方式:

1.使用 drawInContext drawRect 方法,方法會(huì)自動(dòng)創(chuàng)建畫布,只需要獲取上下文繪制。

2.手動(dòng)創(chuàng)建畫布

UIGraphicsBeginImageContext(CGSizeMake(400,400));

//獲取上下文

CGContextRef context =UIGraphicsGetCurrentContext();

//使用CG來繪制

CGFloat lineWidth = 2.f;

CGRect allRect =CGRectMake(0, 0, 100, 100);

CGRect circleRect =CGRectInset(allRect, lineWidth/2.f, lineWidth/2.f);

CGPointcenter =CGPointMake(20, 20);

[[UIColor blueColor]setStroke];

[[UIColor grayColor]setFill];

CGContextSetLineWidth(context, lineWidth);

//繪制

CGContextStrokeEllipseInRect(context, circleRect);

//使用beizer繪制

CGFloat startAngle = - ((float)M_PI/ 2.f);

// Draw progress

UIBezierPath*processPath = [UIBezierPath bezierPath];

processPath.lineCapStyle=kCGLineCapButt;

processPath.lineWidth= lineWidth * 2.f;

CGFloatradius = 30;

CGFloatendAngle = 30 + startAngle;

[processPath addArcWithCenter:centerradius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];

[[UIColor blackColor]set];

[processPath stroke];

//獲取繪制的圖片

UIImage* im =UIGraphicsGetImageFromCurrentImageContext();

//關(guān)閉上下文

UIGraphicsEndImageContext();

//將繪制的圖片顯示處理

UIImageView*imageView = [[UIImageViewalloc]initWithFrame:CGRectMake(50, 50, 200, 200)];

[self.view addSubview:imageView];

[imageView setImage:im];


socket長連接設(shè)計(jì)(AsyncSocket):

使用單例模式維持一個(gè)長連接,并且定時(shí)地向服務(wù)器發(fā)送心跳包來判斷是否在連接中,否則重新連接??蛻舳诵枰獧z測連接狀態(tài),通過delegate來對(duì)連接狀態(tài)進(jìn)行回調(diào),包括:正在連接,連接中,連接斷開,重新連接。并且提供對(duì)應(yīng)的方法讓用戶去進(jìn)行一些常用的操作,包括:開始連接,退出登錄后的斷開連接,消息的收發(fā)等


當(dāng)const修飾一個(gè)指針變量的時(shí)候,可以指定指針不可修掛,或者指針指向的數(shù)據(jù)不可修改

const int *a(數(shù)據(jù)不可修改,指針可以) ?int *const a(指針可修改,數(shù)據(jù)不可變)


UIView,UIViewController,UIApplication直接繼承自UIResponder,而UIWindow繼承自UIView,UIResponder 下面有對(duì)應(yīng)的響應(yīng)用戶觸摸的方法



watchdog超時(shí)機(jī)制:

當(dāng)應(yīng)用未能及時(shí)響應(yīng)用戶界面事件,如在主線程操作網(wǎng)絡(luò),文件操作等耗時(shí)操作導(dǎo)致程序卡主了,就會(huì)會(huì)殺死程序并生成watchdog超時(shí)日志。



38.觀察者模式:

是一種訂閱-發(fā)布模式??梢酝瑫r(shí)對(duì)一個(gè)對(duì)象進(jìn)行觀察,當(dāng)對(duì)象的狀態(tài)發(fā)生改變,觀察者就會(huì)接收到對(duì)應(yīng)的通知,他的優(yōu)點(diǎn)在于觀察者與消息發(fā)布者并不需要知道對(duì)方的細(xì)節(jié),只需要做好自己的業(yè)務(wù),并且觀察者的數(shù)量并沒有限制,是一種低藕的一對(duì)多的觀察方式。

在ios里典型的就是NSNotification和KVO,前者常用語系統(tǒng)的事件通知,如鍵盤事件,前后臺(tái)切換,或者模塊之間的通信。KVO就是對(duì)對(duì)象屬性的觀察。



struct class 區(qū)別:

struct可以繼承,可以多態(tài),可以定義函數(shù),和class最大區(qū)別在于變量class的默認(rèn)訪問控制是private,而struct默認(rèn)是public;對(duì)于對(duì)象內(nèi)存的管理有系統(tǒng)的回收機(jī)制處理,而 struct 定義的對(duì)象則是在使用完畢后自動(dòng)清理分配的內(nèi)存。

當(dāng)需要有大量的邏輯處理使用類,如果只是CGPoint,CGSize這些輕量結(jié)構(gòu),使用struct。



枚舉typedef NS_ENUM

使用情景:當(dāng)需要列舉的狀態(tài)有限的,并且數(shù)量不多(3-4左右),使用枚舉



沙盒機(jī)制(用來存放非代碼文件(圖片,音頻,視頻,屬性列表(plist), sqlite數(shù)據(jù)庫,文本文件,其他等等)):

Document文件夾用于保存程序運(yùn)行中需要?jiǎng)?chuàng)建的文件,如sqlite文件

Library Preferences:存放應(yīng)用的偏好設(shè)置(有系統(tǒng)維護(hù),不能直接去修改,需要通過NSUserDefault來添加偏好設(shè)置)

Cache:緩存文件夾,在程序退出后不會(huì)刪除(iTunes不會(huì)備份)

tmp:臨時(shí)文件夾(在文件使用結(jié)束后刪除),在手機(jī)重啟目錄文件會(huì)被刪除;在內(nèi)存底的情況下也可能會(huì)被刪除,不會(huì)被iTunes備份

.app文件包,應(yīng)用程序本身,不能去修改。

如果你做個(gè)記事本的app,那么用戶寫了東西,總要把東西存起來。那么這個(gè)文件則是用戶自行生成的,就放在documents文件夾里面。

如果你有一個(gè)app,需要和服務(wù)器配合,經(jīng)常從服務(wù)器下載東西,展示給用戶看。那么這些下載下來的東西就放在library/cache


//獲取沙盒主目錄路徑

NSString *homeDir = NSHomeDirectory();

//獲取Documents目錄路徑

NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];

//獲取Library的目錄路徑

NSString *libDir = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) firstObject];

//獲取Caches目錄路徑

NSString *cachesDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];

//獲取tmp目錄路徑

NSString *tmpDir =NSTemporaryDirectory();


進(jìn)程

ios中app的運(yùn)行是單進(jìn)程的,進(jìn)程是資源分配的基本單位,而線程是cpu調(diào)度的基本單位,是進(jìn)程中的一個(gè)實(shí)體。線程沒有獨(dú)立的存儲(chǔ)控件,進(jìn)程下的線程共享該進(jìn)程下的資源。

進(jìn)程間通信方式:

1.管道

2.消息隊(duì)列

3.socket

4.共享內(nèi)存(常用)



objc_msgForward消息轉(zhuǎn)發(fā)

當(dāng)我們在對(duì)一個(gè)對(duì)象發(fā)送消息的時(shí)候,運(yùn)行時(shí)調(diào)用objc_msgSend方法,根據(jù)累的分發(fā)表去尋找該方法,如果找不到就去父類找,如果依然找不到就會(huì)調(diào)用objc_msgForward進(jìn)行消息轉(zhuǎn)發(fā),首先它會(huì)嘗試去尋找在運(yùn)行的時(shí)候是否動(dòng)態(tài)地去實(shí)現(xiàn)了這個(gè)方法,如果沒有就去尋找有沒有其他的對(duì)象可以相應(yīng)該方法,如果仍然沒有,,則會(huì)調(diào)用forwardInvocation方法來來將消息轉(zhuǎn)發(fā)給其他的對(duì)象,如果以上三步都沒有處理掉就會(huì)跑出異常。

(_objc_msgForward是IMP類型,用于消息轉(zhuǎn)發(fā)的:當(dāng)向一個(gè)對(duì)象發(fā)送一條消息,但它并沒有實(shí)現(xiàn)的時(shí)候)


BAD_ACCESS在什么情況下出現(xiàn)?

訪問了野指針,比如訪問已經(jīng)釋放的對(duì)象的成員變量或者向他發(fā)消息

所以當(dāng)指針變量所指向的對(duì)象內(nèi)存被釋放掉后,需要對(duì)指針賦值為nil,防止產(chǎn)生“野指針”。



檢測UIViewController內(nèi)存泄漏的原理:

1、添加一個(gè)myDealloc方法并且在里面輸出對(duì)應(yīng)的信息,在類方法load 里實(shí)現(xiàn)默認(rèn)的dealloc 與自定義定位方法進(jìn)行方法交換,那么根據(jù)打印處理的信息,就可以判斷一個(gè)VC有沒有釋放掉。

2、利用ARC中weak變量不持有對(duì)象,并且在對(duì)象釋放時(shí)會(huì)自動(dòng)置為nil的特性,在適當(dāng)?shù)臅r(shí)候來檢測VC是否在內(nèi)存駐留。


Left Join[左聯(lián)結(jié)]

返回包括左表中的所有記錄和右表中聯(lián)結(jié)字段相等的記錄

Right Join[右聯(lián)結(jié)]

返回包括右表中的所有記錄和右表中聯(lián)結(jié)字段相等的記錄

Inner Join[等值聯(lián)結(jié)]

只返回兩個(gè)表中字段相等的行


sqlite優(yōu)化:

1.查詢優(yōu)化:索引建立(防止全文檢索,防止索引建立太多)

2.大量的更新操作:事務(wù)(效率,安全)

3.表的建立(靈活,字段設(shè)置)




網(wǎng)絡(luò)請(qǐng)求中如何提高性能

1.在于服務(wù)器交換的數(shù)據(jù)格式方面,gson要比xml效率高,如果使用xml那么在大量數(shù)據(jù)的情況下使用基于事件的解析方式要比dom樹的方式效率高

2.對(duì)請(qǐng)求響應(yīng)的數(shù)據(jù)進(jìn)行壓縮 gzip

3.對(duì)請(qǐng)求數(shù)據(jù)進(jìn)行緩存,可以使用系統(tǒng)默認(rèn)的NSURLCache 對(duì)GET請(qǐng)求進(jìn)行緩存,只需要在請(qǐng)求時(shí)設(shè)置好對(duì)應(yīng)的緩存策略。

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@""] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:3];

connection= [[NSURLConnection alloc] initWithRequest:request delegate:self];

[connection start];


ios 循環(huán)引用

1.計(jì)時(shí)器NSTimer,當(dāng)我使用計(jì)時(shí)器時(shí)候,內(nèi)部會(huì)有一個(gè)引用指向VC,導(dǎo)致VC我發(fā)釋放,dealloc不會(huì)被調(diào)用。

2.delegate

3.block



如果賦值沒有通過setter方法或者KVC,而是直接修改屬性對(duì)應(yīng)的成員變量,例如:僅調(diào)用_name = @"newName",這時(shí)是不會(huì)觸發(fā)kvo機(jī)制



KVO

typedef NS_OPTIONS(NSUInteger, NSKeyValueObservingOptions) {

NSKeyValueObservingOptionNew = 0x01,//改變后的值

NSKeyValueObservingOptionOld = 0x02,//改變前的值

NSKeyValueObservingOptionInitial NS_ENUM_AVAILABLE(10_5, 2_0) = 0x04, //addobserving之后會(huì)馬上調(diào)用observeValueForKeyPath,不會(huì)等到值改變

NSKeyValueObservingOptionPrior NS_ENUM_AVAILABLE(10_5, 2_0) = 0x08//分2次調(diào)用。在值改變之前和值改變之后

};

FOUNDATION_EXPORT NSString *const NSKeyValueChangeNewKey;

FOUNDATION_EXPORT NSString *const NSKeyValueChangeOldKey;

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {

if (context == (__bridge void*)self) {

if ([keyPath isEqualToString:kKeyPathForNavigationItemRightBarButtonItems]) {

//取值

NSArray *rightBarButtonItems = [change objectForKey:NSKeyValueChangeNewKey];

}

}

}

當(dāng)我們通過KVO對(duì)對(duì)象屬性進(jìn)行監(jiān)聽,如果注冊的選項(xiàng)使用NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld,那么在接受消息出會(huì)將新和舊的值都會(huì)傳遞過來。如果加上NSKeyValueObservingOptionPrior選項(xiàng)那么在改變值得前后都會(huì)個(gè)發(fā)一次通知。

原來類似于手動(dòng)觸發(fā)KVO通知(因?yàn)槟J(rèn)下類別添加的屬性因缺少setter getter方法而無法使用,通過runtime的關(guān)系屬性來添加屬性,如果需要對(duì)屬性的改變通過KVO進(jìn)行監(jiān)聽,因?yàn)橄到y(tǒng)這個(gè)時(shí)候是不會(huì)自動(dòng)觸發(fā)通知,所以就需要手動(dòng)去觸發(fā)):

[self willChangeValueForKey:@"mj_footer"]; // KVO

objc_setAssociatedObject(self, &MJRefreshFooterKey,//修改屬性

mj_footer, OBJC_ASSOCIATION_ASSIGN);

[self didChangeValueForKey:@"mj_footer"];//KVO





72.MJRefresh基本原理

對(duì)于使用下拉刷新使用的header刷新控件和下拉加載的footer刷新控件都是將這些控件放在scrollview的可見區(qū)域外,而對(duì)于下拉加載的footer控件的添加則要判斷scrollview的contentSize高度和frame的高度,如果內(nèi)容是超出可見區(qū)域content高度大于frame高度,則將footer空間添加到contentSize高度之后,否則就加在frame的高度之后。

因?yàn)閷?duì)于header還是footer刷新的動(dòng)作都是通過KVO對(duì)scrollview的y軸偏移量變化來處理,而整個(gè)下拉上拉的狀態(tài)可以在:默認(rèn)狀態(tài),正在下拉,刷新中,返回默認(rèn)狀態(tài)這幾個(gè)狀態(tài)中,所以將他們的這些特性抽象出來他們的父類,在里面添加KVO的消息機(jī)制,添加KVO所觸發(fā)的鉤子方法,不做任何實(shí)現(xiàn),具體實(shí)現(xiàn)在header,footer的類中根據(jù)偏移量的不同是處理不同的狀態(tài)變化,重寫狀態(tài)屬性的setter方法,當(dāng)偏移量發(fā)生改變,在對(duì)應(yīng)的響應(yīng)方法這里只需要判斷并且設(shè)置當(dāng)前刷新狀態(tài),而在狀態(tài)屬性的stter方法里,根據(jù)狀態(tài)的不同來設(shè)置不同的contentInset,視圖的改變。

在這里為了table或者collection的方便添加Header或者footer,添加scrollview的類別,這樣就需要在里面使用到下拉刷新的header屬性和上啦加載的footer屬性,這個(gè)時(shí)候就是用runtime機(jī)制的關(guān)系屬性的方法來處理,并且在這兩個(gè)setter方法添加KVO的手動(dòng)觸發(fā)通知willChangeValueForKey和didChangeValueForKey。





73.通過UIPanGestureRecognizer實(shí)現(xiàn)控件的拖拽效果

-(void)panAction:(UIPanGestureRecognizer *)pan

{

//以self.playerView的左上角為坐標(biāo)原點(diǎn)

//CGPoint point=[pan locationInView:self.pointView];

//獲取的點(diǎn)是以手指按下的點(diǎn)為原點(diǎn)的

CGPoint point1 = [pan translationInView:pan.view];

UIView *targetView = pan.view;

targetView.center = CGPointMake(targetView.center.x + point1.x, targetView.center.y + point1.y);

//清空位移數(shù)據(jù),避免拖拽事件的位移疊加

[pan setTranslation:CGPointZero inView:pan.view];

}



數(shù)據(jù)傳值方式

1.變量之間的數(shù)據(jù)傳遞

2.指針類型之間的地址傳遞

3.代理設(shè)置模式的數(shù)據(jù)傳值

4.通過的block傳遞

5.系統(tǒng)通知傳值(userInfo)



crash日志分析

在我們每次編譯(需要將debug的選項(xiàng)改為dsym)或打包版本時(shí)候都會(huì)自動(dòng)產(chǎn)生一個(gè)dsym文件,這是一個(gè)16進(jìn)制的函數(shù)地址映射文件,首先檢查.dsym和.crash文件的UUID是一致的,然后通過這個(gè)文件和崩潰日志.crash文件,使用XCODE自帶的symbolicatecrash命令行工具,就可以導(dǎo)出一個(gè).log文件,里面就可以讓我們定位到程序哪里出問題。所以每次發(fā)布版本的時(shí)候就需要將.xcarchive文件夾保存下來,里面就有我們所需要的文件。這里還需要注意要。


Time Profiler

按照固定的時(shí)間間隔來跟蹤每一個(gè)線程的堆棧信息,從而讓我們方便地看到程序運(yùn)行過程中各個(gè)方法正在消耗CPU時(shí)間



id聲明的對(duì)象具有運(yùn)行時(shí)的特性,知道運(yùn)行時(shí)才回去決定他的類型,即可以指向任意繼承自NSObject的對(duì)象



82.判斷cell是否在屏幕內(nèi)

1. 獲取當(dāng)前cell對(duì)于tableview的位置 rectForRowAtIndexPath

2.獲取table y軸上的偏移量,將cell的frame的y坐標(biāo) - 偏移量,獲取相對(duì)于內(nèi)容視圖的位置

3.可視區(qū)域?yàn)閠able 的frame,然后通過函數(shù) CGRectIntersectsRect 判斷兩個(gè)位置是否存在重疊

4.這里如果是加入到導(dǎo)航欄中的table,還需要考慮到contentInset內(nèi)編劇


CGFloat offsetY = self.tableView.contentOffset.y;

CGRect contentRect = self.tableView.frame;

CGRect rectCell = [self.tableView rectForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];

rectCell.origin.y = rectCell.origin.y - offsetY;

if(CGRectIntersectsRect(contentRect, rectCell)){

NSLog(@"再屏幕內(nèi)");

}else{

NSLog(@"--不再屏幕內(nèi)");

}



解決UITableView中Cell重用機(jī)制導(dǎo)致內(nèi)容出錯(cuò)的方法總結(jié)

1.不使用重用機(jī)制

// UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; //改為以下的方法

UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; //根據(jù)indexPath準(zhǔn)確地取出一行

每個(gè)cell指定不同的重用標(biāo)識(shí)符

2.內(nèi)容出錯(cuò)往往是加載過慢導(dǎo)致內(nèi)容沒有及時(shí)地更新,可以使用縮略圖,顯示默認(rèn)圖片,預(yù)加載進(jìn)緩存中等方式處理。


哪些途徑可以讓ViewController瘦下來

1.將視圖處理單獨(dú)封裝(如各種窗口,cell)

2.將業(yè)務(wù)邏輯的處理,如網(wǎng)絡(luò)數(shù)據(jù)庫處理等可以放到對(duì)應(yīng)的model里進(jìn)行



Objective-C如何對(duì)【已有的方法】,添加自己的功能代碼以實(shí)現(xiàn)類似記錄日志這樣的功能?

1.創(chuàng)建一個(gè)方法,在里面調(diào)用原有的方法,并且加上記錄功能

2.使用runtime 的方法交換,對(duì)原有方法和自定義的方法進(jìn)行交換。


CADisplayLink保持著和屏幕刷新率形同的頻率進(jìn)行回調(diào)

//創(chuàng)建對(duì)象

self.progressObjectDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateProgressFromProgressObject)];

//注冊到runloop中

[_progressObjectDisplayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];//停止

[self.displayLink invalidate];

self.displayLink = nil;

對(duì)于一些需要高頻率刷新以致到達(dá)流暢效果的,如動(dòng)畫,繪制,視頻畫面等,一般使用TA。



當(dāng)我們使用readonly去修飾屬性,意味著不會(huì)生成setter方法,那么通過訪問方式如obj.name self.name這些實(shí)際就是訪問setter方法,但是因?yàn)闆]有所以這樣調(diào)用會(huì)報(bào)錯(cuò),所以修改屬性的方法就是在類內(nèi)部使用_name這種方式去修改。當(dāng)然可以用KVC的方式去修改(setter方法->accessInstanceVariablesDirectly yes->成員變量_name _isName name isName->setValues forUndefineKey該方法默認(rèn)拋異常,可以去重寫)

查找:

get<key>,<key>,is<key>?的順序方法查找getter方法,如果沒找到回去找類似于<key>AtIndex類似的數(shù)組方法。

+ (BOOL)accessInstanceVariablesDirectly,如果返回YES(默認(rèn)行為),那么和先前的設(shè)值一樣,會(huì)按_key,_isKey,key,isKey?的順序搜索成員變量名,這里不推薦這么做,因?yàn)檫@樣直接訪問實(shí)例變量破壞了封裝性,使代碼更脆弱。如果重寫了類方法+(BOOL)accessInstanceVariablesDirectly返回NO的話,那么會(huì)直接調(diào)用valueForUndefinedKey:

還沒有找到的話,調(diào)用valueForUndefinedKey:


什么時(shí)候用@autoreleasepool

根據(jù)Apple的文檔,使用場景如下:

1.寫循環(huán),循環(huán)里面包含了大量臨時(shí)創(chuàng)建的對(duì)象。(本文的例子,相冊,本地文件的遍歷就會(huì)產(chǎn)生比較多開銷較大的對(duì)象,使用block來遍歷,在遍歷的時(shí)候會(huì)在內(nèi)部創(chuàng)建自動(dòng)釋放池來對(duì)對(duì)象及時(shí)釋放)

2.長時(shí)間在后臺(tái)運(yùn)行的任務(wù)。(如長時(shí)間運(yùn)行在后臺(tái)的網(wǎng)絡(luò)服務(wù))



97.github + xcode結(jié)合使用

特點(diǎn):

分布式:可以將代碼提交到本地代碼庫,在確定后再更新到服務(wù)器上。

流程:

一般在開發(fā)中,多人合作開發(fā)的時(shí)候,版本控制非常重要,所以一定要有穩(wěn)定的主分支Master,開發(fā)功能的分支developer,預(yù)發(fā)布的分支release這三個(gè)重要分支。每次有新功能和需求的時(shí)候每個(gè)開發(fā)人員就從developer分支分別拉取項(xiàng)目開發(fā),最后合并入developer,功能完成后就并入release,修改bug時(shí)在release分支操作,修復(fù)完成后分別并入Master和developer分支,最后從Master分支拉取最終的代碼打包上傳APP Store

常用命令:

commit 將代碼提交到本地代碼庫

push 將本地代碼庫提交到服務(wù)器

pull 將服務(wù)器代碼更新到本地上

merge 分之合并


viewController的生命周期

初始化:

1.initWithNibName(通過代碼調(diào)用,如present,pushNavigation)

2.initWithCoder(如果使用 storyboard 調(diào)用VC,VC這個(gè)時(shí)候是放在storyboard中),然后調(diào)用 awakeFromNib

如果view為 nil ?

loadView (系統(tǒng)通過代碼方式創(chuàng)建一個(gè)空的view),如果自己覆蓋,則需要同樣按照系統(tǒng)的方法去寫

UIView *view = [[UIView alloc]initWithFrame:[UIScreen mainScreen].bounds];

self.view = view;

不要使用 [super loadView]


viewDidLoad:view加載完畢

viewWillAppear:控制器的view將要顯示

viewWillLayoutSubviews:控制器的view將要布局子控件

viewDidLayoutSubviews:控制器的view布局子控件完成

這期間系統(tǒng)可能會(huì)多次調(diào)用viewWillLayoutSubviews 、 ? ?viewDidLayoutSubviews 倆個(gè)方法

viewDidAppear:控制器的view完全顯示

viewWillDisappear:控制器的view即將消失的時(shí)候

viewDidDisappear:控制器的view完全消失的時(shí)候


loadView viewDidLoad

loadView方法在控制器的view為Nil的時(shí)候會(huì)調(diào)用,若控制器有關(guān)聯(lián)的 Xib 文件,該方法會(huì)從 Xib 文件中加載 view;如果沒有,則創(chuàng)建空白 UIView 對(duì)象。

如果用storyboard初始化控制器,就不用調(diào)用loadview方法了。如果重寫這個(gè)方法給控制器創(chuàng)建view則這個(gè)view必須是一個(gè)單例,而且不能被其他的控制器使用.并且不可以調(diào)用super。

不建議使用loadview,可以根據(jù)自己的需要在storyboard或者viewdidload中創(chuàng)建自己需要的view給控制器,如果使用 Interface Builder 創(chuàng)建 view,則務(wù)必不要重寫該方法。

viewDidlLoad :view 被加載到內(nèi)存后調(diào)用,不管什么情況都會(huì)被調(diào)用,用于視圖的初始化。


集合遍歷方法

1.對(duì)于數(shù)據(jù)量比較大,或者在便利過程中會(huì)產(chǎn)生一些消耗較大的臨時(shí),使用block的形式遍歷更好,因?yàn)槭褂枚嗑€程的方式,并且內(nèi)部會(huì)自動(dòng)創(chuàng)建一個(gè)autoreleasepool,對(duì)臨時(shí)創(chuàng)建的對(duì)象及時(shí)釋放。

2.一般的遍歷,如果不需要使用到下標(biāo),那么使用for in的方式更直觀效率也高。

3.對(duì)于block的數(shù)組方式,除了NSEnumerationConcurrent這種會(huì)在子線程內(nèi)遍歷,其余都是在主線程遍歷。NSEnumerationConcurrent使用了GCD的group原理,當(dāng)遍歷完成,返回主線程


常量

define 宏:只是在預(yù)處理器里進(jìn)行文本替換,不能聲明類型,會(huì)多次地分配內(nèi)存。除了定義常量,還可以定義函數(shù)宏

#define MIN(A,B) A < B ? A : B

const 常量:只分配一次內(nèi)存

修飾局部變量

static const (內(nèi)存分配在靜態(tài)區(qū),在運(yùn)行周期中保持一份)

聲明全局常量:

extern NSString *const kName?

UIKIT_EXTERN

FOUNDATION_EXPORT


autorelease 對(duì)象釋放

1.autorelease 本質(zhì)上就是延遲調(diào)用 release,autorelease pool,其實(shí)這個(gè)pool本質(zhì)上是一個(gè)stack,扔到pool中的對(duì)象等價(jià)于入棧

2.默認(rèn)下,對(duì)象會(huì)在當(dāng)前runloop迭代結(jié)束的時(shí)候釋放。

viewDidAppear 調(diào)用之前,NSAutoreleasePool會(huì)在當(dāng)前runLoop迭代結(jié)束的時(shí)候被銷毀,向池中的對(duì)象發(fā)送release消息,并且pop彈出棧中。

3.手動(dòng)指定 @autoreleasepool {},當(dāng)出了@autoreleasepool {}的作用域時(shí),當(dāng)前autoreleasepool被drain,其中的autoreleased對(duì)象被release

4.對(duì)于每一個(gè)Runloop,系統(tǒng)會(huì)隱式創(chuàng)建一個(gè)Autorelease pool(自然會(huì)有多個(gè)Autorelease pool),這樣所有的release pool會(huì)構(gòu)成一個(gè)象CallStack一樣的一個(gè)棧式結(jié)構(gòu),在每一個(gè)Runloop結(jié)束時(shí),當(dāng)前棧頂?shù)腁utorelease pool會(huì)被銷毀,這樣這個(gè)pool里的每個(gè)Object會(huì)被release。

- (void)viewDidLoad {

[superviewDidLoad];

//????@autoreleasepool?{

//????????NSString?*string?=?[NSString?stringWithFormat:@"leichunfeng"];//對(duì)象創(chuàng)建時(shí)計(jì)數(shù)器+1,有變量指向它,+1,計(jì)數(shù)器為= 2

//????????string_weak_?=?string;

//????}

//出了池的作用域,池被釋放,對(duì)象計(jì)數(shù)器 - 1,局部變量為nil,計(jì)數(shù)器-1,這時(shí)候?qū)ο蟊会尫?/p>


//????NSString?*string?=?nil;

//????@autoreleasepool?{

//????????string?=?[NSString?stringWithFormat:@"leichunfeng"];

//????????string_weak_?=?string;

//????}

出了池的作用域,池被釋放,對(duì)象計(jì)數(shù)器 - 1,局部變量這個(gè)時(shí)候還存,所以只有在viewdidload結(jié)束的時(shí)候,才會(huì)置nil,計(jì)數(shù)器-1,這時(shí)候?qū)ο蟊会尫牛詫?duì)象在viewdidload內(nèi)還存在,在viewwillappear才會(huì)是nil

NSLog(@"string:?%@",?string_weak_);

}



block對(duì)象就是一個(gè)結(jié)構(gòu)體,里面有isa指針指向自己的類(global malloc stack),有desc結(jié)構(gòu)體描述block的信息,引用到的__block變量,最重要的block結(jié)構(gòu)體有一個(gè)函數(shù)指針,指向block代碼塊。


KVO,NSNotification Delegate都是同步發(fā)送消息的


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • *面試心聲:其實(shí)這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個(gè)offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,595評(píng)論 30 472
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,872評(píng)論 25 709
  • iOS網(wǎng)絡(luò)架構(gòu)討論梳理整理中。。。 其實(shí)如果沒有APIManager這一層是沒法使用delegate的,畢竟多個(gè)單...
    yhtang閱讀 5,474評(píng)論 1 23
  • 望著這一張不成樣子的照片,我心竊喜。 校園漸漸變得安靜了,十點(diǎn)一過,該是學(xué)生熄燈休息的時(shí)間點(diǎn)了。 ...
    一個(gè)南瓜先生閱讀 886評(píng)論 0 3
  • 馬甲線 ——懶惰是劣質(zhì)生活的導(dǎo)火索!SO關(guān)注健康,認(rèn)真生活從現(xiàn)在開始! 關(guān)注健康 ▼ 規(guī)律飲食 早餐──7:00(...
    馬甲線app閱讀 341評(píng)論 0 0

友情鏈接更多精彩內(nèi)容