2016-08-21 9 views
7

Я сделал исследование исследований stackoverflow и документации Apple относительно ARC и Weak/Unowned (Shall we always use [unowned self] inside closure in Swift). Я получаю основную идею о сильном эталонным цикле и, как это не хорошо, поскольку они вызывают утечки памяти. Тем не менее, я пытаюсь раздобыть голову, когда нужно использовать Weak/Unowned self в закрытии. Вместо того, чтобы зайти в «теорию», я думаю, что это действительно помогло бы, если бы кто-нибудь мог любезно объяснить их в терминах нижних трех случаев, которые у меня есть. Мои вопросыСлабый «я» в замыканиях и пример последствий

  1. Можно ли поставить слабый себя во всех из них (я думаю, что для случая два нет необходимости, потому что я где-то видел, что UIView не связан с самими собой ?. Однако, что если я ставлю слабый сам, есть ли что-нибудь, что может вызвать у меня головную боль?

  2. Скажите, есть ли ответ «Нет», вы не можете ставить слабое «я» во всех трех случаях, что произойдет, если я это сделаю (например, ответ будет очень оценен. Например, программа выйдет из строя, когда этот VC ....

  3. Вот как я планирую использовать weakSelf За пределами закрытия, я положил слабый var weakSelf = self Затем замените все «я» в закрытом слабом салоне? Это нормально?

    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 вы теоретически могли бы использовать [weak self] в блоке animation, но зачем вам? Нет причин.Слабая ссылка - это то, что вы делаете с обработчиками завершения и/или закрывающими переменными, но для блока анимации он не предлагает никакой утилиты, поэтому я бы этого не делал. Использование weak здесь предполагает непонимание семантики памяти.

  3. В случае 3 у вас есть две отдельные проблемы.

    • В didSelectItemAtIndexHandler, что, вероятно, следует использовать [unowned self], потому что собственное закрытие объекта имеет в виду себя.

      Это может быть спорная проблема, поскольку я не вижу, что вы действительно используете этот BTNavigationDropdownMenu (возможно, что инициализатор добавляет себя в контроллер навигации, но это не хорошо спроектированный инициализатор, если так, IMHO).

      Но как общая концепция, когда объект имеет закрытие обработчика, которое может быть вызвано только тогда, когда объект все еще находится вокруг, но не должен сам по себе, чтобы объект был сохранен, вы должны использовать [unowned self].

    • В более общем случае, вопрос заключается в том, является ли это обработчиком завершения. Если это так, вы, вероятно, должны использовать [weak self], потому что это может быть инициировано и запущено к моменту, когда self будет уволен, и вы не хотите, чтобы checkUserLoggedIn содержал ссылку на контроллер вида, который был уволен. Но вы не хотели бы использовать [unowned self], потому что это оставило бы вас с оборванными указателями, если бы оно было выпущено к моменту закрытия.

      Как и в сторону, вы размышляете:

      weak var weakSelf = self 
      

      Это немного unswifty. Вы должны использовать шаблон [weak self] в начале закрытия checkUserLoggedIn. Если у вас есть пример, когда вы соблазняетесь использовать weak var weakSelf = ..., вы должны отредактировать свой вопрос, включая пример того, где вы хотите использовать этот шаблон. Но это не один из этих случаев.

+0

Не могли бы вы рассказать о том, что вы подразумеваете под «не предлагает никакой пользы». Кроме того, справедливо ли говорить, что любое закрытие, которое включает любой вид, ожидающий от интернет-запроса, всегда нуждается в слабом или незанятом себе? И правильно ли, что почти во всех случаях это было бы слабым я? – user172902

+1

Исключительные ссылки в закрытии 'animation', не предлагающие утилиту: Закрытие' animation', предоставленное 'animateWithDuration', не является обработчиком завершения, который запускается позже (хотя есть отдельное закрытие' завершения', но это отдельный шар из воска в целом). Он вызывается немедленно, и анимация инициируется, но закрытие не содержит никаких сильных ссылок на 'self' на время анимации. – Rob

+1

Re сетевые блокировки всегда нуждаются в слабой/незаслуженной: Нет, это, конечно, не так.Например, вы можете сделать что-то в этом закрытии, которое должно выполняться _must_ (например, обновлять локальную db в отношении завершения сетевого запроса, сохранять загруженное изображение в кеш и т. Д.). Используйте только слабый, если вам не нужно/нужно, чтобы код в закрытии сохранял ссылку на объект_ (например, вы просто обновляете пользовательский интерфейс, но не обновляете кеши или базы данных или структуры моделей). Не просто бездумно используйте «слабый»: посмотрите, что находится в закрытии, и решите, должно ли оно быть (или должно быть) слабым или нет. – Rob

-1

Слабые ссылками

Слабая ссылка является ссылкой, что не держит сильное влияние на экземпляре он относится, и поэтому не остановить ARC от утилизации ссылочный экземпляр. Такое поведение предотвращает ссылку из становится частью сильного опорного цикла. Вы указываете слабую ссылку, помещая ключевое слово weak перед объявлением свойства или переменной.

Для большей ясности слабых, прочитайте the doc here.

+0

Кажется, что OP действительно знает, что такое слабая ссылка. Но он хочет знать о слабом я, которого вы не рассматриваете в своем ответе. Так что это не отвечает на вопрос. –