2017-06-13 103 views
2

我已經通過Swift ClosuresARC in Swift,我有點困惑。瞭解快速關閉捕獲

我有調用Web服務和使用響應數據的簡單場景。
這是我的基本實現:

class WebServices: NSObject { 
    func requestDataFromServer(completion: @escaping (_ data: Data?) -> Void) { 
    //web service call here 
    completion(Data()) 
    } 
    deinit { 
    print("WebServices deinitializer...") 
    } 
} 

class Controller: NSObject { 
    private let webService = WebServices() 
    private func useResponseData(_ data: Data) { 
    print("Response Data: \(data)") 
    } 
    func fetchData() { 
    webService.requestDataFromServer { (data) in 
     if let responseData = data { 
     self.useResponseData(responseData)//direct use of self 
     } 
    } 
    } 
    deinit { 
    print("Controller deinitializer...") 
    } 
} 

var controller: Controller? = Controller() 
controller!.fetchData() 
controller = nil 

控制檯輸出爲:

響應數據:0字節
控制器deinitializer ...
的WebServices deinitializer ...

我的問題是,即使我正在使用self直接關閉爲什麼這個實施我s不會導致參考保留週期
如果我使用unownedweak那麼也是同樣的行爲。


什麼能引起參考上面的場景中保留週期?(我不希望引起,而是想知道錯誤的)

回答

0

好吧,我想這個問題是你在做什麼這裏實際上不是異步,所以陸續執行一個,該代碼會導致內存泄漏:

import Foundation 

class WebServices { 
    func requestDataFromServer(completion: @escaping (_ data: Data?) -> Void) { 
     //web service call here 
     print("called") 
     DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: { 
      print("called async") 
      completion(Data()) 
     }) 
    } 
    deinit { 
     print("WebServices deinitializer...") 
    } 
} 

class Controller: UIViewController { 
    private let webService = WebServices() 
    private func useResponseData(_ data: Data) { 
     print("Response Data: \(data)") 
    } 
    func fetchData() { 
     webService.requestDataFromServer { (data) in 
      print("called") 
      if let responseData = data { 
       self.useResponseData(responseData)//direct use of self 
      } 
     } 
     self.dismiss(animated: true, completion: nil) 
    } 
    deinit { 
     print("Controller deinitializer...") 
    } 
} 

var controller: Controller? = Controller() 
controller!.fetchData() 
+0

即使這種情況下,與異步還兼具實例去初始化! – D4ttatraya

+0

@DashAndRest編輯,我的錯誤,現在它是'UIViewContoller'類似的行爲,'解僱'而不是'nil'的例子 – JuicyFruit

+0

但是,這仍然是如何初始化?以及它如何泄漏內存? – D4ttatraya

1

有一個在你的代碼沒有問題,因爲requestDataFromServer呼叫完成處理器直接(不異步)。因此,在您致電期間,呼叫者不能被釋放。

但是,當你將實現你的web服務的真正的呼叫,它將是異步的。所以用戶可以在你的web服務應答之前切換頁面。在這種情況下,您將保留對您的控制器的強烈參考,並且它永遠不會被釋放。您應該在關閉時使用[weak self](因此請撥打self?.useResponseData(responseData)將自己視爲可選項)。

unowned的情況下使用,你就一定參考不會是零(它不是一個可選)