iOS 四月份百度面試總結

1.blcok相關知識?面試

在ARC環境下,編譯器會根據狀況自動將棧上的block進行一次copy操做,將block複製到堆上。swift

//block拷貝到堆上的幾種狀況:數組

  1. 調用block的copy實例方法
  2. Block做爲函數返回值
  3. 將block賦值給有__strong修飾符的id類型的類或block類型成員變量時
  4. 在方法名中含有usingBlock的cocoa框架方法或GCD的API傳遞blokc時<code>

咱們使用block有兩種方式,逃逸和非逃逸(借用swift中的說法)。markdown

非逃逸:聲明的block的生命週期就是聲明所在的函數體的生命週期。咱們在函數體中聲明一個block,這個block會在函數體結束時釋放。網絡

逃逸:聲明的block生命週期和聲明所在的函數體無關了。咱們在函數A中聲明的block,在B中也能夠調用。app

1.NSGlobalBlock (不捕獲自動變量的類型或者捕獲的是靜態局部變量)框架

此處指的不捕獲自動變量,變量不包含全局變量,由於全局變量的特殊生命週期,不須要捕獲,也能夠在block中訪問。異步

1.值捕獲:捕獲的變量爲其指針指向的值,或基礎數據類型的值函數

指針指向的值:oop

2.地址捕獲:捕獲的變量爲其指針自己,或指向基礎數據類型的指針

4.解決循環引用,打破block對對象的強引用便可,兩種方式:__weak對象,__block對象(需在block內將變量主動置空)

對於 MRC 環境,使用 Copy 修飾 Block,會將棧區的 Block 拷貝到堆區。

對於 ARC 環境,使用 Strong、Copy 修飾 Block,都會將棧區的 Block 拷貝到堆區。

因此,Block 不是必定要用 Copy 來修飾的,在 ARC 環境下面 Strong 和 Copy 修飾效果是同樣的。

補充:一個block要使用self,會處理成在外部聲明一個weak變量指向self,然而爲什麼有時會出如今block裏又聲明一個strong變量指向weakSelf?

緣由:block會把寫在block裏的變量copy一份,若是直接在block裏使用self,(self對變量默認是強引用)self對block持有,block對self持有,致使循環引用,因此這裏須要聲明一個弱引用weakSelf,讓block引用weakSelf,打破循環引用。

而這樣會致使另一個問題,由於weakSelf是對self的弱引用,若是這個時候控制器pop或者其餘的方式引用計數爲0,就會釋放,若是這個block是異步調用並且調用的時候self已經釋放了,這個時候weakSelf已就變成了nil。

當控制器(也能夠是其餘的控件)pop回來以後(或者一些其餘的緣由致使釋放),網絡請求完成,若是這個時候須要控制器作出反映,須要strongSelf再對weakSelf強引用一下。

可是,你可能會疑問,strongSelf對weakSelf強引用,weakSelf對self弱引用,最終不也是對self進行了強引用,會致使循環引用嗎。不會的,由於strongSelf是在block裏面聲明的一個指針,當block執行完畢後,strongSelf會釋放,這個時候將再也不強引用weakSelf,因此self會正確的釋放。

2.數組的深拷貝和淺拷貝?

@property (nonatomic, strong) NSArray *array0;

@property (nonatomic, copy) NSArray *array1;

@property (nonatomic, strong) NSMutableArray *array2;

@property (nonatomic, copy) NSMutableArray *array3;

第一種寫法不推薦使用,是對傳遞對象的強引用,不論是傳遞 NSArray 仍是 NSMutableArray 對象都是多了一個強引用的指針而已。當外面傳遞的是 NSMutableArray 對象,在該類中使用該屬性時就要注意外面也可能隨時修改該對象。

第二種寫法爲推薦寫法,若是傳遞的是 NSArray 對象,則只是對原先對象的一份強引用(應該是編譯器優化的),可是若是傳遞的是 NSMutableArray 對象,則是對原先對象的一次「單層深拷貝」,生成的 NSArray 對象是一份新內存地址的對象,可是其中的元素仍是原先的。

第三種寫法爲推薦寫法,是對傳遞 NSMutableArray 對象的一個強引用。該類中使用該屬性時要注意外面也可能隨時修改該對象。

第四種寫法爲錯誤寫法,是對傳遞 NSMutableArray 對象的一個「單層深拷貝」,並且生成的對象是 NSArray 類型而不是 NSMutableArray 類型,在該類中對該屬性作增刪操做就會出現unrecognized method send to … 引起crash。

NSString 與 NSMutableString 和上面的結論是同樣的,只是沒有單層深拷貝的概念。

3. 淺拷貝、單層深拷貝、深拷貝

淺拷貝

所謂的淺拷貝,就是指只是將對象內存地址多了一個引用,也就是說,拷貝結束以後,兩個對象的值不只相同,並且對象所指的內存地址都是同樣的。

單層深拷貝

對於不可變的容器類對象(如NSArray、NSSet、NSDictionary)進 mutableCopy 操做,內存地址發生了變化,可是其中的元素內存地址並無發生變化,屬於單層深拷貝。

對於可變集合類對象(如NSMutableArray、NSMutableSet、NSMutableDictionary),不論是進行 copy 操做仍是 mutableCopy 操做,其內存地址都發生了變化,可是其中的元素內存地址都沒有發生變化,屬於單層深拷貝。

深拷貝

所謂深拷貝,就是指拷貝一個對象的具體內容,拷貝結束以後,兩個對象的值雖然是相同的,可是指向的內存地址是不一樣的。兩個對象之間也互不影響,互不干擾。

對 NSArray 進行 copy 操做的時候,數組的內存地址沒有發生變化,可是進行 mutableCopy 操做時,其內存地址發生了變化,結論跟非集合類的差很少。

可是,這裏的深拷貝和非集合類的深拷貝仍是不太同樣的,上面咱們打印出了數組的第一個元素的內存地址,能夠發現,進行 mutableCopy 操做時,雖然數組內存地址發生了變化,可是數組元素的內存地址並無發生變化。

這個屬於一個特例,咱們稱它爲單層深複製。並非理論上的徹底深複製。

對 NSMutableArray 進行 copy 和 mutableCopy 操做,其內存地址都發生了變化,可是,對於數組中的元素,不論是進行的哪一種操做,內存地址始終都沒有發生變化,因此屬於單層深拷貝。

因此,咱們能夠得出,對於不可變的集合類對象進行 copy 操做,只是改變了指針,其內存地址並無發生變化;進行 mutableCopy 操做,內存地址發生了變化,可是其中的元素內存地址並無發生變化。

對於可變集合類對象,不論是進行 copy 操做仍是 mutableCopy 操做,其內存地址都發生了變化,可是其中的元素內存地址都沒有發生變化,屬於單層深拷貝。

深拷貝就是內容拷貝,淺拷貝就是指針拷貝。本質區別在於:

是否開啓新的內存地址

是否影響內存地址的引用計數

特別注意的是:對於集合類的可變對象來講,深拷貝並不是嚴格意義上的深複製,只能算是單層深複製,即雖然新開闢了內存地址,可是存放在內存上的值(也就是數組裏的元素仍然之鄉員數組元素值,並無另外複製一份),這就叫作單層深複製。

No1:可變對象的copy和mutableCopy方法都是深拷貝(區別徹底深拷貝與單層深拷貝) 。

No2:不可變對象的copy方法是淺拷貝,mutableCopy方法是深拷貝。

No3:copy方法返回的對象都是不可變對象。

在修改原值以前,marry一、marry二、marr3 地址都不同,很明顯copy和mutableCopy都是深拷貝,可是從修改原值後的打印結果來看,這裏的深拷貝只是單層深拷貝:新開闢了內存地址,可是數組中的值仍是指向原數組的,這樣才能在修改原值後,marry2 marr3中的值都修改了。另外,從打印的數組元素地址能夠很明顯的看出來,修改先後marry一、marry、marr3的數組元素地址都是如出一轍的,更加佐證了這一點。

可是修改數組的元素的個數,只有當前數組的個數會改變,數組之間不會互相影響,修改元素的值會互相影響 ,全部的數組的元素的值都會改變

[mstr1 appendFormat:@"aaa"];這樣修改元素的值,全部數組的元素都會修改。

[marry3 replaceObjectAtIndex:0 withObject:@"value1---"];這樣修改元素的值,只有當前數組的元素會修改。

3.隱式動畫和顯式動畫的區別?

顯式動畫是指用戶本身經過beginAnimations:context:和commitAnimations建立的動畫。

隱式動畫是指經過UIView的animateWithDuration:animations:方法建立的動畫。

動畫事務--CATransaction

隱式動畫一直存在 如需關閉需設置;顯式動畫是不存在,如需顯式 要開啓(建立)。

顯式動畫是指用戶本身經過beginAnimations:context:和commitAnimations建立的動畫。隱式動畫是指經過UIView的animateWithDuration:animations:方法建立的動畫。

隱式動畫是系統框架自動完成的。Core Animation在每一個runloop週期中自動開始一次新的事務,即便你不顯式的用[CATransaction begin]開始一次事務,任何在一次runloop循環中屬性的改變都會被集中起來,而後作一次0.25秒的動畫。在iOS4中,蘋果對UIView添加了一種基於block的動畫方法:+animateWithDuration:animations:。這樣寫對作一堆的屬性動畫在語法上會更加簡單,但實質上它們都是在作一樣的事情。CATransaction的+begin和+commit方法在+animateWithDuration:animations:內部自動調用,這樣block中全部屬性的改變都會被事務所包含

4.給對象賦值nil是作了什麼操做?

nil在字典,數組中有特殊含義–元素結束標記

5.自動釋放池的相關知識?

每個自動釋放池都是由一系列的 AutoreleasePoolPage 組成的,而且每個 AutoreleasePoolPage 的大小都是 4096 字節(16 進制 0x1000)自動釋放池中的 AutoreleasePoolPage 是以雙向鏈表的形式鏈接起來的:

autorelease 方法

NSAutoreleasePool*pool = [[NSAutoreleasePoolalloc]init ];//建立一個自動釋放池

Person *person = [[Person alloc]init];

//調autorelease方法將對象加入到自動釋放池//注意使用該方法,對象不會本身加入到自動釋放池,須要人爲調用autorelease方法加入

[person autorelease];

//,手動釋放自動釋放池執行完這行代碼是,自動釋放池會對加入他中的對象作一次release操做

[pool release];

自動釋放池銷燬時機:[pool release]代碼執行完後

每個自動釋放池沒有單獨的結構,每個autorealeasePool對象都是由若干個個autoreleasePoolPage經過雙向鏈表鏈接而成,當一個對象調用了autorelease方法,這個對象就會被加入到當前自動釋放池的最新的autoreleasePoolPage中,關於autoreleasePoolPage/,請看下面

當咱們向自動釋放池 pool 發送 release 消息,將會向池中臨時對象發送一條 release 消息,而且自身也會被銷燬。

1、autorelease 對象會在何時釋放?

分兩種狀況:

使用 @autoreleasepool,會在大括號結束時釋放

不使用 @autoreleasepool,這個會由系統自動釋放,釋放時機是在當前 runloop 結束時釋放,由於系統會自動爲每一個 runloop 執行自動釋放池的 push 和 pop 操做

Autorelease對象何時釋放?

這個問題拿來作面試題,問過不少人,沒有幾個能答對的。不少答案都是「當前做用域大括號結束時釋放」,顯然木有正確理解Autorelease機制。

在沒有手加Autorelease Pool的狀況下,Autorelease對象是在當前的runloop迭代結束時釋放的,而它可以釋放的緣由是系統在每一個runloop迭代中都加入了自動釋放池Push和Pop

ARC下,咱們使用@autoreleasepool{}來使用一個AutoreleasePool,隨後編譯器將其改寫成下面的樣子:

void *context = objc_autoreleasePoolPush();

// {}中的代碼

objc_autoreleasePoolPop(context);

而這兩個函數都是對AutoreleasePoolPage的簡單封裝,因此自動釋放機制的核心就在於這個類。

相關文章
相關標籤/搜索