2016-08-21 71 views
7

我已經完成了有關ARC和弱/無主自我(Shall we always use [unowned self] inside closure in Swift)的stackoverflow和蘋果文檔的研究。我瞭解強參考週期的基本概念,以及它如何導致內存泄漏並不好。但是,我試圖讓我的頭在什麼時候使用弱/無主的自我封閉。相反,在進入「理論」時,我認爲如果有人能夠根據我所掌握的最底層的三種情況來解釋它們,那真的會有所幫助。我的問題是弱自我封閉和後果示例

  1. 是否確定把薄弱的自我在所有這些(我認爲情況下,兩個沒有必要,因爲我看到的地方,UIView的不與自相關?但是,如果我把什麼虛弱的自我存在,有什麼能引起我的頭疼?

  2. 說,如果答案是否定的,你不能在所有三種情況下把弱自我無處不在,如果我做(例如反應將非常感激會發生什麼。 ..例如,程序會崩潰時,這個VC ....

  3. 這是我如何計劃使用weakSelf 關閉之外,我把弱變弱weakSelf = self 然後用weakSelf替換所有關閉自我? 那可以嗎?

    Case 1: 
    FIRAuth.auth()?.signInWithCredential(credential, completion: { (user: FIRUser?, error: NSError?) in 
        self.activityIndicatorEnd() 
        self.performSegueWithIdentifier(SEGUE_DISCOVER_VC, sender: self) 
    }) 
    
    Case 2: 
    UIView.addKeyframeWithRelativeStartTime(0.0, relativeDuration: 0.1, animations: { 
        self.messageLbl.alpha = 0.5 
    }) 
    
    Case 3: 
    //checkUserLoggedIn sends a request to firebase and waits for a response to see if the user is still authorised 
    checkUserLoggedIn { (success) in 
        if success == false { 
         // We should go back to login VC automatically 
    
        } else {   
         self.discoverTableView.delegate = self 
         self.discoverTableView.dataSource = self 
    
         // Create dropdown menu 
         let menuView = BTNavigationDropdownMenu(navigationController: self.navigationController, title: self.dropDownItems.first!, items: self.dropDownItems) 
    
         menuView.didSelectItemAtIndexHandler = {[weak self] (indexPath: Int) ->() in 
          if indexPath == 0 { 
           self?.mode = .Closest 
           self?.sortByDistance() 
    
          } else if indexPath == 1 { 
           self?.mode = .Popular 
           self?.sortByPopularity() 
    
          } else if indexPath == 2 { 
           self?.mode = .MyPosts 
           self?.loadMyPosts() 
    
          } else { 
           print("Shouldnt get here saoihasiof") 
          } 
         } 
    
        // Xib 
         let nib = UINib(nibName: "TableSectionHeader", bundle: nil) 
         self.xibRef = nib.instantiateWithOwner(self, options: nil)[0] as? TableSectionHeader 
         self.discoverTableView.registerNib(nib, forHeaderFooterViewReuseIdentifier: "TableSectionHeader") 
    
         // Set location Manager data 
         self.locationManager.delegate = self 
         self.locationManager.desiredAccuracy = kCLLocationAccuracyBest 
    
         // Check location service status 
         if self.locationAuthStatus == CLAuthorizationStatus.AuthorizedWhenInUse { 
          // Already authorised 
          self.displayMessage.hidden = false 
    
         } else if self.locationAuthStatus == CLAuthorizationStatus.NotDetermined { 
          // Have not asked for location service before 
          let storyboard = UIStoryboard(name: "Main", bundle: nil) 
          let vc = storyboard.instantiateViewControllerWithIdentifier("LocationVC") as! LocationVC 
          vc.locationVCDelegate = self 
          self.presentViewController(vc, animated: true, completion: nil) 
    
         } else { 
          let alertController = UIAlertController(title: "Enable Location", message: "location is required to load nearby posts", preferredStyle: .Alert) 
          let cancelAction = UIAlertAction(title: "Cancel", style: .Default, handler: nil) 
          let settingsAction = UIAlertAction(title: "Settings", style: .Default, handler: { (action: UIAlertAction) in 
           let settingsUrl = NSURL(string: UIApplicationOpenSettingsURLString) 
           if let url = settingsUrl { 
            UIApplication.sharedApplication().openURL(url) 
           } 
          }) 
          alertController.addAction(settingsAction) 
          alertController.addAction(cancelAction) 
          self.presentViewController(alertController, animated: true, completion: nil) 
    
          self.displayMessage.hidden = false 
          self.displayMessage.text = "Could not determine your location to find nearby posts. Please enable location Service from settings" 
         } 
    
         // Styling 
         self.refreshBtn.tintColor = COLOR_NAVIGATION_BUTTONS 
         self.discoverTableView.backgroundColor = COLOR_DISCOVERVC_TABLEVIEW_BACKGROUND 
    
         // Allow navigation bar to hide when scrolling down 
         self.hidingNavBarManager = HidingNavigationBarManager(viewController: self, scrollView: self.discoverTableView) 
    
         // Allow location to start updating as soon as we have permission 
         self.locationManager.startUpdatingLocation() 
        } 
    } 
    

--Update-- 我大部分的代碼看起來像3的情況下,一切都是包裝在瓶蓋內,要麼檢查是否有互聯網連接的任何行動的是發生之前。所以我可能會有自我弱點?

--update 2--

Case 4: 
// The haveInternetConnectivity function checks to see if we can reach google within 20 seconds and return true if we can 
haveInternetConnectivity { (success) in 
    if success == false { 
     self.dismissViewControllerAnimated() 
    } else {   
     self.label.text = "You are logged in" 
     self.performSegueWithIdentifier("GoToNextVC") 
    } 
} 

問題有關情況4. 我是正確地說,即使這種封閉不具有弱/無主的自我,它永遠不會創建強引用(記憶泄漏),因爲即使VC在執行完成塊之前被解散,Xcode也會嘗試在完成塊內運行代碼,當我們確認了互聯網狀態並且不會執行任何操作(無崩潰),因爲自己不再存在。一旦代碼到達閉包內的最後一行,對自身的強烈引用將被破壞,從而釋放VC?

所以把[弱自我]在這種情況下,只會意味着Xcode中會忽略這些行(如反對嘗試運行它,什麼都不會發生),這將意味着一個更好的做法,但我的手沒有問題,無論哪種方式

回答

13

這個問題不應該是「我可以使用弱引用」,而是「我應該使用弱引用」。您可以使用弱引用來避免強引用週期,或者在封閉處理後可以保持封閉狀態。但是不要只是添加弱引用,因爲你可以使用

  1. 在案例1中,你可能想使用[weak self]。爲什麼?因爲如果視圖控制器在授權正在進行時被解僱,您是否真的想保留對被解僱的視圖控制器的引用?可能不是這種情況。

  2. 在案例2中,理論上可以在animation塊中使用[weak self],但爲什麼要這樣做?沒有理由。弱引用是你用完成處理程序和/或閉包變量做的事情,但對於動畫塊它沒有提供實用工具,所以我不會在那裏做。在這裏使用weak暗示了對涉及的內存語義的誤解。

  3. 在情況3中,您有兩個單獨的問題。

    • didSelectItemAtIndexHandler,因爲對象自身的封閉是指的自己也許應該用[unowned self]。因爲我沒有看到你實際上使用了BTNavigationDropdownMenu(也許初始化程序將自己添加到導航控制器,但如果是的話,這不是一個設計良好的初始化程序,恕我直言),這可能是一個沒有實際意義的問題。

      但是作爲一個通用的概念,當一個對象有一個處理程序閉包,只能在對象仍然在其周圍時調用,但不應該本身導致該對象被保留時,您可以使用[unowned self]

    • 在更廣泛的checkUserLoggedIn閉包中,問題是這是否是完成處理程序。如果是這樣,您可能應該使用[weak self],因爲這可能會在self被解僱的時候啓動並運行,並且您不希望checkUserLoggedIn保留對被解僱的視圖控制器的引用。但是你不想使用[unowned self],因爲如果在關閉運行的時候釋放了懸掛指針,那麼它會留下懸掛指針。

      順便說一句,你考慮:

      weak var weakSelf = self 
      

      這是一個有點unswifty。您可以在checkUserLoggedIn關閉開始時使用[weak self]模式。如果你有一個例子,你試圖使用weak var weakSelf = ...,你應該編輯你的問題,包括你想使用該模式的例子。但這不是其中之一。

+0

請您詳細說明您的意思是「不提供實用工具」。另外,公平地說,任何涉及互聯網請求的任何類型的閉包總是需要一個虛弱的或無主的自我?幾乎在所有這些情況下,這會是弱自我嗎? – user172902

+1

Re:在動畫閉包中的弱引用不提供實用程序:提供給'animateWithDuration'的動畫閉包不是稍後運行的完成處理程序(雖然有一個單獨的「完成」閉包,但這是一個獨立的蠟球共)。它被立即調用,並且動畫被啓動,但閉合在動畫持續期間沒有保留對「self」的強引用。 – Rob

+1

重新網絡關閉總是需要弱/無主:不,這當然不是這種情況。例如,你可能在這個閉包中執行一些必須運行的操作(例如,更新本地數據庫關於完成網絡請求;將下載的圖像保存到高速緩存等等)。只使用弱_if,你不需要/想讓閉包中的代碼繼續引用object_(例如,你只是更新UI,但不更新緩存或數據庫或模型結構)。不要盲目地使用'weak':看看封閉體內是什麼,並決定它是否應該(或必須)弱。 – Rob

-1

弱引用

弱引用是不保留一個強抱上它是指,所以不從的處置停止ARC的實例的引用引用的實例。此行爲可防止參考成爲強參考週期的一部分。通過在屬性或變量聲明之前放置weak關鍵字來指示弱引用。

欲瞭解更清晰的弱點,請閱讀the doc here

+0

看來OP確實知道一個弱點是什麼。但他想知道自我的弱點,在你的回答中你不會對待自己。所以這不能回答這個問題。 –