[CoreBluetooth] Swift compilation error - Xcode is fine!

I’m trying to use this Playground on a Silver iOS based app (https://github.com/gregiOS/Playgrounds/tree/master/BLE.playground). Just copied the bluetooth parts and put the scanner on a Fire Sample iOS Tabbed App (FistViewController). There are some errors when compiling it with Fire, but the playground works flawlessly with Xcode 10.2.1.

==========================================

import Foundation
import CoreBluetooth

class BluetoothScanner: NSObject, CBCentralManagerDelegate {

public typealias DidDiscoverPeripheralClosure = (PeripheralRepresntable) -> Void
var centralManager: CBCentralManager!
private var onScannerReady: ((BluetoothScanner) -> Void)?
private var onDiscover: DidDiscoverPeripheralClosure?

public init(onScannerReady: @escaping (BluetoothScanner) -> Void) {
    self.onScannerReady = onScannerReady
    super.init()
    centralManager = CBCentralManager(delegate: self, queue: DispatchQueue.main)
}

open func centralManagerDidUpdateState(_ central: CBCentralManager) {
    switch central.state {
        case .poweredOn:
            onScannerReady?(self)
            onScannerReady = nil
        case .poweredOff:
            central.stopScan()
        case .unsupported: fatalError("Unsupported BLE module")
        default: break
    }
}

open func startScanning(_ onDiscover: @escaping DidDiscoverPeripheralClosure) {
    self.onDiscover = onDiscover
    centralManager.scanForPeripherals(withServices: nil, options: nil)
}

// MARK: - CBCentralManagerDelegate

public func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
    onDiscover?(peripheral.asPeripheral(advertisementData: advertisementData, rssi: RSSI.intValue))
}

}

============================================

RemObjects Elements (Oxygene, C#, Swift and Java) Compiler for .NET, Cocoa, Java and Island.
   Version 10.0.0.2415 (develop) built on bajor, 20190621-131308. Commit a346ebd.

No overloaded constructor with these parameters for type "CBCentralManager", best matching overload is "init(# delegate: ICBCentralManagerDelegate?, # queue: dispatch_queue_t!) -> instancetype!" [/Users/mneves/Development/SimpaxCrachaSwift/App/BluetoothScanner.swift (14)]
H: parameter 2 is "DispatchQueue" should be "dispatch_queue_t!" [/Users/mneves/Development/SimpaxCrachaSwift/App/BluetoothScanner.swift (14)]
E: Parameter labels case mismatch. Parameter 1 is labeled "withServices" but should should be "withServices" in call to "func scanForPeripherals(withServices serviceUUIDs: NSArray<CBUUID!>!, # options: NSDictionary<NSString!,id!>!)" [/Users/mneves/Development/SimpaxCrachaSwift/App/BluetoothScanner.swift (31)]
E: No member "uuidString" on type "NSUUID!" [/Users/mneves/Development/SimpaxCrachaSwift/App/Peripheral.swift (46)]
   Reference: /Applications/Fire.app/Contents/Resources/Toffee SDKs/iOS 12.2/CoreLocation.fx

Marcus,

my sincerest apologies for the delay in getting to this post.

any chance you could send the full project as you have it now — just too make sure I’m looking at the exact same test case as you?

thanx,
marc

Hello Marc,

I’ve attached to this email. Hope it helps!

Thank you again!

Best Regards,

Marcus.

SimpaxCrachaSwift.zip (134 KB)

Thanx.

centralManager.scanForPeripherals(withServices: nil, options: nil) 
// E598 Parameter labels do not match. Parameter 1 is labeled "withServices" but should should be "services" in call to "func scanForPeripherals(services serviceUUIDs: NSArray<CBUUID!>!, # options: NSDictionary<NSString!,id!>!)"

this is a case of Apple being inconsistent with how it mangles Cocoa names across to Swift, it seems. the rules very clearly state that “with” should be omitted from the name in such cases, which is why we map it to scanForPeripherals(services: nil, options: nil), which compiles OK. Apple apparently mapped this in violation of their own guidelines :(.

centralManager = CBCentralManager(delegate: self, queue: DispatchQueue.main)
// E407 No overloaded constructor with these parameters for type "CBCentralManager", best matching overload is "init(# delegate: ICBCentralManagerDelegate?, # queue: dispatch_queue_t!) -> instancetype!"
// H3 parameter 2 is "DispatchQueue" should be "dispatch_queue_t!"

this oe is a bit more complicated. DispatchQueue is a wrapper struct around GCD, so it’s not really assignment compatible with a dispatch_queue_t. Apparently Apple Swift does some more low-level hacking here.

I’ll add an implicit cast operator to our implementation of dispatch_queue_t, to make this functional for the next build. In the mean time, workaround would be to simply pass

centralManager = CBCentralManager(delegate: self, queue: DispatchQueue.main.queue).

or

centralManager = CBCentralManager(delegate: self, queue: dispatch_get_main_queue()).

Why these issues? it’s important to keep in mind that Silver and Apple Swift share the same syntax, but sit at very different levels of the technology stack. Apple’s Swift is in many places a very nasty hack and building a parallel platform next to the Objective-C runtime and Cocoa. Our compiler, for all languages including Swift, builds for the native Objective-C runtime and low-level C APIs, on the same level as Objective-C does. In a way, it is a lot more native to the platform than Apple Swift is right now,

hth,
marc

Thank you very much!!

I’ll try your recommendations as soon as possible.

Best regards !

1 Like