Swift 设置委托会生成编译错误
我想使用策略模式来注册一组实现协议的对象。当我设置该协议时,在尝试设置作为协议一部分的委托时,会出现编译错误 出于讨论的目的,我稍微修改了Swift电子书代表团一章中的骰子游戏。重要的变化是:Swift 设置委托会生成编译错误,swift,delegates,Swift,Delegates,我想使用策略模式来注册一组实现协议的对象。当我设置该协议时,在尝试设置作为协议一部分的委托时,会出现编译错误 出于讨论的目的,我稍微修改了Swift电子书代表团一章中的骰子游戏。重要的变化是: 协议骰子游戏-声明一个委托 类SnakesAndLadders实现DiceGame(因此协议和委托) 类游戏包含3个蛇和梯子的实例 1) 一类具体的蛇和梯子 2) 博弈中的一个let常数 3) 协议博弈的一个“var”变量 如果我们使用具体的类(snakesAndLadders),我们可以设置委托。但
- 协议骰子游戏-声明一个委托
- 类SnakesAndLadders实现DiceGame(因此协议和委托)
- 类游戏包含3个蛇和梯子的实例 1) 一类具体的蛇和梯子 2) 博弈中的一个let常数 3) 协议博弈的一个“var”变量
class Dice
{
func roll() -> Int
{
return 7 // always win :)
}
}
protocol DiceGame
{
// all DiceGames must work with a DiceGameDelegate
var delegate:DiceGameDelegate? {get set}
var dice: Dice {get}
func play()
}
protocol DiceGameDelegate
{
func gameDidStart( game:DiceGame )
func gameDidEnd( game:DiceGame )
}
class SnakesAndLadders:DiceGame
{
var delegate:DiceGameDelegate?
let dice = Dice()
func play()
{
delegate?.gameDidStart(self)
playGame()
delegate?.gameDidEnd(self)
}
private func playGame()
{
print("Playing the game here...")
}
}
class Games : DiceGameDelegate
{
let snakesAndLadders = SnakesAndLadders()
// hold the protocol, not the class
let diceGameAsLet:DiceGame = SnakesAndLadders()
var diceGameAsVar:DiceGame = SnakesAndLadders()
func setupDelegateAsClass()
{
// can assign the delegate if using the class
snakesAndLadders.delegate = self
}
func setupDelegateAsVar()
{
// if we use 'var' we can assign the delegate
diceGameAsVar.delegate = self
}
func setupDelegateAsLet()
{
// DOES NOT COMPILE - Why?
//
// We are not changing the dice game so want to use 'let', but it won't compile
// we are changing the delegate, which is declared as 'var' inside the protocol
diceGameAsLet.delegate = self
}
// MARK: - DiceGameDelegate
func gameDidStart( game:DiceGame )
{
print("Game Started")
}
func gameDidEnd( game:DiceGame )
{
print("Game Ended")
}
}
问题是,当您将某个内容存储为
协议
时,即使它是一个类,swift也会将其视为值
类型,而不是您期望的引用
类型。因此,不允许对其任何部分进行更改。查看更多信息。DiceGame
是一种异构协议,您将其用作一种类型;Swift将把这个类型视为一个值类型,因此(就像对于一个结构一样),改变它的可变属性也会改变协议类型本身的实例
但是,如果您将:class
关键字添加到DiceGame
协议中,Swift会将其视为引用类型,允许您变异其实例的成员,而不会变异实例本身。请注意,这将约束协议,使其仅符合类类型
protocol DiceGame: class { ... }
添加上述内容后,将允许不可变的diceGameAsLet
:s属性发生突变
在此上下文中,值得一提的是,
:class
关键字通常用于约束用作委托的协议(例如,在您的示例中,DiceGameDelegate
),使其仅符合类类型。有了这一附加约束,委托可以用作委托所有者(例如某些类)仅持有弱
引用的类型,在对委托的强引用可能创建保留循环的上下文中非常有用
有关详细信息,请参见第二部分。Wow-答案很好。谢谢你准确地指出了我错过的微妙而重要的东西。协议“DiceGame”可能是一个结构,无法修改,因此编译器可以阻止我。我的目的是让这个协议只由类实现,这样就可以告诉编译器问题已经解决了,现在我可以干净地使用“let”变量,并且仍然修改委托属性。(协议DiceGame:class{…})委托
var委托:DiceGameDelegate?
应该是弱引用吗?添加protocol DiceGame:class
解决了编译问题,现在可以解释为什么了。@JimLeask是的,我认为这是合适的。Game
的实例拥有一个snakesandraddes
实例(例如snakesandraddes
):这是Game
实例对snakesandraddes
实例的有力引用。在Game
的setupDelegateAsClass()
函数中,您将snakesandgraddes
:sdelegate
属性的委托设置为Game
本身的实例:这是两个相同实例的另一个强引用,但方向相反;因此,我相信,创造了一个强有力的参照周期。看一看。