Изменение значения в абстрактной структуре - PullRequest
0 голосов
/ 05 сентября 2018

У меня такая ситуация при работе со структурами и протоколами, и мне было интересно узнать, как я могу получить доступ и изменить значение в этом случае:

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 голосов
/ 05 сентября 2018

Документация говорит

Классы имеют дополнительные возможности, которых нет у структур:
- Подсчет ссылок позволяет использовать более одной ссылки на экземпляр класса.

Таким образом, 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.
...