在Swift中传递值类型作为引用

时间:2017-04-13 18:54:44

标签: swift struct pass-by-reference value-type

我在Swift 3.0中将我的模型实现为structs。其中一些structs的代表应该能够根据用户的操作修改模型。

但是,当我将struct传递给delegate方法时,它会被复制。

你是如何解决这个问题的?您是否可以强制编译器将此struct作为参考传递,或者唯一的选择是使用class

3 个答案:

答案 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

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/ClassesAndStructures.html州:

  

您可以使用类和结构来定义自定义数据类型   用作程序代码的构建块。

     

但是,结构实例总是按值和类传递   实例总是通过引用传递。这意味着他们是   适合不同类型的任务。在考虑数据时   您决定项目所需的构造和功能   是否应将每个数据结构定义为类或类   结构