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

iOS蓝牙开发:点击APP按钮无数据发至外设,外设与特征值为nil排查

Why Your Bluetooth Write Isn't Working (Peripheral/Characteristic Are Nil)

It sounds like the core issue here is that your TemperatureViewController isn’t properly accessing the Bluetooth objects managed in AppDelegate, or those objects aren’t being passed/updated correctly when the peripheral connects and characteristics are discovered. Let’s break down the exact causes and how to fix them:

Common Root Causes

  • Your ViewController has uninitialized, separate Bluetooth objects: The centralManager, heartRatePeripheral, and characteristic in TemperatureViewController are not linked to the working instances in AppDelegate—they’re never assigned values, so they stay nil.
  • No communication between AppDelegate and ViewController: When AppDelegate discovers a peripheral or characteristic, it doesn’t notify your ViewController to update its references.
  • You’re calling writeValue too early: If the button is pressed before the peripheral is connected and the target characteristic is fully discovered, those variables will still be nil.

Step-by-Step Fixes

1. Expose AppDelegate’s Bluetooth Instances

First, update your AppDelegate to make its Bluetooth properties accessible to other parts of the app, and ensure it properly tracks connected peripherals and characteristics:

import UIKit
import CoreBluetooth

@main
class AppDelegate: UIResponder, UIApplicationDelegate, CBCentralManagerDelegate, CBPeripheralDelegate {
    var window: UIWindow?
    var centralManager: CBCentralManager!
    var connectedPeripheral: CBPeripheral?
    var targetWriteCharacteristic: CBCharacteristic?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        centralManager = CBCentralManager(delegate: self, queue: nil)
        return true
    }

    // MARK: - CBCentralManagerDelegate
    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        if central.state == .poweredOn {
            // Replace with your peripheral's service UUID
            centralManager.scanForPeripherals(withServices: [CBUUID(string: "YOUR_SERVICE_UUID")])
        }
    }

    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
        centralManager.connect(peripheral, options: nil)
        connectedPeripheral = peripheral
        peripheral.delegate = self
    }

    func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
        peripheral.discoverServices([CBUUID(string: "YOUR_SERVICE_UUID")])
    }

    // MARK: - CBPeripheralDelegate
    func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
        guard let services = peripheral.services else { return }
        for service in services {
            // Replace with your characteristic's UUID
            peripheral.discoverCharacteristics([CBUUID(string: "YOUR_WRITE_CHAR_UUID")], for: service)
        }
    }

    func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
        guard let characteristics = service.characteristics else { return }
        for char in characteristics {
            if char.uuid == CBUUID(string: "YOUR_WRITE_CHAR_UUID") {
                targetWriteCharacteristic = char
                // Notify ViewController the characteristic is ready to use
                NotificationCenter.default.post(name: NSNotification.Name("CharacteristicReady"), object: nil)
            }
        }
    }
}

2. Update Your ViewController to Use AppDelegate’s Objects

Modify your TemperatureViewController to access the shared Bluetooth instances from AppDelegate, and add safeguards to avoid nil references:

import UIKit
import CoreBluetooth

class TemperatureViewController: UIViewController {
    // Remove local Bluetooth properties—we'll use AppDelegate's instead
    // var centralManager: CBCentralManager!
    // var heartRatePeripheral: CBPeripheral!
    // var characteristic: CBCharacteristic?

    @IBOutlet weak var sendValueButton: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Disable button until characteristic is ready
        sendValueButton.isEnabled = false
        // Listen for notification from AppDelegate when characteristic is discovered
        NotificationCenter.default.addObserver(self, selector: #selector(enableWriteButton), name: NSNotification.Name("CharacteristicReady"), object: nil)
    }

    @objc func enableWriteButton() {
        sendValueButton.isEnabled = true
    }

    // Button action to send value
    @IBAction func sendValueTapped(_ sender: UIButton) {
        writeValue(value: 25) // Example temperature value
    }

    func writeValue(value: Int8) {
        // Get reference to AppDelegate
        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
            print("Failed to access AppDelegate")
            return
        }

        // Validate all required objects exist and support writing
        guard let peripheral = appDelegate.connectedPeripheral,
              let characteristic = appDelegate.targetWriteCharacteristic,
              characteristic.properties.contains(.write) || characteristic.properties.contains(.writeWithoutResponse) else {
            print("Peripheral/Characteristic is nil or doesn't support writing")
            return
        }

        // Convert Int8 value to Data
        let data = Data(bytes: &value, count: MemoryLayout<Int8>.size)

        // Write to peripheral (use .withoutResponse if you don't need confirmation)
        peripheral.writeValue(data, for: characteristic, type: .withResponse)
    }
}

3. Key Additional Checks

  • Wait for proper initialization: Only enable the send button after the CharacteristicReady notification fires—this ensures the peripheral is connected and the characteristic is ready.
  • Verify UUIDs: Double-check that the service and characteristic UUIDs in your code match exactly what the Bluetooth peripheral is advertising. Mismatched UUIDs will prevent discovery.
  • Check characteristic properties: Ensure the peripheral’s characteristic actually supports writing (look for .write or .writeWithoutResponse in its properties).

Debugging Tips

  • Add print statements in AppDelegate’s delegate methods to confirm when the peripheral connects and the characteristic is discovered.
  • In your writeValue method, print peripheral and characteristic to confirm they’re not nil when the button is pressed.
  • Use Xcode’s debug navigator to inspect the state of AppDelegate’s Bluetooth objects at runtime.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 08:35:23