2013-01-22 20 views
7

我目前無法理解Obj-C塊和__block存儲類型的基礎知識。 從下列文件:無法理解Objective-C塊文檔

http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/bxVariables.html#//apple_ref/doc/uid/TP40007502-CH6-SW6

我想了解下段和示例:

當一個塊被複制,它創造強烈的引用對象中使用的變量塊。如果在方法的實現中使用塊:

如果通過引用訪問實例變量,則強引用self; 如果按值訪問實例變量,則會強烈引用該變量。 下面的實施例示出了兩種不同的情況:

dispatch_async(queue, ^{ 
    // instanceVariable is used by reference, a strong reference is made to self 
    doSomethingWithObject(instanceVariable); 
}); 

id localVariable = instanceVariable; 
dispatch_async(queue, ^{ 
    /* 
     localVariable is used by value, a strong reference is made to localVariable 
     (and not to self). 
    */ 
    doSomethingWithObject(localVariable); 
}); 

要覆蓋此行爲對於特定的對象變量,可以用該存儲__block類型修飾符標記它。

我的問題:

  1. 究竟是如何被一個例子「通過引用訪問」,而另一種是通過變量訪問?爲什麼localVariable被「價值使用」?
  2. 這篇文章的意思是「強烈的自我引用」是什麼意思?它指的是「自我」?
  3. 如果我在第二個例子中將__block存儲類型添加到localVariable中,我是否錯誤地假定該塊關閉了變量,所以它將它保留在堆中直到塊被釋放?還有什麼其他事情發生?

謝謝!

回答

6

一個例子「通過引用訪問」究竟如何,而另一個例子是由變量訪問?爲什麼localVariable被「價值使用」?明白這一點

的一種方法如下:

  1. ,當你在方法定義的塊使用局部變量,會發生什麼是變量的內容在某些塊複製私有內存,以便在塊執行時(方法退出後)可用。從這個意義上說,我們可以談論「按價值」訪問(如:價值被複制);在語法上,編譯器不知道localVariable的內容是什麼,所以它的值被視爲這樣;

  2. 當在類的方法中定義的塊中直接訪問instanceVariable時,編譯器知道我們正在訪問執行該方法的同一對象,並且不需要複製任何內容,因爲對象具有更長的比找到塊的方法更有效;但是我們需要確保該塊在執行時仍然存在,因此我們可以強烈引用它。

現在,對於使用「通過引用」:在第一種情況下,你得到的引用的副本的類成員:如果你可以改變它的值(但你不能,因爲編譯器禁止它),你只是修改一個塊私人副本,所以原始對象不受影響。

在第二種情況下,您可以修改instanceVariable的值(如:它是nil,並且您分配了一個通過它引用的對象),這會影響執行方法的對象,如果該塊被定義。

這篇文章的意思是「強烈的自我引用」是什麼意思?它指的是「自我」?

self是當前正在執行找到該塊的方法的對象。強烈的引用僅僅意味着(用ARC的說法)對象的保留計數增加(以確保其他實體不能通過釋放它來解除分配)。

如果我在第二個例子中添加__block存儲類型所以LocalVariable,我錯了的假設,該塊關閉了該變量,所以直到塊被釋放在它周圍堆保留它?還有什麼其他事情發生?

使用__block可以使變量始終按「引用」進行訪問,因此您可以修改它們。

這是如何處理這些:

__block變量生活在一個變量的詞彙範圍,和所有塊,並宣佈或變量的詞法範圍內創建塊的副本之間共享存儲。因此,如果在幀中聲明的塊的任何副本存活超過幀的末尾(例如,通過在某處等待以後執行),那麼存儲器將在存儲器堆棧幀的銷燬中倖存下來。給定詞法範圍中的多個塊可以同時使用共享變量。

作爲優化,塊存儲從堆棧開始 - 就像塊本身一樣。如果使用Block_copy複製塊(或在塊發送副本時在Objective-C中),則將變量複製到堆中。因此,__block變量的地址可以隨時間變化。