<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                Blocks 是 Objective-C 版本的 lambda 或者 closure(閉包)。 使用 block 定義異步接口: ~~~ - (void)downloadObjectsAtPath:(NSString *)path completion:(void(^)(NSArray *objects, NSError *error))completion; ~~~ 當你定義一個類似上面的接口的時候,盡量使用一個單獨的 block 作為接口的最后一個參數。把需要提供的數據和錯誤信息整合到一個單獨 block 中,比分別提供成功和失敗的 block 要好。 以下是你應該這樣做的原因: - 通常這成功處理和失敗處理會共享一些代碼(比如讓一個進度條或者提示消失); - Apple 也是這樣做的,與平臺一致能夠帶來一些潛在的好處; - block 通常會有多行代碼,如果不是在最后一個參數的話會打破調用點; - 使用多個 block 作為參數可能會讓調用看起來顯得很笨拙,并且增加了復雜性。 看上面的方法,完成處理的 block 的參數很常見:第一個參數是調用者希望獲取的數據,第二個是錯誤相關的信息。這里需要遵循以下兩點: - 若 `objects` 不為 nil,則 `error` 必須為 nil - 若 `objects` 為 nil,則 `error` 必須不為 nil 因為調用者更關心的是實際的數據,就像這樣: ~~~ - (void)downloadObjectsAtPath:(NSString *)path completion:(void(^)(NSArray *objects, NSError *error))completion { if (objects) { // do something with the data } else { // some error occurred, 'error' variable should not be nil by contract } } ~~~ 此外,Apple 提供的一些同步接口在成功狀態下向 error 參數(如果非 NULL) 寫入了垃圾值,所以檢查 error 的值可能出現問題。 ## 深入 Blocks 一些關鍵點: - block 是在棧上創建的 - block 可以復制到堆上 - block 有自己的私有的棧變量(以及指針)的常量復制 - 可變的棧上的變量和指針必須用 __block 關鍵字聲明 如果 block 沒有在其他地方被保持,那么它會隨著棧生存并且當棧幀(stack frame)返回的時候消失。當在棧上的時候,一個 block 對訪問的任何內容不會有影響。如果 block 需要在棧幀返回的時候存在,它們需要明確地被復制到堆上,這樣,block 會像其他 Cocoa 對象一樣增加引用計數。當它們被復制的時候,它會帶著它們的捕獲作用域一起,retain 他們所有引用的對象。如果一個 block指向一個棧變量或者指針,那么這個block初始化的時候它會有一份聲明為 const 的副本,所以對它們賦值是沒用的。當一個 block 被復制后,`__block` 聲明的棧變量的引用被復制到了堆里,復制之后棧上的以及產生的堆上的 block 都會引用這個堆上的變量。 用 LLDB 來展示 block 是這樣子的: ![](https://box.kancloud.cn/2015-07-22_55af0bd937ec6.png) 最重要的事情是 `__block` 聲明的變量和指針在 block 里面是作為顯示操作真實值/對象的結構來對待的。 block 在 Objective-C 里面被當作一等公民對待:他們有一個 `isa` 指針,一個類也是用 `isa` 指針來訪問 Objective-C 運行時來訪問方法和存儲數據的。在非 ARC 環境肯定會把它搞得很糟糕,并且懸掛指針會導致 Crash。`__block` 僅僅對 block 內的變量起作用,它只是簡單地告訴 block: > 嗨,這個指針或者原始的類型依賴它們在的棧。請用一個棧上的新變量來引用它。我是說,請對它進行雙重解引用,不要 retain 它。謝謝,哥們。 如果在定義之后但是 block 沒有被調用前,對象被釋放了,那么 block 的執行會導致 Crash。 `__block` 變量不會在 block 中被持有,最后... 指針、引用、解引用以及引用計數變得一團糟。 ## self 的循環引用 當使用代碼塊和異步分發的時候,要注意避免引用循環。 總是使用 `weak` 引用會導致引用循環。 此外,把持有 blocks 的屬性設置為 nil (比如 `self.completionBlock = nil`) 是一個好的實踐。它會打破 blocks 捕獲的作用域帶來的引用循環。 **例子:** ~~~ __weak __typeof(self) weakSelf = self; [self executeBlock:^(NSData *data, NSError *error) { [weakSelf doSomethingWithData:data]; }]; ~~~ **不要這樣做:** ~~~ [self executeBlock:^(NSData *data, NSError *error) { [self doSomethingWithData:data]; }]; ~~~ **多個語句的例子:** ~~~ __weak __typeof(self)weakSelf = self; [self executeBlock:^(NSData *data, NSError *error) { __strong __typeof(weakSelf) strongSelf = weakSelf; if (strongSelf) { [strongSelf doSomethingWithData:data]; [strongSelf doSomethingWithData:data]; } }]; ~~~ **不要這樣做:** ~~~ __weak __typeof(self)weakSelf = self; [self executeBlock:^(NSData *data, NSError *error) { [weakSelf doSomethingWithData:data]; [weakSelf doSomethingWithData:data]; }]; ~~~ 你應該把這兩行代碼作為 snippet 加到 Xcode 里面并且總是這樣使用它們。 ~~~ __weak __typeof(self)weakSelf = self; __strong __typeof(weakSelf)strongSelf = weakSelf; ~~~ 這里我們來討論下 block 里面的 self 的 `__weak` 和 `__strong` 限定詞的一些微妙的地方。簡而言之,我們可以參考 self 在 block 里面的三種不同情況。 1. 直接在 block 里面使用關鍵詞 self 1. 在 block 外定義一個 `__weak` 的 引用到 self,并且在 block 里面使用這個弱引用 1. 在 block 外定義一個 `__weak` 的 引用到 self,并在在 block 內部通過這個弱引用定義一個 `__strong` 的引用。 **1. 直接在 block 里面使用關鍵詞 `self`** 如果我們直接在 block 里面用 self 關鍵字,對象會在 block 的定義時候被 retain,(實際上 block 是 [copied](https://developer.apple.com/library/ios/documentation/cocoa/conceptual/Blocks/Articles/bxVariables.html#//apple_ref/doc/uid/TP40007502-CH6-SW4) 但是為了簡單我們可以忽略這個)。一個 const 的對 self 的引用在 block 里面有自己的位置并且它會影響對象的引用計數。如果 block 被其他 class 或者/并且傳送過去了,我們可能想要 retain self 就像其他被 block 使用的對象,從他們需要被block執行 ~~~ dispatch_block_t completionBlock = ^{ NSLog(@"%@", self); } MyViewController *myController = [[MyViewController alloc] init...]; [self presentViewController:myController animated:YES completion:completionHandler]; ~~~ 不是很麻煩的事情。但是, 當 block 被 self 在一個屬性 retain(就像下面的例子)呢 ~~~ self.completionHandler = ^{ NSLog(@"%@", self); } MyViewController *myController = [[MyViewController alloc] init...]; [self presentViewController:myController animated:YES completion:self.completionHandler]; ~~~ 這就是有名的 retain cycle, 并且我們通常應該避免它。這種情況下我們收到 CLANG 的警告: ~~~ Capturing 'self' strongly in this block is likely to lead to a retain cycle (在 block 里面發現了 `self` 的強引用,可能會導致循環引用) ~~~ 所以可以用 `weak` 修飾 **2. 在 block 外定義一個 `__weak` 的 引用到 self,并且在 block 里面使用這個弱引用** 這樣會避免循環引用,也是我們通常在 block 已經被 self 的 property 屬性里面 retain 的時候會做的。 ~~~ __weak typeof(self) weakSelf = self; self.completionHandler = ^{ NSLog(@"%@", weakSelf); }; MyViewController *myController = [[MyViewController alloc] init...]; [self presentViewController:myController animated:YES completion:self.completionHandler]; ~~~ 這個情況下 block 沒有 retain 對象并且對象在屬性里面 retain 了 block 。所以這樣我們能保證了安全的訪問 self。 不過糟糕的是,它可能被設置成 nil 的。問題是:如果和讓 self 在 block 里面安全地被銷毀。 舉個例子, block 被一個對象復制到了另外一個(比如 myControler)作為屬性賦值的結果。之前的對象在可能在被復制的 block 有機會執行被銷毀。 下面的更有意思。 **3. 在 block 外定義一個 `__weak` 的 引用到 self,并在在 block 內部通過這個弱引用定義一個 `__strong` 的引用** 你可能會想,首先,這是避免 retain cycle 警告的一個技巧。然而不是,這個到 self 的強引用在 _block 的執行時間_ 被創建。當 block 在定義的時候, block 如果使用 self 的時候,就會 retain 了 self 對象。 [Apple 文檔](http://developer.apple.com/library/mac/#releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html) 中表示 "為了 non-trivial cycles ,你應該這樣" : ~~~ MyViewController *myController = [[MyViewController alloc] init...]; // ... MyViewController * __weak weakMyController = myController; myController.completionHandler = ^(NSInteger result) { MyViewController *strongMyController = weakMyController; if (strongMyController) { // ... [strongMyController dismissViewControllerAnimated:YES completion:nil]; // ... } else { // Probably nothing... } }; ~~~ 首先,我覺得這個例子看起來是錯誤的。如果 block 本身被 completionHandler 屬性里面 retain 了,那么 self 如何被 delloc 和在 block 之外賦值為 nil 呢? completionHandler 屬性可以被聲明為 `assign` 或者 `unsafe_unretained` 的,來允許對象在 block 被傳遞之后被銷毀。 我不能理解這樣做的理由,如果其他對象需要這個對象(self),block 被傳遞的時候應該 retain 對象,所以 block 應該不被作為屬性存儲。這種情況下不應該用 `__weak`/`__strong` 總之,其他情況下,希望 weakSelf 變成 nil 的話,就像第二種情況解釋那么寫(在 block 之外定義一個弱應用并且在 block 里面使用)。 還有,Apple的 "trivial block" 是什么呢。我們的理解是 trivial block 是一個不被傳送的 block ,它在一個良好定義和控制的作用域里面,weak 修飾只是為了避免循環引用。 雖然有 Kazuki Sakamoto 和 Tomohiko Furumoto) 討論的 [一](http://dhoerl.wordpress.com/2013/04/23/i-finally-figured-out-weakself-and-strongself/)[些](http://blog.random-ideas.net/?p=160)[的](http://stackoverflow.com/questions/7904568/disappearing-reference-to-self-in-a-block-under-arc)[在線](http://stackoverflow.com/questions/12218767/objective-c-blocks-and-memory-management)[參考](https://github.com/AFNetworking/AFNetworking/issues/807), [Matt Galloway](https://twitter.com/mattjgalloway) 的 ([Effective Objective-C 2.0](http://www.effectiveobjectivec.com/) 和 [Pro Multithreading and Memory Management for iOS and OS X](http://www.amazon.it/Pro-Multithreading-Memory-Management-Ios/dp/1430241160) ,大多數開發者始終沒有弄清楚概念。 在 block 內用強引用的優點是,搶占執行的時候的魯棒性。看上面的三個例子,在 block 執行的時候 **1. 直接在 block 里面使用關鍵詞 `self`** 如果 block 被屬性 retain,self 和 block 之間會有一個循環引用并且它們不會再被釋放。如果 block 被傳送并且被其他的對象 copy 了,self 在每一個 copy 里面被 retain **2. 在 block 外定義一個 `__weak` 的 引用到 self,并且在 block 里面使用這個弱引用** 沒有循環引用的時候,block 是否被 retain 或者是一個屬性都沒關系。如果 block 被傳遞或者 copy 了,在執行的時候,weakSelf 可能會變成 nil。 block 的執行可以搶占,并且后來的對 weakSelf 的不同調用可以導致不同的值(比如,在 一個特定的執行 weakSelf 可能賦值為 nil ) ~~~ __weak typeof(self) weakSelf = self; dispatch_block_t block = ^{ [weakSelf doSomething]; // weakSelf != nil // preemption, weakSelf turned nil [weakSelf doSomethingElse]; // weakSelf == nil }; ~~~ ** 3. 在 block 外定義一個 `__weak` 的 引用到 self,并在在 block 內部通過這個弱引用定義一個 `__strong` 的引用。** 不論管 block 是否被 retain 或者是一個屬性,這樣也不會有循環引用。如果 block 被傳遞到其他對象并且被復制了,執行的時候,weakSelf 可能被nil,因為強引用被復制并且不會變成nil的時候,我們確保對象 在 block 調用的完整周期里面被 retain了,如果搶占發生了,隨后的對 strongSelf 的執行會繼續并且會產生一樣的值。如果 strongSelf 的執行到 nil,那么在 block 不能正確執行前已經返回了。 ~~~ __weak typeof(self) weakSelf = self; myObj.myBlock = ^{ __strong typeof(self) strongSelf = weakSelf; if (strongSelf) { [strongSelf doSomething]; // strongSelf != nil // preemption, strongSelf still not nil(搶占的時候,strongSelf 還是非 nil 的) [strongSelf doSomethingElse]; // strongSelf != nil } else { // Probably nothing... return; } }; ~~~ 在一個 ARC 的環境中,如果嘗試用 `->`符號來表示,編譯器會警告一個錯誤: ~~~ Dereferencing a __weak pointer is not allowed due to possible null value caused by race condition, assign it to a strong variable first. (對一個 __weak 指針的解引用不允許的,因為可能在競態條件里面變成 null, 所以先把他定義成 strong 的屬性) ~~~ 可以用下面的代碼展示 ~~~ __weak typeof(self) weakSelf = self; myObj.myBlock = ^{ id localVal = weakSelf->someIVar; }; ~~~ 在最后【疑問】 - **1**: 只能在 block 不是作為一個 property 的時候使用,否則會導致 retain cycle。 - **2**: 當 block 被聲明為一個 property 的時候使用。 - **Case 3**: 和并發執行有關。當涉及異步的服務的時候,block 可以在之后被執行,并且不會發生關于 self 是否存在的問題。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看