在抽象结构中修改值

时间:2018-09-05 10:38:21

标签: ios swift swift-protocols

在使用结构和协议时,我遇到了这种情况,并很好奇在这种情况下如何访问和修改值:

import Foundation

struct Garage {
    var vehicles : [VehicleProtocol]
}

protocol VehicleProtocol {
    var id: String { get }
}

protocol TwoWheelsProtocol: VehicleProtocol {
    var id: String { get }
    var uniqueTwoWheelsAttribut: String { get set     }
}

struct TwoWheels: TwoWheelsProtocol {
    var id: String
    var uniqueTwoWheelsAttribut: String
}

protocol FourWheelsProtocol: VehicleProtocol {
    var uniqueFourWheelsAttribut: String { get set }
}

struct FourWheels: FourWheelsProtocol {
    var id: String
    var uniqueFourWheelsAttribut: String
}

func printVehicules(of garage: Garage) {
    for vehicle in garage.vehicles {
        if vehicle is TwoWheelsProtocol {
            let tw = vehicle as! TwoWheelsProtocol
            print("\(tw.id) | \(tw.uniqueTwoWheelsAttribut)")
        }

        if vehicle is FourWheelsProtocol {
            let tw = vehicle as! FourWheelsProtocol
            print("\(tw.id) | \(tw.uniqueFourWheelsAttribut)")
        }
    }
}

let vehicle0 = TwoWheels(id: "0", uniqueTwoWheelsAttribut: "vehicle0")
let vehicle1 = FourWheels(id: "1", uniqueFourWheelsAttribut: "vehicle1")

var a = Garage(vehicles: [vehicle0, vehicle1])

printVehicules(of: a)

printVehicules(of: a)的结果是:

0 | vehicle0
1 | vehicle1

如何将Vehicle0 uniqueTwoWheelsAttribut修改为:

0 | modified
1 | vehicle1

我可以使用

if a is TwoWheelsProtocol {
    let tw as! TwoWheelsProtocol
    ......
}

但是由于强制转换结果在另一个变量中,因此修改不会影响原点值。

1 个答案:

答案 0 :(得分:0)

documentation

  

类具有结构所没有的其他功能:
  -引用计数允许对一个类实例进行多个引用。

由于let tw as! TwoWheelsProtocol是一个结构,因此TwoWheels总是创建一个新对象。为避免这种情况,您可以将TwoWheels变成一个班级:

class TwoWheels: TwoWheelsProtocol {
    var id: String
    var uniqueTwoWheelsAttribut: String

    init(id: String, uniqueTwoWheelsAttribut: String) {
        self.id = id
        self.uniqueTwoWheelsAttribut = uniqueTwoWheelsAttribut
    }
}

现在let tw as! TwoWheelsProtocol不会创建新副本,而只会创建对该对象的新引用。

您可以改进的地方

要求VehicleProtocol仅允许类实现协议。这样,您可以确定强制转换和所做的更改确实确实更改了所引用的对象,而不仅仅是它的副本。

protocol VehicleProtocol: class {
    var id: String { get }
}

您可以使用更紧凑的铸造方法。

if var tw = vehicle as? TwoWheelsProtocol {
    // Modify tw.
}

guard var tw = vehicle as? TwoWheelsProtocol else {
    return
}
// Modify tw.