【问题标题】:Nested callback strong reference cycle嵌套回调强引用循环
【发布时间】:2016-12-10 06:59:10
【问题描述】:
@IBAction func sendSweet(sender: UIBarButtonItem) {

    var inputTextField: UITextField?
    let alert = UIAlertController(title: "New sweet", message: "Enter a sweet", preferredStyle: .alert)
    alert.addTextField { (textField: UITextField) in
        textField.placeholder = "Your sweet"
        inputTextField = textField
    }

    let sendAction = UIAlertAction(title: "Send", style: .default, handler: {
        [weak self] (alertAction: UIAlertAction) in
        guard let strongSelf = self else { return }

        if inputTextField?.text != "" {
            let newSweet = CKRecord(recordType: "Sweet")
            newSweet["content"] = inputTextField?.text as CKRecordValue?

            let publicData = CKContainer.default().publicCloudDatabase
            publicData.save(newSweet, completionHandler: {
                (record: CKRecord?, error: Error?) in

                if error == nil {
                    // we want ui code to dispatch asychronously in main thread
                    DispatchQueue.main.async {
                        strongSelf.tableView.beginUpdates()
                        strongSelf.sweets.insert(newSweet, at: 0)
                        let indexPath = IndexPath(row: 0, section: 0)
                        strongSelf.tableView.insertRows(at: [indexPath], with: .top)
                        strongSelf.tableView.endUpdates()
                    }
                } else {
                    if let error = error {
                        print(error.localizedDescription)
                        return
                    }
                }
            })
        }
    })

    alert.addAction(sendAction)
    alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
    present(alert, animated: true, completion: nil)

}

我有这个回调地狱,我想知道

  1. 回调地狱最顶端的[weak self]guard let strongSelf 是否通过GCD 的异步回调完全阻止了强引用循环。我在这里读到了其他帖子,也是一本书的帖子,上面说如果我在回调中引用的对象可以deinit 成功,这意味着没有强引用周期的好兆头,这仍然是真的吗?

  2. 如何防止这种回调地狱,你能引导我一些我错过的阅读材料或主题吗?类似于 javascript 的承诺链语法?

【问题讨论】:

    标签: ios swift multithreading swift3 grand-central-dispatch


    【解决方案1】:

    据我所知,没有保留周期,因此无需弱化self。您当然可以在每个街区都这样做以进行防守。

    没有保留周期,因为实例 (self) 没有引用任何闭包。特别是对于sendAction,因为sendAction 是在sendSweet 函数内部声明的。

    class MyView: UIView {
        let str = "some variable to have somsthing to use self with"
    
        func foo() {
            let ba = {
                // no problem. The instance of MyView (self) does not hold a (strong) reference to ba
                self.str.trimmingCharacters(in: CharacterSet.alphanumerics)
            }
    
            ba()
        }
    }
    

    如果您将let sendAction = ... 作为实例的属性移动到函数之外,那么您将有一个引用循环。在这种情况下,实例 (self) 将对 sendAction 具有强引用,sendAction 闭包将对实例 (self) 具有强引用:

    自我 {自我。 ...}又名sendAction

    class MyView: UIView {
        let str = "asd"
        // Problem. 
        // The instance of MyView (self) does hold a (strong) reference to ba ...
        let ba: () -> Void 
    
        override init(frame: CGRect) {
            super.init(frame: frame)
            ba = {     
                // ... while ba holds a strong reference to the instance (self)           
                self.str.trimmingCharacters(in: CharacterSet.alphanumerics)
            }
        }
    
        func foo() {
            ba()
        }
    }
    

    在这种情况下,您必须像您一样在闭包内通过weakifying self 打破循环。


    如何防止这种回调地狱,你能带我看一些阅读材料

    结帐DispatchGroups。

    (Apple Documentation)

    【讨论】:

    • 这提醒了我阅读的另一篇博文,引用循环仅在您尝试在对象层次结构中引用两个方向时发生,而不是在单个方向上发生
    • 那是cycle的定义。
    【解决方案2】:

    为我的问题 #2 找到了一个非常巧妙的解决方案

    https://github.com/duemunk/Async

    示例 sn-p:

    Async.userInitiated {
        return 10
    }.background {
        return "Score: \($0)"
    }.main {
        label.text = $0
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-16
      • 1970-01-01
      • 1970-01-01
      • 2020-09-30
      • 2021-11-05
      • 1970-01-01
      相关资源
      最近更新 更多