我在Swift 3.0中将我的模型实现为structs
。其中一些structs
的代表应该能够根据用户的操作修改模型。
但是,当我将struct
传递给delegate
方法时,它会被复制。
你是如何解决这个问题的?您是否可以强制编译器将此struct
作为参考传递,或者唯一的选择是使用class
?
答案 0 :(得分:4)
struct
总是按值传递。使用struct
的重点是使其表现为值类型。如果你需要委托(通常意味着可变状态),你应该使用一个类。
如果确实需要,您可以使用inout
参数强制传递引用,但一般不建议这样做。您还可以使用box type来模拟按引用传递。但是,一般来说,如果需要引用行为,则应该使用一个类。
答案 1 :(得分:2)
首先使用struct的重点是这是理想的行为。它保留了数据的不变性。 inout
可以实现这一点,但在一般情况下不建议这样做。
protocol Delegate {
func callback(_ oldValue: Int) -> Int
}
struct IncrementerDelegate: Delegate {
let step: Int
func callback(_ oldValue: Int) -> Int {
return oldValue + step
}
}
struct Model {
var i = 0
}
class Controller {
var model = Model()
var delegate: Delegate
init(delegate: Delegate) {
self.delegate = delegate
}
// To be called externally, such as by a button
func doSomething() {
// Delegate determains new value, but it's still the
// controller's job to perform the mutation.
model.i = delegate.callback(model.i)
}
}
let delegate = IncrementerDelegate(step: 5)
let controller = Controller(delegate: delegate)
print(controller.model.i)
controller.doSomething() // simulate button press
print(controller.model.i)
protocol CrappyDelegate {
func callback(_ model: inout Model)
}
struct CrappyIncrementerDelegate: CrappyDelegate {
let step: Int
func callback(_ model: inout Model) {
model.i = 9999999
// Just hijacked the models value,
// and the controller can't do anything about it.
}
}
class VulnerableController {
var model = Model()
var delegate: CrappyDelegate
init(delegate: CrappyDelegate) {
self.delegate = delegate
}
// To be called externally, such as by a button
func doSomething() {
// Controller leaks entire model, and has no control over what happens to it
delegate.callback(&model)
}
}
let crappyDelegate = CrappyIncrementerDelegate(step: 5)
let vulnerableController = VulnerableController(delegate: crappyDelegate)
print(controller.model.i)
controller.doSomething() // simulate button press
print(controller.model.i) // model hijacked
答案 2 :(得分:0)
如果您想通过引用传递,通常应使用class
而不是struct
。
您可以使用类和结构来定义自定义数据类型 用作程序代码的构建块。
但是,结构实例总是按值和类传递 实例总是通过引用传递。这意味着他们是 适合不同类型的任务。在考虑数据时 您决定项目所需的构造和功能 是否应将每个数据结构定义为类或类 结构