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
相关产品推荐
相关产品推荐

