我正在学习委托,我不明白为什么
let friendsFunctionsDelegate = FriendsFunctionsDelegate()
let friendsFunctions = FriendsFunctions()
friendsFunctionsDelegate.delegate = friendsFunctions
是正确的,而
let friendsFunctionsDelegate = FriendsFunctionsDelegate()
friendsFunctionsDelegate.delegate = FriendsFunction()
是错误的。
下面是完整的代码:
protocol FriendsDelegate: AnyObject {
func orderPizza()
func takeABreak()
}
class FriendsFunctionsDelegate {
weak var delegate: FriendsDelegate? = nil
func buyPizza() {
delegate?.orderPizza()
}
func sleep() {
delegate?.takeABreak()
}
}
class FriendsFunctions: FriendsDelegate {
func orderPizza() {
print("I ordered a pizza")
}
func takeABreak() {
print("I'm going to sleep")
}
}
let friendsFunctionsDelegate = FriendsFunctionsDelegate()
let friendsFunctions = FriendsFunctions()
friendsFunctionsDelegate.delegate = friendsFunctions
ARC (for Automatic Reference Counting)
是自动管理对象的内存分配/释放的系统。
的工作方式是,只要你有至少1对代码中对象的强引用将保留在内存中。请注意,默认情况下,任何未定义为弱的属性定义都是隐式强的。
当指定一个属性为弱属性时,它不会增加"保持引用计数"。。
您遇到的问题…
在你的第一个例如,当您第一次创建let常量时,您保存一个强引用,然后将其赋值给弱变量。=>
- 1对对象的弱引用(存储在
friendsFunctionsDelegate.delegate
上) - 1强引用对象(let constant
let friendsFunctions = FriendsFunctions()
)
因此,ARC是NOT释放对象(强引用>= 1) =>它正在工作✅
在秒例如,当您直接实例化+分配委托给弱变量时,没有首先创建一个常量。=>
- 1对对象的弱引用(存储在
friendsFunctionsDelegate.delegate
上) - 0对对象的强引用
因此,ARC正在释放(从内存中释放)赋值后的对象(强引用== 0)=>不工作❌
结论作为结论,您需要在某个地方保留对该委托对象的强引用。
委托模式中的弱用法
当使用委托时,我们使用弱属性来防止内存保留周期。当一个对象(对象A)持有对另一个对象(对象B)的强引用,而另一个对象(对象B)也有对第一个对象(对象A)的强引用时,就会发生这种情况。
- =比;B强劲
- B =比;一个强大的
=比;⚠️保留周期⚠️
当你试图从内存中删除对象A或B时,强引用计数将仍然为1,然后你将获得内存泄漏,内存中充满了未使用的对象,这可能导致可用的应用程序。解决方案是将这两个引用中的一个定义为弱引用(而不是两个)。当应用委托模式时,可以将持有委托引用的属性定义为weak。
一些额外的注释:
- 小心命名,可能会产生误导。delegate关键字应该只附加到协议后,而不是类名后。如果你删除它,虽然你会有重叠,这是一个暗示,命名可以更适当地定义。
- 当你将一个属性定义为Optional并且你希望它为nil作为默认值时,你不需要显式地指定
= nil
。虽然你仍然可以这样做;) - 最佳实践告诉你,当你想要一个类符合委托/协议时,你应该使用一个扩展,而不是直接遵循类定义。 委托模式应该是一种盲通信模式,所以你的类不应该知道作用域外的函数。然后,委托方法的命名应该修改为
func didBuyPizza()
和func didTakeABreak()
或类似的东西。let friendsFunctions = FriendsFunctions() // holds a strong reference
friendsFunctionsDelegate.delegate = friendsFunctions
可以工作,因为它保存了一个强引用,而
friendsFunctionsDelegate.delegate = FriendsFunction()
不能同时工作(lhs),rhs)是weak
,所以没有保留发生(delegate
是weak
属性)
注意FriendsFunctionsDelegate.delegate
属性是一个弱引用:
weak var delegate: FriendsDelegate? = nil
^^^^
如果你做了
friendsFunctionsDelegate.delegate = FriendsFunction()
您创建了一个FriendsFunction
对象,并且唯一有引用的对象是friendsFunctionsDelegate
,通过它的delegate
属性。但这是一个弱参考。没有对新的FriendsFunction
对象的强引用!因此,它将在创建后立即被释放。
你应该在这里看到一个警告:
实例将立即被释放,因为属性'delegate'是'weak'
另一方面,如果您先将新创建的FriendsFunction
对象放入let
常量中,
let friendsFunctions = FriendsFunctions()
let
常量friendsFunctions
将是对FriendsFunctions
对象的强引用,因为它不是weak
。由于至少有一个强引用指向该对象,因此在所有强引用消失之前,该对象不会被释放。
更多信息请参见Swift指南中的自动引用计数。