我想使用策略模式来注册一组实现协议的对象.当我设置它时,我在尝试设置作为协议一部分的委托时遇到编译错误.
出于讨论目的,我从Swift电子书的代表团章节略微重写了DiceGame.意义的变化是:
如果我们使用具体类(snakesAndLadders),我们可以设置委托.但是,如果我们使用'let'将其作为协议(diceGameAsLet)保存,则会出现编译错误,但如果我们将变量保存为'var'(diceGameAsVar),则会编译.
它很容易解决,但是,委托本身永远不会改变,因此应该保持为"let"常量,因为它只是内部属性发生变化.关于协议以及它们如何工作和应该如何使用,我一定不能理解(可能是微妙但重要的).
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")
}
}
Run Code Online (Sandbox Code Playgroud)
DiceGame是一种异类协议,您将其用作类型; Swift会将此类型视为值类型,因此(就像结构一样),更改其可变属性也会改变协议类型本身的实例.
但是,如果您将: class关键字添加到DiceGame协议中,Swift会将其视为引用类型,允许您变更实例的成员,而不会改变实例本身.请注意,这将制约该协议为适形于通过类类型而已.
protocol DiceGame: class { ... }
Run Code Online (Sandbox Code Playgroud)
通过添加上述内容,diceGameAsLet将允许不可变的s属性的变异.
在这种情况下,值得一提的是,: class关键字通常用于约束用作委托的协议(例如,DiceGameDelegate在您的示例中),仅适用于类类型.使用此附加约束,委托可以用作委托所有者(例如某些类)仅包含weak引用的类型,在对委托的强引用可以创建保留周期的上下文中有用.
有关详细信息,请参阅此答案的第2部分.