LoginSignup
7
7

More than 5 years have passed since last update.

【Domain=kCLErrorDomain Code=5】3つ目の原因

Last updated at Posted at 2015-06-26

iBeaconのビーコン領域監視アプリを作成していると、時折下記のエラーに出くわすことがあるかと思います。

Domain=kCLErrorDomain Code=5

これについてネットで調べると、2つ、原因が見つかります。

  • regionがnil
  • 監視しているregionが20個超

また、原因が何とは特定していなくても、iOSデバイスを再起動すれば解消される、と説明しているweb記事もあります。

上記2件の原因のいずれにも当てはまらず、iOSデバイスの再起動でもDomain=kCLErrorDomain Code=5が解消されなかったので、その解決方法を記そうと思います。

現象

  • ビーコンを検知しない
  • func locationManager(_: monitoringDidFailForRegion)Domain=kCLErrorDomain Code=5

原因

  • BluetoothがOFF

領域監視開始(CLLocationManagerインスタンス生成?)時に出るダイアログで位置情報サービスはONにしてあったし、アプリの位置情報の許諾も出していたんです。
が、BTのダイアログでOKを選んでしまったため(設定OKの二択)、BTがOFFのまま……。
それに気付かず延々1時間、ネット徘徊とログ取りを繰り返してしまいました。
偶然でも原因に気が付けて良かったです。

上の話は仕事中にあった出来事です。
下記コードは家に帰ってから記憶を頼りに適当に打ったものですので、動作確認等はしていません。
コンパイルエラーは出ていませんが(Xcode6.3)。
ターゲットはiOS7.1を想定しているのでAuthorizationの処理が甘いです。
あ、UUIDだけは変えました。

import UIKit
import CoreLocation

class ViewController: UIViewController, CLLocationManagerDelegate {

    var myLocation: CLLocationManager!
    var myRegion: CLBeaconRegion!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        myLocation = CLLocationManager()
        myLocation.delegate = self
        myRegion = CLBeaconRegion(proximityUUID: NSUUID(UUIDString: "uuidgenで求めてください"), identifier: "hoge")
    }

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

// MARK:CLLocationManagerDelegate
extension ViewController {
    // CLLocationManagerインスタンスを生成すると呼ばれる
    func locationManager(manager: CLLocationManager!, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
        // 領域監視開始
        manager.startMonitoringForRegion(myRegion)

        // デバッグ用
        for region in manager.monitoredRegions {
            println("monitoring region count \(manager.monitoredRegions.count)")
            println(region)
        }
    }

    // startMonitoringForRegionに対するデリゲート
    func locationManager(manager: CLLocationManager!, didStartMonitoringForRegion region: CLRegion!) {
        // 監視状況のチェック
        // エラー発生時、monitoringDidFailForRegionに拾わせるため
        manager.requestStateForRegion(myRegion)
    }

    // requestStateForRegionに対するデリゲート
    // requestStateForRegionを呼んでなくても領域を検知した場合は呼ばれる
    func locationManager(manager: CLLocationManager!, didDetermineState state: CLRegionState, forRegion region: CLRegion!) {
        println("didDetermineState: \(state.name)")
    }

    // startMonitoringForRegion後のエラーを拾う
    func locationManager(manager: CLLocationManager!, monitoringDidFailForRegion region: CLRegion!, withError error: NSError!) {
        println("monitoringDidFailForRegion")
        // withError: Error Domain=kCLErrorDomain Code=5
        // 1. region が nil
        // 2. 監視している region が 20 個を超えた
        // 3. Bluetooth を ON にしてない
    }
}

extension CLRegionState {
    var name : NSString {
        get{
            var enumName = "CLRegionState"
            var valueName = ""

            switch self {
            case .Unknown:
                valueName = enumName + "Unknown"
            case .Inside:
                valueName = enumName + "Inside"
            case .Outside:
                valueName = enumName + "Outside"
            }
            return valueName
        }
    }
}

参考

BLEのペリフェラルを今更実装してみた(iOS編)

「CoreBluetoothのEnum値」
ログ出し用のnameプロパティ、重宝させて頂いております。

[Swift]switch文のcaseやdefault節で何も処理しない場合はbreakが必要

自分もそう思っていました。
でも上記のname拡張で、変だなって。
なるほど、switchは取り得る値全てをカバーしていればdefaultは必要ないんですね。

以上です。

7
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7