我不清楚这两个,现在世界正在转向闭包类型。但我不是很清楚这一点。有人可以用实时示例向我解释吗?
最佳答案
因此,两者的现实生活示例如下:
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 个类 TestDelegateClass
和 TestClosureClass
。他们每个人都有一个方法 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
,它使用了 delegate
和 dataSource
(两者都是委托(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/