gpt4 book ai didi

iOS/Swift - 闭包/完成 block 和委托(delegate)/函数之间有什么区别?

转载 作者:行者123 更新时间:2023-11-28 11:30:24 24 4
gpt4 key购买 nike

我不清楚这两个,现在世界正在转向闭包类型。但我不是很清楚这一点。有人可以用实时示例向我解释吗?

最佳答案

因此,两者的现实生活示例如下:

protocol TestDelegateClassDelegate: class {
func iAmDone()
}

class TestDelegateClass {
weak var delegate: TestDelegateClassDelegate?

func doStuff() {
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
self.delegate?.iAmDone()
}
}
}

class TestClosureClass {
var completion: (() -> Void)?

func doStuff() {
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
self.completion?()
}
}
}


class ViewController: UIViewController, TestDelegateClassDelegate {

func iAmDone() {
print("TestDelegateClassDelegate is done")
}

override func viewDidLoad() {
super.viewDidLoad()

let testingDelegate = TestDelegateClass()
testingDelegate.delegate = self
testingDelegate.doStuff()

let testingClosure = TestClosureClass()
testingClosure.completion = {
print("TestClosureClass is done")
}
testingClosure.doStuff()

}

}

这里我们有 2 个类 TestDelegateClassTestClosureClass。他们每个人都有一个方法 doStuff 等待 3 秒,然后向正在监听的人报告,其中一个使用委托(delegate)过程,另一个使用关闭过程。

虽然他们除了等待什么都不做,但您可以很容易地想象他们将图像上传到服务器并在完成时通知。因此,例如,您可能希望在上传过程中运行一个事件指示器,并在完成后停止它。它看起来像这样:

class ViewController: UIViewController, TestDelegateClassDelegate {

@IBOutlet private var activityIndicator: UIActivityIndicatorView?

func iAmDone() {
print("TestDelegateClassDelegate is done")
activityIndicator?.stopAnimating()
}

override func viewDidLoad() {
super.viewDidLoad()

activityIndicator?.startAnimating()
let testingDelegate = TestDelegateClass()
testingDelegate.delegate = self
testingDelegate.doStuff()

activityIndicator?.startAnimating()
let testingClosure = TestClosureClass()
testingClosure.completion = {
self.activityIndicator?.stopAnimating()
print("TestClosureClass is done")
}
testingClosure.doStuff()

}

}

自然地,您只会使用这两个过程中的一个。

你可以看到代码有很大的不同。要执行委托(delegate)过程,您需要创建一个协议(protocol),在本例中为 TestDelegateClassDelegate。协议(protocol)定义了监听器的接口(interface)。由于定义了 iAmDone 方法,因此必须在 ViewController 中定义它,并且只要它被定义为 TestDelegateClassDelegate。否则它不会编译。因此,任何声明为 TestDelegateClassDelegate 的东西都将具有该方法,并且任何类都可以调用它。在我们的例子中,我们有 weak var delegate: TestDelegateClassDelegate?。这就是为什么我们可以调用 delegate?.iAmDone() 而无需关心委托(delegate)到底是什么。例如我们可以创建另一个类:

class SomeClass: TestDelegateClassDelegate {
func iAmDone() {
print("Something cool happened")
}
init() {
let testingDelegate = TestDelegateClass()
testingDelegate.delegate = self
testingDelegate.doStuff()
}
}

一个很好的例子是 UITableView,它使用了 delegatedataSource(两者都是委托(delegate),只是属性命名不同) . TableView 将调用您为这些属性设置的任何类的方法,而无需知道该类是什么,只要它符合给定的协议(protocol)即可。

同样可以用闭包来实现。可以使用提供闭包的属性来定义 TableView ,例如:

tableView.onNumberOfRows { section in
return 4
}

但这很可能会导致代码困惑。在这种情况下,由于潜在的内存泄漏,闭包也会让许多程序员头疼。这并不是说闭包不太安全或其他什么,它们只是做了很多你看不到的代码,这些代码可能会产生保留循环。在这种特定情况下,最有可能的泄漏是:

tableView.onNumberOfRows { section in
return self.dataModel.count
}

修复它就是简单地做

tableView.onNumberOfRows { [weak self] section in
return self?.dataModel.count ?? 0
}

现在看起来过于复杂。

我不会深入探讨闭包,但最后当您重复调用回调时(例如在 TableView 的情况下),您将需要在委托(delegate)或闭包中使用 weak 链接。但是当闭包只被调用一次时(比如上传图片),闭包中就不需要 weak 链接(在大多数情况下,但不是所有情况下)。

在回顾中尽可能多地使用闭包,但一旦将闭包用作属性(具有讽刺意味的是我给出的示例),请避免或谨慎使用。但您更愿意这样做:

func doSomethingWithClosure(_ completion: @escaping (() -> Void)) {
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
completion()
}
}

并将其用作

    doSomethingWithClosure {
self.activityIndicator?.stopAnimating()
print("TestClosureClass is done")
}

这现在已经消除了所有潜在的风险。我希望这能为您清除一两件事。

关于iOS/Swift - 闭包/完成 block 和委托(delegate)/函数之间有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56946789/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com