美文网首页
# 常见的[weak self]案例清单(持续更新)

# 常见的[weak self]案例清单(持续更新)

作者: tdt | 来源:发表于2017-12-08 15:26 被阅读51次

    如有错误,欢迎斧正。 代码环境:Xcode9 swift4.

    1. addObserver(forName:object:queue:using:)必须使用[weak self]

      stackover上相关问题:question1 , question2

      官方文档显示如下:

      The block is copied by the notification center and (the copy) held until the observer registration is removed.

      • NotificationCenter-->block-->self

      闭包会被NotificationCenter持有,并且执行之后也并不会自动移除。所以self不会被自动释放。

      解决办法:self使用弱引用

      NotificationCenter.default.addObserver(forName: NSNotification.Name.RetainCycle, object: nil, queue: nil) {[weak self] (notification) in
          guard let `self` = self else { return }
      }
      

      PS: 见到有人说和object是否传入self有关。自己测试了一下,无论是否在object传入self,都不影响结果。测试相关代码如下,ViewController1和ViewController2均未释放:

      import UIKit
      class ViewController1: UIViewController {
      
          deinit {
              //for iOS9-
              NotificationCenter.default.removeObserver(self)
              print("ViewController deinit")
          }
      
          override func viewDidLoad() {
              super.viewDidLoad()
              self.title = "object obtains self"
              NotificationCenter.default.addObserver(forName: NSNotification.Name.RetainCycle, object: self, queue: OperationQueue.main) { (_) in
                  self.title = ""
              }
          }
      }
      
      class ViewController2: UIViewController {
          
          deinit {
              //for iOS9-
             NotificationCenter.default.removeObserver(self)
             print("ViewController deinit")
         }
         
         override func viewDidLoad() {
          super.viewDidLoad()
          self.title = "object obtains self"
          NotificationCenter.default.addObserver(forName: NSNotification.Name.RetainCycle, object: nil, queue: OperationQueue.main) { (_) in
              self.title = ""
              }
          }
      }
      
    2. 多重嵌套。如果在闭包中继续包含一个闭包,是否需要给每一个嵌套加上[weak self]呢?

      答案是否定的。只需要使用一次即可。如下面的例子。

      • self-->foo-->barclosure
      • barclosure-->(weak)self
      import UIKit
      
      class Foo {
          
          func bar(closure:()->()) {
              print(vc)
          }
          
          var vc:UIViewController!
          
      }
      
      class ViewController3: UIViewController {
      
          deinit {
              //for iOS9-
              NotificationCenter.default.removeObserver(self)
              print("ViewController deinit")
          }
          
          var foo = Foo()
          
          override func viewDidLoad() {
              super.viewDidLoad()
              self.title = "object does not obtain self"
              //self.foo.vc = self 可不能写在这里,真循环引用了
              NotificationCenter.default.addObserver(forName: NSNotification.Name.RetainCycle, object: nil, queue: OperationQueue.main) { [weak self](_) in
                  //定义一次即可,嵌套的就不再需要继续定义了。
                  guard let `self` = self else {return}
                  
                  self.title = ""
                  self.foo.bar {
                      self.foo.vc = self
                  }
                  
              }
          }
      }
      

      引用stackoverflow上的回答

      Weak references are implemented as optionals, which are value types. Therefore you cannot directly have a strong reference to one – instead you first have to unwrap it, and then take a strong reference to the underlying instance. In this case you're simply dealing with a strong reference (exactly like my example above with strongSelf).

      However, if a weak reference is boxed (this happens with closure capture – the value type will be put into a heap-allocated box) – then you can indeed have a strong reference to that box. The effect of this is equivalent to a weak reference to the original instance, you just have an invisible bit of extra indirection.

      In fact, this is exactly what happens in the example where the outer closure weakly captures self and the inner closure 'strongly captures' that weak reference. The effect is that neither closure retains self.

    3. DispatchQueue.global().async

      • DispatchQueue.main-->block-->self

      闭包被DispatchQueue.main持有,但是执行后就移除了引用,而self及属性不持有blockDispatchQueue.main,不构成循环。因此不需要使用[weak self]

      demo代码如下。block执行前,退出ViewController,ViewController不销毁。但一旦block全部执行完后,ViewController销毁。

      import UIKit
      
      class ViewController4: UIViewController {
          
          deinit {
              print("ViewController deinit")
          }
          
          override func viewDidLoad() {
              super.viewDidLoad()
      
               let deadline = DispatchTime.now() + 5
      
              DispatchQueue.global().async {
                  // Do task in default queue
                  
                  DispatchQueue.main.async {
                      // Do task in main queue
                      self.title = ""
                  }
                  
                  DispatchQueue.global().asyncAfter(deadline: deadline) {
                      // Do task in main queue
                      self.title = "123"
                  }
              }
          }
      }
      
    4. 同DispatchQueue.main还有几个类似的强引用。都是block强引用self,但self不需要强引用block

      • UIViewanimate(withDuration duration: TimeInterval, animations: @escaping () -> Swift.Void)
      • OperationQueue.mainaddOperation(_ block: @escaping () -> Swift.Void)
      • Alamofirerequest类方法

      demo如下

      import UIKit
      
      class ViewController5: UIViewController {
          
          deinit {
              print("ViewController deinit")
          }
      
          override func viewDidLoad() {
              super.viewDidLoad()
      
              UIView.animate(withDuration: 1) {
                  self.title = "123"
              }
      
              OperationQueue.main.addOperation {
                  self.title = "456"
              }
              
          }
      
      }
      

    相关文章

      网友评论

          本文标题:# 常见的[weak self]案例清单(持续更新)

          本文链接:https://www.haomeiwen.com/subject/lebeixtx.html