嵌套回调强引用循环
Nested callback strong reference cycle
@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)
}
我有这个回调地狱,我想知道
回调地狱最顶部的 [weak self]
& guard let strongSelf
是否通过 GCD 的异步回调阻止了强引用循环。我在这里读了一些其他的 post ,也是一本书中的一篇,说如果我在回调中引用的对象可以 deinit
成功,这意味着没有强引用循环的好兆头,是吗还是真的吗?
如何防止这种回调地狱,你能引导我阅读一些material或我错过的话题吗?类似于 javascript 的承诺链接语法?
据我所知,没有保留周期,因此不需要弱化 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()
}
}
在这种情况下,您必须像您所做的那样,通过在闭包中 weak
化 self
来打破循环。
How to prevent this kind of callback hell, can you lead me to some reading material
结帐 DispatchGroup
秒。
为我的问题 #2 找到了一个非常巧妙的解决方案
https://github.com/duemunk/Async
示例片段:
Async.userInitiated {
return 10
}.background {
return "Score: \([=10=])"
}.main {
label.text = [=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)
}
我有这个回调地狱,我想知道
回调地狱最顶部的
[weak self]
&guard let strongSelf
是否通过 GCD 的异步回调阻止了强引用循环。我在这里读了一些其他的 post ,也是一本书中的一篇,说如果我在回调中引用的对象可以deinit
成功,这意味着没有强引用循环的好兆头,是吗还是真的吗?如何防止这种回调地狱,你能引导我阅读一些material或我错过的话题吗?类似于 javascript 的承诺链接语法?
据我所知,没有保留周期,因此不需要弱化 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()
}
}
在这种情况下,您必须像您所做的那样,通过在闭包中 weak
化 self
来打破循环。
How to prevent this kind of callback hell, can you lead me to some reading material
结帐 DispatchGroup
秒。
为我的问题 #2 找到了一个非常巧妙的解决方案
https://github.com/duemunk/Async
示例片段:
Async.userInitiated {
return 10
}.background {
return "Score: \([=10=])"
}.main {
label.text = [=10=]
}