这两个代表声明有什么区别?
What's the difference between these two declarations of delegates?
我正在学习委托,但我不明白为什么
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
那个
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
对象没有强引用!因此,它会在创建后立即被释放。
您应该会在此处看到一条警告:
Instance will be immediately deallocated because property 'delegate' is 'weak'
另一方面,如果您先将新创建的 FriendsFunction
对象放入一个 let
常量中,
let friendsFunctions = FriendsFunctions()
let
常量 friendsFunctions
将是对 FriendsFunctions
对象的强引用,因为它不是 weak
。并且由于至少有一个强引用指向它,所以在所有强引用都消失之前,该对象不会被释放。
有关详细信息,请参阅 Swift 指南中的 Automatic Reference Counting。
ARC(用于自动引用计数)
ARC 是自动管理对象的内存分配/释放的系统。
它的工作方式是,只要您有 AT LEAST 1 对代码中对象的强引用,它就会 保留在内存中。 请注意,默认情况下,任何未定义为弱的 属性 定义都隐含地是强的。
当将 属性 指定为弱时,它不会将“持有引用计数”增加一。
您遇到的问题...
在您的 first 示例中,当您第一次创建一个 let 常量时,您持有一个 strong 引用,然后将其分配给弱变量。
然后你有 =>
- 1 对对象的弱引用(存储在
friendsFunctionsDelegate.delegate
)
- 1 对对象的强引用(let 常量
let friendsFunctions = FriendsFunctions()
)
因此,ARC NOT 释放对象(强引用 >= 1)=> 它正在工作 ✅
在您的 second 示例中,当您直接实例化 + 将委托分配给弱变量时 WITHOUT 首先创建一个常量。
然后你有 =>
- 1 对对象的弱引用(存储在
friendsFunctionsDelegate.delegate
)
- 0 对对象的强引用
结果,ARC在赋值后直接解除分配(从内存中释放)对象(强引用==0)=>不工作❌
结论
作为结论,您需要在某处保留对该委托对象的强引用。
委托模式中的弱使用
使用委派时,我们使用弱 属性 来防止内存保留循环。当您有一个对象(对象 A)持有对另一个对象(对象 B)的强引用,而该对象也对第一个对象(对象 A)具有强引用时,就会发生这种情况。
- A => B 强
- B => A 强
=> ⚠️保留周期⚠️
当您尝试从内存中删除对象 A 或 B 时,强引用计数仍为 1,然后您将遇到内存泄漏,内存中充满了未使用的对象,这可能会导致应用可用.解决方案是将这两个引用之一定义为弱引用(而不是两者)。应用委托模式时,您可以将持有对委托的引用的 属性 定义为弱。
一些额外的评论:
- 小心可能会产生误导的命名。 delegate 关键字应该仅附加到协议而不是 class 名称。如果您将其删除,尽管会有重叠,这暗示命名可以更恰当地定义。
- 当您将 属性 定义为 Optional 并且希望它默认为 nil 时,您不必明确指定
= nil
。虽然你仍然可以做到 ;)
- 最佳实践告诉您,当您希望 class 符合委托/协议时,您应该使用扩展而不是直接符合 class 定义。
- 委托模式应该是一种盲目的通信模式,因此您的 class 不应该知道超出范围的功能。然后委托方法的命名应修改为类似
func didBuyPizza()
和 func didTakeABreak()
或类似的东西。
我正在学习委托,但我不明白为什么
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
那个
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
对象没有强引用!因此,它会在创建后立即被释放。
您应该会在此处看到一条警告:
Instance will be immediately deallocated because property 'delegate' is 'weak'
另一方面,如果您先将新创建的 FriendsFunction
对象放入一个 let
常量中,
let friendsFunctions = FriendsFunctions()
let
常量 friendsFunctions
将是对 FriendsFunctions
对象的强引用,因为它不是 weak
。并且由于至少有一个强引用指向它,所以在所有强引用都消失之前,该对象不会被释放。
有关详细信息,请参阅 Swift 指南中的 Automatic Reference Counting。
ARC(用于自动引用计数)
ARC 是自动管理对象的内存分配/释放的系统。
它的工作方式是,只要您有 AT LEAST 1 对代码中对象的强引用,它就会 保留在内存中。 请注意,默认情况下,任何未定义为弱的 属性 定义都隐含地是强的。
当将 属性 指定为弱时,它不会将“持有引用计数”增加一。
您遇到的问题...
在您的 first 示例中,当您第一次创建一个 let 常量时,您持有一个 strong 引用,然后将其分配给弱变量。 然后你有 =>
- 1 对对象的弱引用(存储在
friendsFunctionsDelegate.delegate
) - 1 对对象的强引用(let 常量
let friendsFunctions = FriendsFunctions()
)
因此,ARC NOT 释放对象(强引用 >= 1)=> 它正在工作 ✅
在您的 second 示例中,当您直接实例化 + 将委托分配给弱变量时 WITHOUT 首先创建一个常量。 然后你有 =>
- 1 对对象的弱引用(存储在
friendsFunctionsDelegate.delegate
) - 0 对对象的强引用
结果,ARC在赋值后直接解除分配(从内存中释放)对象(强引用==0)=>不工作❌
结论
作为结论,您需要在某处保留对该委托对象的强引用。
委托模式中的弱使用
使用委派时,我们使用弱 属性 来防止内存保留循环。当您有一个对象(对象 A)持有对另一个对象(对象 B)的强引用,而该对象也对第一个对象(对象 A)具有强引用时,就会发生这种情况。
- A => B 强
- B => A 强
=> ⚠️保留周期⚠️
当您尝试从内存中删除对象 A 或 B 时,强引用计数仍为 1,然后您将遇到内存泄漏,内存中充满了未使用的对象,这可能会导致应用可用.解决方案是将这两个引用之一定义为弱引用(而不是两者)。应用委托模式时,您可以将持有对委托的引用的 属性 定义为弱。
一些额外的评论:
- 小心可能会产生误导的命名。 delegate 关键字应该仅附加到协议而不是 class 名称。如果您将其删除,尽管会有重叠,这暗示命名可以更恰当地定义。
- 当您将 属性 定义为 Optional 并且希望它默认为 nil 时,您不必明确指定
= nil
。虽然你仍然可以做到 ;) - 最佳实践告诉您,当您希望 class 符合委托/协议时,您应该使用扩展而不是直接符合 class 定义。
- 委托模式应该是一种盲目的通信模式,因此您的 class 不应该知道超出范围的功能。然后委托方法的命名应修改为类似
func didBuyPizza()
和func didTakeABreak()
或类似的东西。