

現在、xcode8.1 swift3.0.1を使用しているプログラミング初心者です。  
逆引きswiftのcoreBluetooth 操作アプリのサンプルコードを入力しました。  
<http://docs.fabo.io/swift/corebluetooth/006_corebluetooth.html>  
コンパイル出来たのですが、実機の検索ボタンを押しても検出されません。  
デバックエリアには以下のような表記がなされます。  
[CoreBluetooth] XPC connection invalid  
state CBManagerState  
Bluetoothの電源はOn  
原因が全くわからないのですが、何か分かる方いらっしゃいますでしょうか？

[code]

    import UIKit
    import CoreBluetooth
    
    class ViewController: UIViewController, UITableViewDelegate, 　　UITableViewDataSource, CBCentralManagerDelegate, CBPeripheralDelegate{
    
    var myTableView: UITableView!
    var myUuids: [String] = []
    var myNames: [String] = []
    var myPeripheral: [CBPeripheral] = []
    var myCentralManager: CBCentralManager!
    var myTargetPeripheral: CBPeripheral!
    let myButton: UIButton = UIButton()
    
    let dataSets = NSMutableArray()
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
        // Status Barの高さを取得.
        let barHeight: CGFloat = UIApplication.shared.statusBarFrame.size.height
    
        // Viewの高さと幅を取得.
        let displayWidth = self.view.frame.width
        let displayHeight = self.view.frame.height
    
        // TableViewの生成( status barの高さ分ずらして表示 ).
        myTableView = UITableView(frame: CGRect(x: 0, y: barHeight, width: displayWidth, height: displayHeight - barHeight))
    
        // Cellの登録.
        myTableView.register(UITableViewCell.self, forCellReuseIdentifier: "MyCell")
    
        // DataSourceの設定.
        myTableView.dataSource = self
    
        // Delegateを設定.
        myTableView.delegate = self
    
        // Viewに追加する.
        self.view.addSubview(myTableView)
    
        // サイズ
        myButton.frame = CGRect(x:0,y:0,width:200,height:40)
        myButton.backgroundColor = UIColor.red;
        myButton.layer.masksToBounds = true
        myButton.setTitle("検索", for: UIControlState.normal)
        myButton.setTitleColor(UIColor.white, for: UIControlState.normal)
        myButton.layer.cornerRadius = 20.0
        myButton.layer.position = CGPoint(x: self.view.frame.width/2, y:self.view.frame.height-50)
        myButton.tag = 1
        myButton.addTarget(self, action: #selector(ViewController.onClickMyButton
            ), for: .touchUpInside)
    
        // UIボタンをViewに追加.
        self.view.addSubview(myButton);
    }
    
    /*
     ボタンイベント.
     */
    func onClickMyButton(sender: UIButton){
    
        // 配列をリセット.
    
        myUuids = []
        myNames = []
        myPeripheral = []
    
        // CoreBluetoothを初期化および始動.
    
        myCentralManager = CBCentralManager(delegate: self, queue: nil)
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    
    // MARK: - CBCentralManagerDelegate
    
    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        print("state \(central.state)");
        switch (central.state) {
        case .poweredOff:
            print("Bluetoothの電源がOff")
        case .poweredOn:
            print("Bluetoothの電源はOn")
            // BLEデバイスの検出を開始.
            myCentralManager.scanForPeripherals(withServices: nil, options:nil)
        case .resetting:
            print("レスティング状態")
        case .unauthorized:
            print("非認証状態")
        case .unknown:
            print("不明")
        case .unsupported:
            print("非対応")
        }
    }
    
    /*
     BLEデバイスが検出された際に呼び出される.
     */
    func centralManager(central: CBCentralManager,
                        didDiscoverPeripheral peripheral: CBPeripheral,
                        advertisementData: [String : AnyObject],
                        RSSI: NSNumber!)
    {
        print("pheripheral.name: \(peripheral.name)")
        print("advertisementData:\(advertisementData)")
        print("RSSI: \(RSSI)")
        print("peripheral.identifier.UUIDString: \(peripheral.identifier.uuidString)")
    
        let kCBAdvDataLocalName = advertisementData["kCBAdvDataLocalName"] as? String
        if let name = kCBAdvDataLocalName {
            myNames.append(name)
        } else {
            myNames.append("no name")
        }
    
        myPeripheral.append(peripheral)
        myUuids.append(peripheral.identifier.uuidString)
    
        myTableView.reloadData()
    }
    
    /*
     Cellが選択された際に呼び出される.
     */
    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) {
        print("Num: \(indexPath.row)")
        print("Uuid: \(myUuids[indexPath.row])")
        print("Name: \(myNames[indexPath.row])")
    
        self.myTargetPeripheral = myPeripheral[indexPath.row]
        myCentralManager.connect(self.myTargetPeripheral, options: nil)
    }
    
    /*
     Cellの総数を返す.
     */
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return myUuids.count
    }
    
    /*
     Cellに値を設定する.
     */
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell(style: UITableViewCellStyle.subtitle, reuseIdentifier:"MyCell" )
    
        // Cellに値を設定.
        cell.textLabel!.sizeToFit()
        cell.textLabel!.textColor = UIColor.red
        cell.textLabel!.text = "\(myNames[indexPath.row])"
        cell.textLabel!.font = UIFont.systemFont(ofSize: 20)
        // Cellに値を設定(下).
        cell.detailTextLabel!.text = "\(myUuids[indexPath.row])"
        cell.detailTextLabel!.font = UIFont.systemFont(ofSize: 12)
        return cell
    }
    
    /*
     Peripheralに接続
     */
    func centralManager(central: CBCentralManager, didConnectPeripheral peripheral: CBPeripheral) {
        print("connect")
    
        // 遷移するViewを定義する.
        let mySecondViewController: SecondViewController = SecondViewController()
    
        print("setPeripheral")
        mySecondViewController.setPeripheral(target: peripheral)
        mySecondViewController.setCentralManager(manager: central)
        mySecondViewController.searchService()
    
        // アニメーションを設定する.
        mySecondViewController.modalTransitionStyle = UIModalTransitionStyle.partialCurl
    
        print(self.navigationController)
        // Viewの移動する.
        self.navigationController?.pushViewController(mySecondViewController, animated: true)
    }
    
    /*
     Peripheralに接続失敗した際
     */
    func centralManager(central: CBCentralManager, didFailToConnectPeripheral peripheral: CBPeripheral, error: NSError?) {
        if let e = error {
            print("Error: \(e.localizedDescription)")
            return
        }
        print("not connnect")
    }    
    
[/code]

}


CC BY-SA 3.0
2016-12-06T08:40:34.570
30952
2017-10-13T01:16:12.013
2016-12-06T22:22:16.153
3605
19832
question
swift3
coreBluetooth BLEの検出


かなり多数のdelegateメソッドのシグニチャーがSwift2用のままで、Swift3用に変換されていません。(Xcode8.1の標準テンプレートからプロジェクトを作れば警告が表示されていたはずですが。)

* * *
[code]

    /*
     BLEデバイスが検出された際に呼び出される.
     */
    func centralManager(central: CBCentralManager,
                        didDiscoverPeripheral peripheral: CBPeripheral,
                        advertisementData: [String : AnyObject],
                        RSSI: NSNumber!)
    
[/code]

↓

[code]

    func centralManager(_ central: CBCentralManager,
                        didDiscover peripheral: CBPeripheral,
                        advertisementData: [String : Any],
                        rssi RSSI: NSNumber)
    
[/code]

* * *
[code]

    /*
     Cellが選択された際に呼び出される.
     */
    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath)
    
[/code]

↓

[code]

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
    
[/code]

* * *
[code]

    /*
     Peripheralに接続
     */
    func centralManager(central: CBCentralManager, didConnectPeripheral peripheral: CBPeripheral)
    
[/code]

↓

[code]

    func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral)
    
[/code]

* * *
[code]

    /*
     Peripheralに接続失敗した際
     */
    func centralManager(central: CBCentralManager, didFailToConnectPeripheral peripheral: CBPeripheral, error: NSError?)
    
[/code]

↓

[code]

    func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?)
    
[/code]

* * *

Swift3では先頭パラメータもデフォルトでは外部名(パラメータラベル)を持つので、オーバライド対象のメソッドやdelegateのメソッドを実装する場合、先頭のパラメータの前には`_`(パラメータラベルが要らないことを示す)が入るのが普通です。

その他にもSwift2では`AnyObject`だったところが`Any`になったり`NSError`が`Error`になったりNullability(データ型の`!`と`?`)が変更されていたり、パラメータラベルの一部が削られたり(主にデータ型名がラベルに含まれる場合)...

もう枚挙に暇が無いくらい多数の変更が加えられました。リンク先のコードはSwift3用に書き換わっていましたから、少し以前(Swift2用のコードが掲載されていた時代)にコードだけ入手して、それを手作業で(Xcodeが適切なサジェスチョンを与えてくれるところだけ?)Swift3に書き換えたというところでしょうか。(それとも間違えてSwift2.3と書かれた部分のコードを参照した?)

Swift言語は上に書いたようにバージョン間でのソースコード非互換の変更が多数発生しており、古いサイトや書籍で勉強すると、Swift言語の勉強をしているのか、Swift2からSwift3への変換方法を勉強しているのかわからない状態になってしまいます。リンク先のサイトがSwift3に対応されたのがいつ頃なのかはわかりませんが、同様に日本語でSwift3の情報を載せているサイトも増えてきました。Xcode8.1/Swift
3.0.1で学習されるのであれば、少し時間をかけてでもSwift3用の情報であることをきちんと確かめてからかかった方が、本筋以外のことに悩まされなくて済む分学習の効率もあがりますよ。

なお、上に示した修正は全てXcodeのコード補完(`centralManage`あたりまで入力すると(indexingが無事に終わっていれば)いくつか候補を表示してくれます)から拾い上げたものです。先ほど書いたようにリンク先のサイトは既にSwift3用のコードを掲載しているようですので、そちらも合わせて参考にして修正していかれれば良いのではないかと思います。


CC BY-SA 3.0
2016-12-06T09:58:35.027
30956
2016-12-06T09:58:35.027
13972
30952
answer