代码之家  ›  专栏  ›  技术社区  ›  user172902

关闭和后果示例中的弱自我

  •  8
  • user172902  · 技术社区  · 8 年前

    我对stackoverflow和苹果关于ARC和弱/无主自我的文档做了一些研究( Shall we always use [unowned self] inside closure in Swift ). 我得到了关于强引用循环的基本概念,以及它如何不好,因为它们会导致内存泄漏。然而,我正在努力弄清楚什么时候在闭包中使用弱/无主自我。我认为,如果有人能用我所掌握的最底层的三个案例来解释它们,那就真的会有帮助。我的问题是

    1. 把脆弱的自我放在所有的里面可以吗(我认为对于案例二没有必要,因为我在某个地方看到UIView与自我无关?但是,如果我把脆弱的自己放在那里,有什么东西会让我头痛吗?

    2. 如果答案是否定的,那么你不能在所有三种情况下都把脆弱的自我放在任何地方,如果我这样做会发生什么(例如,非常感谢你的回答…例如,当这个VC。。。。

    3. 这就是我计划使用weakSelf的方式 在闭包之外,我将弱var weakSelf=self 然后用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()
         }
      }
      

    --更新-- 我的大部分代码看起来像案例3,其中所有内容都被封装在一个闭包中,要么在执行任何操作之前检查是否存在互联网连接。所以我可能到处都是软弱的自我??

    --更新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")
        }
    }
    

    我正确地说,即使这个闭包没有弱/无主自我,它也不会创建强引用(和内存泄漏),因为即使VC在执行完成块之前被解除,当我们确认了互联网状态时,Xcode会尝试在完成块内运行代码,并且什么也不做(没有崩溃),因为自我不再存在。一旦代码到达闭包内的最后一行,对self的强引用就会被破坏,从而释放VC?

    因此,在这种情况下使用[weak Self]只意味着xcode将忽略这些行(与尝试运行它相反,什么也没有发生),这意味着更好的实践,但我手头也没有问题

    1 回复  |  直到 7 年前
        1
  •  17
  •   Rob Md Fahim Faez Abir    8 年前

    问题不应该是“我可以使用弱引用吗”,而是“我应该使用弱引用”。使用弱引用是为了避免强引用循环,或者是为了防止闭包在被处理后挂起。但不要只添加弱引用,因为 可以

    1. 在案例1中,您可能确实想使用 [weak self] 为什么?因为如果视图控制器在授权过程中被解除,您真的想保留对解除的视图控制器的引用吗?在这种情况下可能不会。

    2. [脆弱的自我] 在中 animation 阻止,但你为什么要阻止?没有理由这样做。弱引用是用完成处理程序和/或闭包变量做的,但对于动画块,它没有提供实用程序,所以我不会在那里做。要使用 weak 这里暗示了对所涉及的记忆语义的误解。

    3. 在案例3中,您有两个单独的问题。

      • didSelectItemAtIndexHandler [unowned self] 因为对象自己的闭包引用自身。

        这可能是一个没有实际意义的问题,因为我看不到你真的在使用它 BTNavigationDropdownMenu (也许初始化器正在将自己添加到导航控制器中,但如果是这样的话,那不是一个设计良好的初始化器,IMHO)。

        但是作为一个一般概念,当一个对象有一个处理程序闭包,该闭包只能在对象仍然存在时调用,但它本身不应该导致对象被保留时,您应该使用 [无主自我] .

      • 在更广泛的范围内 checkUserLoggedIn 闭包,问题是这是否是一个完成处理程序。如果是这样,您可能应该使用 [脆弱的自我] ,因为这可以在 self 被解雇了,你不想 检查用户登录 保留对已解除的视图控制器的引用。但你不会想用 [无主自我] 因为如果在闭包运行时它已经被释放,那么会给您留下悬而未决的指针。

        顺便说一句,你想:

        weak var weakSelf = self 
        

        这有点不灵活。您可以使用 [脆弱的自我] 模式的开头 检查用户登录 关闭。如果你有一个你想用的例子 weak var weakSelf = ...