You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift5中如何在不同传感器类实例间复制指定属性值

优化Sensor实例属性复制的方案

针对手动复制属性扩展性差的问题,这里提供几个Swift原生的优化方案,无需依赖反射即可实现灵活的属性复制:

方案1:将可复制属性封装为独立结构体

把所有需要跨实例复制的属性统一封装到一个结构体中,复制时只需赋值整个结构体实例,新增属性时仅需修改结构体定义,无需改动复制逻辑。

修改后的代码示例:

// 封装可复制的元数据属性
struct SensorMetadata {
    var bluetoothDeviceSerialNumber: String = ""
    var hardwareVersion: String = ""
    var firmwareVersion: String = ""
    var softwareVersion: String = ""
    var alias: String = ""
    var lastConnectedDate: Date = Date()
    var exampleProperty1: Int = 0
    var exampleProperty2: Int = 0
    var exampleProperty3: Int = 0
    var exampleProperty4: Bool = false
    var exampleProperty5: Bool = false
}

public class Sensor {
    // 无需复制的属性
    public let peripheral: CBPeripheral    
    var sensorID: Int = 0
    var sensorImage: UIImage?
    var modelName: String = ""
    var sensorType: String = ""

    // 可复制的元数据
    var metadata: SensorMetadata = SensorMetadata()

    required public init(withPeripheral peripheral: CBPeripheral) {
        self.peripheral = peripheral
    }

    // 简化的复制方法
    func copyMetadata(from oldSensor: Sensor) {
        self.metadata = oldSensor.metadata
    }
}

class UV_Sensor: Sensor {
    required public init(withPeripheral peripheral: CBPeripheral){
        super.init(withPeripheral: peripheral)
        
        self.sensorID = 1
        self.sensorImage = UIImage(named: "UV_Sensor")
        self.modelName = "UVSensorModelName"
        self.sensorType = "UV"
    }
}

class TemperatureSensor: Sensor {
    required public init(withPeripheral peripheral: CBPeripheral){
        super.init(withPeripheral: peripheral)
        
        self.sensorID = 2
        self.sensorImage = UIImage(named: "Temp_Sensor")
        self.modelName = "TemperatureSensorModelName"
        self.sensorType = "Temp"
    }
}

方案2:使用KeyPath数组批量赋值

如果不想重构结构体,可以用Swift的KeyPath特性,定义一个包含所有需要复制属性的KeyPath数组,遍历数组完成批量赋值。新增属性时只需向数组中添加对应的KeyPath即可。

代码示例:

public class Sensor {
    // 无需复制的属性
    public let peripheral: CBPeripheral    
    var sensorID: Int = 0
    var sensorImage: UIImage?
    var modelName: String = ""
    var sensorType: String = ""

    // 可复制的属性
    var bluetoothDeviceSerialNumber: String = ""
    var hardwareVersion: String = ""
    var firmwareVersion: String = ""
    var softwareVersion: String = ""
    var alias: String = ""
    var lastConnectedDate: Date = Date()
    var exampleProperty1: Int = 0
    var exampleProperty2: Int = 0
    var exampleProperty3: Int = 0
    var exampleProperty4: Bool = false
    var exampleProperty5: Bool = false

    // 定义需要复制的属性KeyPath集合
    private static let copyableKeyPaths: [WritableKeyPath<Sensor, Any>] = [
        \.bluetoothDeviceSerialNumber,
        \.hardwareVersion,
        \.firmwareVersion,
        \.softwareVersion,
        \.alias,
        \.lastConnectedDate,
        \.exampleProperty1,
        \.exampleProperty2,
        \.exampleProperty3,
        \.exampleProperty4,
        \.exampleProperty5
    ]

    required public init(withPeripheral peripheral: CBPeripheral) {
        self.peripheral = peripheral
    }

    func copyPropertyValues(from oldSensor: Sensor) {
        for keyPath in Self.copyableKeyPaths {
            self[keyPath: keyPath] = oldSensor[keyPath: keyPath]
        }
    }
}

方案3:协议+扩展实现通用复制逻辑

如果需要更灵活的扩展(比如子类可以自定义复制属性),可以定义一个协议,要求实现复制属性的KeyPath集合,再通过扩展协议实现通用复制方法。

代码示例:

protocol CopyableSensor {
    static var copyableKeyPaths: [WritableKeyPath<Self, Any>] { get }
    func copyProperties(from old: Self)
}

extension CopyableSensor {
    func copyProperties(from old: Self) {
        for keyPath in Self.copyableKeyPaths {
            self[keyPath: keyPath] = old[keyPath: keyPath]
        }
    }
}

public class Sensor: CopyableSensor {
    // 无需复制的属性
    public let peripheral: CBPeripheral    
    var sensorID: Int = 0
    var sensorImage: UIImage?
    var modelName: String = ""
    var sensorType: String = ""

    // 可复制的属性
    var bluetoothDeviceSerialNumber: String = ""
    var hardwareVersion: String = ""
    var firmwareVersion: String = ""
    var softwareVersion: String = ""
    var alias: String = ""
    var lastConnectedDate: Date = Date()
    var exampleProperty1: Int = 0
    var exampleProperty2: Int = 0
    var exampleProperty3: Int = 0
    var exampleProperty4: Bool = false
    var exampleProperty5: Bool = false

    static var copyableKeyPaths: [WritableKeyPath<Sensor, Any>] {
        [
            \.bluetoothDeviceSerialNumber,
            \.hardwareVersion,
            \.firmwareVersion,
            \.softwareVersion,
            \.alias,
            \.lastConnectedDate,
            \.exampleProperty1,
            \.exampleProperty2,
            \.exampleProperty3,
            \.exampleProperty4,
            \.exampleProperty5
        ]
    }

    required public init(withPeripheral peripheral: CBPeripheral) {
        self.peripheral = peripheral
    }
}

额外提示

你原代码中的子类初始化存在问题:子类里的sensorID等变量是局部变量,并未赋值给基类的属性,需要改成self.sensorID = 1这类写法,否则基类属性无法被正确初始化。

内容的提问来源于stack exchange,提问作者Brock Larson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 09:05:33