iOS BLE app - I can get notifications from a characteristic, but can't read it
<p>I've been working on an iOS app that interfaces with a BLE device. The device has 1 service with 5 characteristics. Three of them are read/notify, while the other two are read/write/notify.</p>

<p>When I first launch the app, I need to read the 5 characteristics, then listen for future notifications.  For some reason, the read is not working (no response to <code>readValueForCharacteristic</code>), but the notifications do work (changes on the device show up in the app).</p>

<p>Also unusual - I never receive calls to <code>didUpdateNotificationStateForCharacteristic</code>, despite the fact that the notifications do indeed work.</p>

<p>I also am unable to write to the 2 writable characteristics, though that isn't my primary concern right now.  I've verified none of these problems are on the device end, because I can perform them using the LightBlue.app</p>

<p>Here's my code:</p>

<pre><code>import UIKit
import CoreBluetooth

class ViewController: UIViewController, CBCentralManagerDelegate, CBPeripheralDelegate {

// GUI elements
@IBOutlet var statusLabel: UILabel!
@IBOutlet var char1Field: UITextField!
@IBOutlet var char2Field: UITextField!
@IBOutlet var char3Field: UITextField!
@IBOutlet var char4Selector: UISegmentedControl!
@IBOutlet var char5Field: UITextField!

// BLE
var centralManager : CBCentralManager!
var myPeriph : CBPeripheral!

var char3 : CBCharacteristic!
var char4 : CBCharacteristic!

var value1 : UInt32 = 0
var value2 : UInt32 = 0
var value3 : Float32 = 0
var value4 : UInt8 = 0
var value5 : UInt8 = 0


override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    // Initialize central manager on load
    centralManager = CBCentralManager(delegate: self, queue: nil)
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


@IBAction func char3FieldChanged(sender: AnyObject) {

    if char3Field.text == "" {
        value3 = 0
    } else {
        value3 = Float32(char3Field.text!)!
    }

    let wtBytes = NSData(bytes: &amp;value3, length: sizeof(UInt8))
    char3Field.text = String(format: "%0.1f", arguments: [value3])

    if char3 != nil {
        self.myPeriph.writeValue(wtBytes, forCharacteristic: char3, type: CBCharacteristicWriteType.WithoutResponse)
    }
}


@IBAction func char4SelectorChanged(sender: AnyObject) {

    value4 = UInt8(char4Selector.selectedSegmentIndex)
    let char4Bytes = NSData(bytes: &amp;value4, length: sizeof(UInt8))

    if char4 != nil {
        self.myPeriph.writeValue(char4Bytes, forCharacteristic: char4, type: CBCharacteristicWriteType.WithoutResponse)
    }
}




/******* CBCentralManagerDelegate *******/

// Check status of BLE hardware
func centralManagerDidUpdateState(central: CBCentralManager) {
    if central.state == CBCentralManagerState.PoweredOn {
        // Scan for peripherals if BLE is turned on
        central.scanForPeripheralsWithServices(nil, options: nil)
        self.statusLabel.text = "Searching for BLE Devices"
    }
    else {
        // Can have different conditions for all states if needed - show generic alert for now
        showAlertWithText("Error", message: "Bluetooth switched off or not initialized")
    }
}


// Check out the discovered peripherals to find Sensor Tag
func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber) {

    if MyPeriph.NameFound(advertisementData) == true {

        // Update Status Label
        self.statusLabel.text = "Device Found"

        // Stop scanning, set as the peripheral to use and establish connection
        self.centralManager.stopScan()
        self.myPeriph = peripheral
        self.myPeriph.delegate = self
        self.centralManager.connectPeripheral(peripheral, options: nil)
    }
    else {
        self.statusLabel.text = "Device NOT Found"

    }
}

// Discover services of the peripheral
func centralManager(central: CBCentralManager, didConnectPeripheral peripheral: CBPeripheral) {
    self.statusLabel.text = "Discovering peripheral services"
    peripheral.discoverServices(nil)
    print("Searching for peripheral")
}


// If disconnected, start searching again
func centralManager(central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: NSError?) {
    self.statusLabel.text = "Disconnected"
    central.scanForPeripheralsWithServices(nil, options: nil)
    print("Disconnected")
}

/******* CBCentralPeripheralDelegate *******/

// Check if the service discovered is valid
func peripheral(peripheral: CBPeripheral, didDiscoverServices error: NSError?) {
    self.statusLabel.text = "Looking at peripheral services"
    for service in peripheral.services! {
        let thisService = service as CBService
        if MyPeriph.validService(thisService) {
            // Discover characteristics of all valid services
            peripheral.discoverCharacteristics(nil, forService: thisService)
            print("Peripheral service found, searching for characteristics")
        }
    }
}


func peripheral(peripheral: CBPeripheral, didUpdateNotificationStateForCharacteristic characteristic: CBCharacteristic, error: NSError?) {
    print("Did update notify status for \(characteristic.description)")
}

func peripheral(peripheral: CBPeripheral, didUpdateValueForDescriptor descriptor: CBDescriptor, error: NSError?) {
    print("Did update value for descriptor")
}

// Enable notification and sensor for each characteristic of valid service
func peripheral(peripheral: CBPeripheral, didDiscoverCharacteristicsForService service: CBService, error: NSError?) {

    self.statusLabel.text = "Configuring..."

    print("Found \(service.characteristics?.count) characteristics")

    for characteristic in service.characteristics! {
        let thisCharacteristic = characteristic as CBCharacteristic

        self.myPeriph.readValueForCharacteristic(thisCharacteristic)
        self.myPeriph.discoverDescriptorsForCharacteristic(thisCharacteristic)

        switch characteristic.UUID {
        case Char1Uuid:
            self.myPeriph.setNotifyValue(true, forCharacteristic: thisCharacteristic)
        case Char2Uuid:
            self.myPeriph.setNotifyValue(true, forCharacteristic: thisCharacteristic)
        case Char3Uuid:
            self.myPeriph.setNotifyValue(true, forCharacteristic: thisCharacteristic)
            char3 = characteristic
        case Char4Uuid:
            self.myPeriph.setNotifyValue(true, forCharacteristic: thisCharacteristic)
            char4 = characteristic
        case Char5Uuid:
            self.myPeriph.setNotifyValue(true, forCharacteristic: thisCharacteristic)
        default: break
        }
    }
}

// Get data values when they are updated
func peripheral(peripheral: CBPeripheral, didUpdateValueForCharacteristic characteristic: CBCharacteristic, error: NSError?) {

    self.statusLabel.text = "Connected"

    switch characteristic.UUID {
    case Char1Uuid:
        value1 = MyPeriph.getvalue1(characteristic.value!)
        char1Field.text = String(value1)
    case Char2Uuid:
        value2 = MyPeriph.getvalue2(characteristic.value!)
        char2Field.text = String(value2)
    case Char3Uuid:
        value3 = MyPeriph.getvalue3(characteristic.value!)
        char3Field.text = String(value3)
        char3 = characteristic
    case Char4Uuid:
        value4 = MyPeriph.getvalue4(characteristic.value!)
        if value4 == 0 {
            char4Selector.selectedSegmentIndex = 0
        } else {
            char4Selector.selectedSegmentIndex = 1
        }
        char4 = characteristic
    case Char5Uuid:
        value5 = MyPeriph.getvalue5(characteristic.value!)
        char5Field.text = String(value5)
    default: break
    }
}


/******* Helper *******/

// Show alert
func showAlertWithText (header : String = "Warning", message : String) {
    let alert = UIAlertController(title: header, message: message, preferredStyle: UIAlertControllerStyle.Alert)
    alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil))
    alert.view.tintColor = UIColor.redColor()
    self.presentViewController(alert, animated: true, completion: nil)
}


}
</code></pre>