ios 面試題之—block
對block的綜合理解
block的實質
物件, 一個函式指標, 指向程式碼塊, 以及上下文所需的變數
函式指標和block的格式對比
函式指標 void(*fun)(int)
block void(^fun)(int)
block在記憶體中的分類
全域性block –> GlobalBlock <==> 相當於全域性變數, 系統會自動釋放
棧block –> StackBlock <==> 相當於區域性變數, 系統會自動釋放
堆block –> MallocBlock <==> (需要手動釋放記憶體)
block型別區分方法
如果block實現中沒有訪問任何”外部”變數(包括區域性和全域性), 該block為GlobalBlock
如果block實現中訪問了任何”外部”變數(包括區域性和全域性), 該block為StackBlock
對StackBlock進行拷貝(copy/Block_copy), 該block為MallocBlock
注意點:
block預設都是在棧上建立的, 當block超過作用域, 就會被銷燬, 如果要在作用域外使用block, 應copy該block到堆上, 此時會建立一個新的MallocBlock到堆上
宣告block物件, 應該使用copy修飾, 將其儲存到堆上, 不然在回撥時block已經銷燬, 無法訪問
delegate跟block的區別,使用場景有哪些不同?
定義:
A物件設定協議和代理,並讓B物件遵守協議和成為代理,從而讓B物件實現協議方法, 是為代理
block的本質是指標函式, 內部封存的是程式碼塊
區別:
代理
代理是一對一的, 需要設定介面
可能引起迴圈引用,導致記憶體洩漏
通過指定delegate物件為weak,可以避免迴圈引用
block
block的不需要設定介面, 使用更為輕型
更容易造成迴圈引用
通過指定block內的物件為__weak,可以避免迴圈引用
使用場景:
代理
當要實現的方法大於3個
為了防止迴圈引用時
寫一個庫給別人使用,又不清楚使用者的能力,建議使用delegate
block
當要實現的方法小於3個
需要請求資料回撥
GCD跟Block使用需要注意什麼?
GCD使用注意點:
防止死鎖
GCD不能控制最大任務併發量(無法決定具體開多少子執行緒,只能由系統決定)
GCD的請求一旦傳送,無法直接取消
Block使用注意點:
防止迴圈引用
在block中用到外部變數都是隻讀拷貝的
棧block超過作用域就被自動釋放了
堆block需要手動釋放
Block在ARC跟MRC中的行為和用法有什麼區別?
相同點
block的本質一樣, 都是函式指標
使用__block都可以解決在block中修改外部變數的問題
不同點
解決迴圈引用的方式不同
MRC中使用__block
ARC中使用 __weak
block用什麼屬性修飾,為什麼?
在MRC中, 定義Block屬性時, 應該用copy修飾
在ARC中, 定義Block屬性時, 系統會自動將其copy, 即複製到堆上. 但習慣上還是會用copy修飾
用copy修飾的原因
block建立時預設是建立在棧上的, 超過作用域後就會被銷燬, 只有使用copy才會生成一個堆block, 在作用域外被訪問