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

如何避免多个自定义类重复实现BLE协议的必需方法?

解决方案:复用BLE协议实现的最佳实践

嘿,这个问题问到点子上了——复用协议实现绝对是iOS开发里减少冗余代码、降低维护成本的关键,尤其是你说未来还要加更多类似类的情况。咱们先把问题拆开来聊:

一、复制粘贴可行吗?

短期来看,复制粘贴确实能让你的新MotorViewController快速跑起来,但长期绝对是个大坑:

  • 冗余代码:每个类里都有几乎一样的协议方法实现,项目体积无端膨胀;
  • 维护噩梦:如果后续需要修改BLE逻辑(比如新增协议方法、调整扫描策略),你得手动修改所有复制过代码的类,很容易漏改导致bug;
  • 违反DRY(Don't Repeat Yourself)原则,这是开发里的大忌。

所以除非是临时测试用,否则完全不推荐复制粘贴。

二、复用协议方法的最佳方案

针对你的场景(多个类逻辑流程一致,仅数据处理/属性不同),有两种非常合适的方案,推荐优先用第一种:

方案1:协议扩展 + 自定义协议(最灵活)

利用Swift的协议扩展特性,把CBCentralManagerDelegate和CBPeripheralDelegate的通用逻辑抽离到扩展里,再通过一个自定义协议让各个类实现自己的专属逻辑。

步骤如下:

  1. 定义一个自定义协议,规定每个类需要实现的专属方法:
// 自定义协议,让需要处理BLE数据的类遵守
protocol BLEDataHandler: CBCentralManagerDelegate, CBPeripheralDelegate {
    /// 处理收到的BLE数据,由子类实现专属解析逻辑
    func handleBLEData(_ data: Data)
    // 可以根据需求添加其他必须实现的属性/方法,比如蓝牙服务UUID、特征UUID等
}
  1. 给两个BLE协议写扩展,实现通用逻辑:
// 扩展CBCentralManagerDelegate,实现通用的蓝牙状态管理、扫描逻辑
extension CBCentralManagerDelegate where Self: BLEDataHandler {
    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        switch central.state {
        case .poweredOn:
            // 通用扫描逻辑,比如扫描指定服务UUID的外设
            central.scanForPeripherals(withServices: [YourServiceUUID], options: nil)
        case .poweredOff:
            // 通用提示逻辑,比如弹窗提示用户打开蓝牙
            print("蓝牙已关闭,请打开后重试")
        default:
            print("蓝牙状态异常:\(central.state.rawValue)")
        }
    }
    
    // 其他通用的CBCentralManagerDelegate方法,比如发现外设的逻辑
    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
        // 通用连接逻辑,比如判断外设名称后连接
        if peripheral.name == "YourPSoC4Device" {
            central.stopScan()
            connectedPeripheral = peripheral
            peripheral.delegate = self
            central.connect(peripheral, options: nil)
        }
    }
}

// 扩展CBPeripheralDelegate,实现通用的服务/特征发现、数据接收逻辑
extension CBPeripheralDelegate where Self: BLEDataHandler {
    func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
        guard let services = peripheral.services else { return }
        // 通用服务发现逻辑,遍历服务找目标特征
        for service in services {
            if service.uuid == YourServiceUUID {
                peripheral.discoverCharacteristics([YourCharacteristicUUID], for: service)
            }
        }
    }
    
    func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
        guard let characteristics = service.characteristics else { return }
        // 通用特征订阅逻辑,订阅目标特征的通知
        for characteristic in characteristics {
            if characteristic.uuid == YourCharacteristicUUID {
                peripheral.setNotifyValue(true, for: characteristic)
            }
        }
    }
    
    func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
        guard let data = characteristic.value else { return }
        // 调用自定义协议的方法,让子类处理专属数据
        self.handleBLEData(data)
    }
}
  1. 让你的ViewController遵守自定义协议,实现专属数据处理:
    比如PressureViewController:
class PressureViewController: UIViewController, BLEDataHandler {
    private var voltage: UInt32 = 0
    var centralManager: CBCentralManager!
    var connectedPeripheral: CBPeripheral?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        centralManager = CBCentralManager(delegate: self, queue: nil)
    }
    
    // 实现自定义协议的方法,处理电压数据
    func handleBLEData(_ data: Data) {
        // 将Data转成UInt32类型的电压值
        voltage = data.withUnsafeBytes { $0.load(as: UInt32.self) }
        // 这里可以更新UI或做其他业务逻辑
        updateVoltageUI()
    }
    
    private func updateVoltageUI() {
        // 更新UI的逻辑
    }
}

MotorViewController:

class MotorViewController: UIViewController, BLEDataHandler {
    private var radialPosition: UInt8 = 0
    var centralManager: CBCentralManager!
    var connectedPeripheral: CBPeripheral?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        centralManager = CBCentralManager(delegate: self, queue: nil)
    }
    
    // 实现自定义协议的方法,处理径向位置数据
    func handleBLEData(_ data: Data) {
        // 将Data转成UInt8类型的径向位置值
        radialPosition = data.withUnsafeBytes { $0.load(as: UInt8.self) }
        // 更新UI或其他业务逻辑
        updatePositionUI()
    }
    
    private func updatePositionUI() {
        // 更新UI的逻辑
    }
}

这种方案的优势是灵活性极高:

  • 不需要继承,避免了ViewController继承链复杂的问题;
  • 未来如果有非ViewController的类(比如ViewModel)需要处理BLE逻辑,也可以遵守BLEDataHandler协议直接复用;
  • 如果某个类需要特殊处理某个协议方法,直接在类里重写即可,会覆盖扩展里的默认实现。

方案2:基类继承(适合有共同UI/逻辑的场景)

如果你的多个ViewController除了BLE逻辑,还有其他共同的UI或业务逻辑,可以创建一个基类,让它实现BLE协议的通用方法,子类继承后重写专属逻辑:

class BLEBaseViewController: UIViewController, CBCentralManagerDelegate, CBPeripheralDelegate {
    var centralManager: CBCentralManager!
    var connectedPeripheral: CBPeripheral?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        centralManager = CBCentralManager(delegate: self, queue: nil)
    }
    
    // 通用的CBCentralManagerDelegate方法
    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        // 通用逻辑...
    }
    
    // 通用的CBPeripheralDelegate方法
    func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
        guard let data = characteristic.value else { return }
        // 调用子类必须实现的方法
        handleBLEData(data)
    }
    
    // 抽象方法,强制子类实现
    func handleBLEData(_ data: Data) {
        fatalError("子类必须实现handleBLEData方法")
    }
    
    // 其他通用方法...
}

然后子类继承基类:

class PressureViewController: BLEBaseViewController {
    private var voltage: UInt32 = 0
    
    override func handleBLEData(_ data: Data) {
        voltage = data.withUnsafeBytes { $0.load(as: UInt32.self) }
        updateVoltageUI()
    }
    
    private func updateVoltageUI() {
        // 更新UI逻辑
    }
}

这种方案的缺点是受限于Swift的单继承特性,如果你的ViewController已经继承了其他基类,就没法用了,所以灵活性不如协议扩展。

总结

  • 复制粘贴短期可行,但长期维护成本极高,不推荐;
  • 优先选择协议扩展+自定义协议的方案,灵活性最高,适合未来扩展;
  • 如果多个ViewController有大量共同UI/逻辑,再考虑基类继承的方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:23:23