From a705e94fc41a9829d95e708429d006850a8ad7f5 Mon Sep 17 00:00:00 2001 From: Kevin Lundberg Date: Tue, 23 Apr 2024 15:13:27 -0400 Subject: [PATCH] Only capture the absolute necessary values inside closures, to avoid improperly caching or reusing of core bluetooth objects --- .../Interface+CentralManager.swift | 40 +++++++++--------- .../Peripheral/Interface+Peripheral.swift | 42 +++++++++---------- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/Sources/CombineCoreBluetooth/CentralManager/Interface+CentralManager.swift b/Sources/CombineCoreBluetooth/CentralManager/Interface+CentralManager.swift index a8e9648..267eda0 100644 --- a/Sources/CombineCoreBluetooth/CentralManager/Interface+CentralManager.swift +++ b/Sources/CombineCoreBluetooth/CentralManager/Interface+CentralManager.swift @@ -83,24 +83,24 @@ public struct CentralManager: Sendable { } public func connect(_ peripheral: Peripheral, options: PeripheralConnectionOptions? = nil) -> AnyPublisher { - Publishers.Merge( - didConnectPeripheral - .filter { $0 == peripheral } - .setFailureType(to: Error.self), - didFailToConnectPeripheral - .filter { p, _ in p == peripheral } - .tryMap { _, error in - throw error ?? CentralManagerError.unknownConnectionFailure - } - ) - .prefix(1) - .handleEvents(receiveSubscription: { _ in - _connectToPeripheral(peripheral, options) - }, receiveCancel: { - _cancelPeripheralConnection(peripheral) - }) - .shareCurrentValue() - .eraseToAnyPublisher() + Publishers.Merge( + didConnectPeripheral + .filter { [id = peripheral.id] p in p.id == id } + .setFailureType(to: Error.self), + didFailToConnectPeripheral + .filter { [id = peripheral.id] p, _ in p.id == id } + .tryMap { _, error in + throw error ?? CentralManagerError.unknownConnectionFailure + } + ) + .prefix(1) + .handleEvents(receiveSubscription: { _ in + _connectToPeripheral(peripheral, options) + }, receiveCancel: { + _cancelPeripheralConnection(peripheral) + }) + .shareCurrentValue() + .eraseToAnyPublisher() } public func cancelPeripheralConnection(_ peripheral: Peripheral) { @@ -117,10 +117,10 @@ public struct CentralManager: Sendable { public func monitorConnection(for peripheral: Peripheral) -> AnyPublisher { Publishers.Merge( didConnectPeripheral - .filter { p in p == peripheral } + .filter { [id = peripheral.id] p in p.id == id } .map { _ in true }, didDisconnectPeripheral - .filter { (p, error) in p == peripheral } + .filter { [id = peripheral.id] p, _ in p.id == id } .map { _ in false } ) .eraseToAnyPublisher() diff --git a/Sources/CombineCoreBluetooth/Peripheral/Interface+Peripheral.swift b/Sources/CombineCoreBluetooth/Peripheral/Interface+Peripheral.swift index 5578e64..16263c4 100644 --- a/Sources/CombineCoreBluetooth/Peripheral/Interface+Peripheral.swift +++ b/Sources/CombineCoreBluetooth/Peripheral/Interface+Peripheral.swift @@ -190,20 +190,20 @@ public struct Peripheral: Sendable { private func writeValueWithResponse(_ value: Data, for characteristic: CBCharacteristic) -> AnyPublisher { didWriteValueForCharacteristic - .filterFirstValueOrThrow(where: { - $0.uuid == characteristic.uuid - }) - .map { _ in } - .handleEvents(receiveSubscription: { [_writeValueForCharacteristic] _ in - _writeValueForCharacteristic(value, characteristic, .withResponse) - }) - .shareCurrentValue() + .filterFirstValueOrThrow(where: { [uuid = characteristic.uuid] in + $0.uuid == uuid + }) + .map { _ in } + .handleEvents(receiveSubscription: { [_writeValueForCharacteristic] _ in + _writeValueForCharacteristic(value, characteristic, .withResponse) + }) + .shareCurrentValue() } public func setNotifyValue(_ enabled: Bool, for characteristic: CBCharacteristic) -> AnyPublisher { didUpdateNotificationState - .filterFirstValueOrThrow(where: { - $0.uuid == characteristic.uuid + .filterFirstValueOrThrow(where: { [uuid = characteristic.uuid] in + $0.uuid == uuid }) .map { _ in } .handleEvents(receiveSubscription: { [_setNotifyValue] _ in @@ -214,8 +214,8 @@ public struct Peripheral: Sendable { public func discoverDescriptors(for characteristic: CBCharacteristic) -> AnyPublisher<[CBDescriptor]?, Error> { didDiscoverDescriptorsForCharacteristic - .filterFirstValueOrThrow(where: { - $0.uuid == characteristic.uuid + .filterFirstValueOrThrow(where: { [uuid = characteristic.uuid] in + $0.uuid == uuid }) .map(\.descriptors) .handleEvents(receiveSubscription: { [_discoverDescriptors] _ in @@ -226,8 +226,8 @@ public struct Peripheral: Sendable { public func readValue(for descriptor: CBDescriptor) -> AnyPublisher { didUpdateValueForDescriptor - .filterFirstValueOrThrow(where: { - $0.uuid == descriptor.uuid + .filterFirstValueOrThrow(where: { [uuid = descriptor.uuid] in + $0.uuid == uuid }) .map(\.value) .handleEvents(receiveSubscription: { [_readValueForDescriptor] _ in @@ -238,8 +238,8 @@ public struct Peripheral: Sendable { public func writeValue(_ value: Data, for descriptor: CBDescriptor) -> AnyPublisher { didWriteValueForDescriptor - .filterFirstValueOrThrow(where: { - $0.uuid == descriptor.uuid + .filterFirstValueOrThrow(where: { [uuid = descriptor.uuid] in + $0.uuid == uuid }) .map { _ in } .handleEvents(receiveSubscription: { [_writeValueForDescriptor] _ in @@ -292,7 +292,7 @@ public struct Peripheral: Sendable { discoverCharacteristics(withUUIDs: [characteristicUUID], inServiceWithUUID: serviceUUID) .tryMap { characteristics in // assume core bluetooth won't send us a characteristic list without the characteristic we expect - guard let characteristic = characteristics.first(where: { characteristic in characteristic.uuid == characteristicUUID }) else { + guard let characteristic = characteristics.first(where: { c in c.uuid == characteristicUUID }) else { throw PeripheralError.characteristicNotFound(characteristicUUID) } return characteristic @@ -405,8 +405,8 @@ public struct Peripheral: Sendable { public func listenForUpdates(on characteristic: CBCharacteristic) -> AnyPublisher { didUpdateValueForCharacteristic // not limiting to `.first()` here as callers may want long-lived listening for value changes - .filter({ (readCharacteristic, error) -> Bool in - return readCharacteristic.uuid == characteristic.uuid + .filter({ [uuid = characteristic.uuid] (readCharacteristic, error) -> Bool in + readCharacteristic.uuid == uuid }) .selectValueOrThrowError() .map(\.value) @@ -438,8 +438,8 @@ public struct Peripheral: Sendable { self.listenForUpdates(on: characteristic), didUpdateNotificationState - .filterFirstValueOrThrow(where: { - $0.uuid == characteristic.uuid + .filterFirstValueOrThrow(where: { [uuid = characteristic.uuid] in + $0.uuid == uuid }) .ignoreOutput(setOutputType: Data?.self) )