From 1ed9721b842f0089a8df9534da12ea0c42d49cb7 Mon Sep 17 00:00:00 2001 From: Mikhail Zinov Date: Mon, 8 Jan 2018 14:26:36 +1000 Subject: [PATCH] Update swift scanner sample to Swift v4.0 --- .../project.pbxproj | 2 + .../BeaconScanner.swift | 69 +++++++++---------- .../DispatchTimer.swift | 42 +++++------ .../Eddystone.swift | 32 ++++----- 4 files changed, 67 insertions(+), 78 deletions(-) diff --git a/tools/ios-eddystone-scanner-sample/EddystoneScannerSample.xcodeproj/project.pbxproj b/tools/ios-eddystone-scanner-sample/EddystoneScannerSample.xcodeproj/project.pbxproj index a048ac2..eb1a840 100644 --- a/tools/ios-eddystone-scanner-sample/EddystoneScannerSample.xcodeproj/project.pbxproj +++ b/tools/ios-eddystone-scanner-sample/EddystoneScannerSample.xcodeproj/project.pbxproj @@ -441,6 +441,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.google.sample.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.0; }; name = Debug; }; @@ -453,6 +454,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.google.sample.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.0; }; name = Release; }; diff --git a/tools/ios-eddystone-scanner-sample/EddystoneScannerSampleSwift/BeaconScanner.swift b/tools/ios-eddystone-scanner-sample/EddystoneScannerSampleSwift/BeaconScanner.swift index 3a6f802..a7b2f77 100644 --- a/tools/ios-eddystone-scanner-sample/EddystoneScannerSampleSwift/BeaconScanner.swift +++ b/tools/ios-eddystone-scanner-sample/EddystoneScannerSampleSwift/BeaconScanner.swift @@ -42,17 +42,16 @@ class BeaconScanner: NSObject, CBCentralManagerDelegate { var onLostTimeout: Double = 15.0 private var centralManager: CBCentralManager! - private let beaconOperationsQueue: dispatch_queue_t = - dispatch_queue_create("beacon_operations_queue", nil) - private var shouldBeScanning: Bool = false + private let beaconOperationsQueue = DispatchQueue(label: "beacon_operations_queue") + private var shouldBeScanning = false private var seenEddystoneCache = [String : [String : AnyObject]]() - private var deviceIDCache = [NSUUID : NSData]() + private var deviceIDCache = [UUID : NSData]() override init() { super.init() - self.centralManager = CBCentralManager(delegate: self, queue: self.beaconOperationsQueue) + self.centralManager = CBCentralManager(delegate: self, queue: beaconOperationsQueue) self.centralManager.delegate = self } @@ -61,7 +60,7 @@ class BeaconScanner: NSObject, CBCentralManagerDelegate { /// scanning. /// func startScanning() { - dispatch_async(self.beaconOperationsQueue) { + beaconOperationsQueue.async { self.startScanningSynchronized() } } @@ -76,8 +75,8 @@ class BeaconScanner: NSObject, CBCentralManagerDelegate { /// /// MARK - private methods and delegate callbacks /// - func centralManagerDidUpdateState(central: CBCentralManager) { - if central.state == CBCentralManagerState.PoweredOn && self.shouldBeScanning { + func centralManagerDidUpdateState(_ central: CBCentralManager) { + if central.state == .poweredOn && self.shouldBeScanning { self.startScanningSynchronized(); } } @@ -86,32 +85,31 @@ class BeaconScanner: NSObject, CBCentralManagerDelegate { /// Core Bluetooth CBCentralManager callback when we discover a beacon. We're not super /// interested in any error situations at this point in time. /// - func centralManager(central: CBCentralManager, - didDiscoverPeripheral peripheral: CBPeripheral, - advertisementData: [String : AnyObject], - RSSI: NSNumber) { + func centralManager(_ central: CBCentralManager, + didDiscover peripheral: CBPeripheral, + advertisementData: [String : Any], + rssi RSSI: NSNumber) { if let serviceData = advertisementData[CBAdvertisementDataServiceDataKey] as? [NSObject : AnyObject] { var eft: BeaconInfo.EddystoneFrameType - eft = BeaconInfo.frameTypeForFrame(serviceData) + eft = BeaconInfo.frameTypeForFrame(advertisementFrameList: serviceData) // If it's a telemetry frame, stash it away and we'll send it along with the next regular // frame we see. Otherwise, process the UID frame. if eft == BeaconInfo.EddystoneFrameType.TelemetryFrameType { - deviceIDCache[peripheral.identifier] = BeaconInfo.telemetryDataForFrame(serviceData) + deviceIDCache[peripheral.identifier] = BeaconInfo.telemetryDataForFrame(advertisementFrameList: serviceData) } else if eft == BeaconInfo.EddystoneFrameType.UIDFrameType || eft == BeaconInfo.EddystoneFrameType.EIDFrameType { let telemetry = self.deviceIDCache[peripheral.identifier] let serviceUUID = CBUUID(string: "FEAA") - let _RSSI: Int = RSSI.integerValue + let _RSSI: Int = RSSI.intValue - if let - beaconServiceData = serviceData[serviceUUID] as? NSData, - beaconInfo = + if let beaconServiceData = serviceData[serviceUUID] as? NSData, + let beaconInfo = (eft == BeaconInfo.EddystoneFrameType.UIDFrameType - ? BeaconInfo.beaconInfoForUIDFrameData(beaconServiceData, telemetry: telemetry, + ? BeaconInfo.beaconInfoForUIDFrameData(frameData: beaconServiceData, telemetry: telemetry, RSSI: _RSSI) - : BeaconInfo.beaconInfoForEIDFrameData(beaconServiceData, telemetry: telemetry, + : BeaconInfo.beaconInfoForEIDFrameData(frameData: beaconServiceData, telemetry: telemetry, RSSI: _RSSI)) { // NOTE: At this point you can choose whether to keep or get rid of the telemetry @@ -119,7 +117,7 @@ class BeaconScanner: NSObject, CBCentralManagerDelegate { // for this beacon, or delete it until we get a new / "fresh" TLM frame. // We'll treat it as "report it only when you see it", so we'll delete it // each time. - self.deviceIDCache.removeValueForKey(peripheral.identifier) + self.deviceIDCache.removeValue(forKey: peripheral.identifier) if (self.seenEddystoneCache[beaconInfo.beaconID.description] != nil) { // Reset the onLost timer and fire the didUpdate. @@ -129,22 +127,22 @@ class BeaconScanner: NSObject, CBCentralManagerDelegate { timer.reschedule() } - self.delegate?.didUpdateBeacon(self, beaconInfo: beaconInfo) + self.delegate?.didUpdateBeacon(beaconScanner: self, beaconInfo: beaconInfo) } else { // We've never seen this beacon before - self.delegate?.didFindBeacon(self, beaconInfo: beaconInfo) + self.delegate?.didFindBeacon(beaconScanner: self, beaconInfo: beaconInfo) let onLostTimer = DispatchTimer.scheduledDispatchTimer( - self.onLostTimeout, - queue: dispatch_get_main_queue()) { + delay: self.onLostTimeout, + queue: DispatchQueue.main) { (timer: DispatchTimer) -> () in let cacheKey = beaconInfo.beaconID.description if let beaconCache = self.seenEddystoneCache[cacheKey], - lostBeaconInfo = beaconCache["beaconInfo"] as? BeaconInfo { - self.delegate?.didLoseBeacon(self, beaconInfo: lostBeaconInfo) - self.seenEddystoneCache.removeValueForKey( - beaconInfo.beaconID.description) + let lostBeaconInfo = beaconCache["beaconInfo"] as? BeaconInfo { + self.delegate?.didLoseBeacon(beaconScanner: self, beaconInfo: lostBeaconInfo) + self.seenEddystoneCache.removeValue( + forKey: beaconInfo.beaconID.description) } } @@ -156,12 +154,11 @@ class BeaconScanner: NSObject, CBCentralManagerDelegate { } } else if eft == BeaconInfo.EddystoneFrameType.URLFrameType { let serviceUUID = CBUUID(string: "FEAA") - let _RSSI: Int = RSSI.integerValue + let _RSSI: Int = RSSI.intValue - if let - beaconServiceData = serviceData[serviceUUID] as? NSData, - URL = BeaconInfo.parseURLFromFrame(beaconServiceData) { - self.delegate?.didObserveURLBeacon(self, URL: URL, RSSI: _RSSI) + if let beaconServiceData = serviceData[serviceUUID] as? NSData, + let URL = BeaconInfo.parseURLFromFrame(frameData: beaconServiceData) { + self.delegate?.didObserveURLBeacon(beaconScanner: self, URL: URL, RSSI: _RSSI) } } } else { @@ -170,14 +167,14 @@ class BeaconScanner: NSObject, CBCentralManagerDelegate { } private func startScanningSynchronized() { - if self.centralManager.state != CBCentralManagerState.PoweredOn { + if self.centralManager.state != .poweredOn { NSLog("CentralManager state is %d, cannot start scan", self.centralManager.state.rawValue) self.shouldBeScanning = true } else { NSLog("Starting to scan for Eddystones") let services = [CBUUID(string: "FEAA")] let options = [CBCentralManagerScanOptionAllowDuplicatesKey : true] - self.centralManager.scanForPeripheralsWithServices(services, options: options) + self.centralManager.scanForPeripherals(withServices: services, options: options) } } } diff --git a/tools/ios-eddystone-scanner-sample/EddystoneScannerSampleSwift/DispatchTimer.swift b/tools/ios-eddystone-scanner-sample/EddystoneScannerSampleSwift/DispatchTimer.swift index 641aa52..cd79527 100644 --- a/tools/ios-eddystone-scanner-sample/EddystoneScannerSampleSwift/DispatchTimer.swift +++ b/tools/ios-eddystone-scanner-sample/EddystoneScannerSampleSwift/DispatchTimer.swift @@ -27,24 +27,23 @@ class DispatchTimer: NSObject { typealias TimerHandler = (DispatchTimer) -> Void private let timerBlock: TimerHandler - private let queue: dispatch_queue_t - private let delay: NSTimeInterval + private let queue: DispatchQueue + private let delay: TimeInterval private var wrappedBlock: (() -> Void)? - private let source: dispatch_source_t + private let source: DispatchSourceTimer - init(delay: NSTimeInterval, queue: dispatch_queue_t, block: TimerHandler) { + init(delay: TimeInterval, queue: DispatchQueue, block: @escaping TimerHandler) { timerBlock = block self.queue = queue self.delay = delay - - self.source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.queue) + self.source = DispatchSource.makeTimerSource(queue: queue) super.init() let wrapper = { () -> Void in - if dispatch_source_testcancel(self.source) == 0 { - dispatch_source_cancel(self.source) + if !self.source.isCancelled { + self.source.cancel() self.timerBlock(self) } } @@ -52,38 +51,33 @@ class DispatchTimer: NSObject { self.wrappedBlock = wrapper } - class func scheduledDispatchTimer(delay: NSTimeInterval, - queue: dispatch_queue_t, - block: TimerHandler) -> DispatchTimer { - let dt = DispatchTimer(delay: delay, queue: queue, block: block) - dt.schedule() - return dt + class func scheduledDispatchTimer(delay: TimeInterval, queue: DispatchQueue, block: @escaping TimerHandler) -> DispatchTimer { + let dt = DispatchTimer(delay: delay, queue: queue, block: block) + dt.schedule() + + return dt } func schedule() { self.reschedule() - dispatch_source_set_event_handler(self.source, self.wrappedBlock) - dispatch_resume(self.source) + self.source.setEventHandler(handler: self.wrappedBlock) + self.source.resume() } func reschedule() { - let start = dispatch_time(DISPATCH_TIME_NOW, Int64(self.delay * Double(NSEC_PER_SEC))) - - // Leeway is 10% of timer delay - dispatch_source_set_timer(self.source, start, DISPATCH_TIME_FOREVER, - UInt64((self.delay / 10.0) * Double(NSEC_PER_SEC))) + self.source.schedule(deadline: .now() + self.delay) } func suspend() { - dispatch_suspend(self.source) + self.source.suspend() } func resume() { - dispatch_resume(self.source) + self.source.resume() } func cancel() { - dispatch_source_cancel(self.source) + self.source.cancel() } } diff --git a/tools/ios-eddystone-scanner-sample/EddystoneScannerSampleSwift/Eddystone.swift b/tools/ios-eddystone-scanner-sample/EddystoneScannerSampleSwift/Eddystone.swift index adbdd33..2e9309e 100644 --- a/tools/ios-eddystone-scanner-sample/EddystoneScannerSampleSwift/Eddystone.swift +++ b/tools/ios-eddystone-scanner-sample/EddystoneScannerSampleSwift/Eddystone.swift @@ -34,14 +34,14 @@ class BeaconID : NSObject { /// let beaconID: [UInt8] - private init(beaconType: BeaconType!, beaconID: [UInt8]) { + fileprivate init(beaconType: BeaconType!, beaconID: [UInt8]) { self.beaconID = beaconID self.beaconType = beaconType } override var description: String { if self.beaconType == BeaconType.Eddystone || self.beaconType == BeaconType.EddystoneEID { - let hexid = hexBeaconID(self.beaconID) + let hexid = hexBeaconID(beaconID: self.beaconID) return "BeaconID beacon: \(hexid)" } else { return "BeaconID with invalid type (\(beaconType))" @@ -52,7 +52,7 @@ class BeaconID : NSObject { var retval = "" for byte in beaconID { var s = String(byte, radix:16, uppercase: false) - if s.characters.count == 1 { + if s.count == 1 { s = "0" + s } retval += s @@ -121,13 +121,12 @@ class BeaconInfo : NSObject { self.telemetry = telemetry } - class func frameTypeForFrame(advertisementFrameList: [NSObject : AnyObject]) - -> EddystoneFrameType { + class func frameTypeForFrame(advertisementFrameList: [NSObject : AnyObject]) -> EddystoneFrameType { let uuid = CBUUID(string: "FEAA") if let frameData = advertisementFrameList[uuid] as? NSData { if frameData.length > 1 { let count = frameData.length - var frameBytes = [UInt8](count: count, repeatedValue: 0) + var frameBytes = [UInt8](repeating: 0, count: count) frameData.getBytes(&frameBytes, length: count) if frameBytes[0] == EddystoneUIDFrameTypeID { @@ -154,11 +153,10 @@ class BeaconInfo : NSObject { /// in the Swift compiler — it can't tear-down partially initialised objects, so we'll have to /// wait until this gets fixed. For now, class method will do. /// - class func beaconInfoForUIDFrameData(frameData: NSData, telemetry: NSData?, RSSI: Int) - -> BeaconInfo? { + class func beaconInfoForUIDFrameData(frameData: NSData, telemetry: NSData?, RSSI: Int) -> BeaconInfo? { if frameData.length > 1 { let count = frameData.length - var frameBytes = [UInt8](count: count, repeatedValue: 0) + var frameBytes = [UInt8](repeating: 0, count: count) frameData.getBytes(&frameBytes, length: count) if frameBytes[0] != EddystoneUIDFrameTypeID { @@ -177,11 +175,10 @@ class BeaconInfo : NSObject { return nil } - class func beaconInfoForEIDFrameData(frameData: NSData, telemetry: NSData?, RSSI: Int) - -> BeaconInfo? { + class func beaconInfoForEIDFrameData(frameData: NSData, telemetry: NSData?, RSSI: Int) -> BeaconInfo? { if frameData.length > 1 { let count = frameData.length - var frameBytes = [UInt8](count: count, repeatedValue: 0) + var frameBytes = [UInt8](repeating: 0, count: count) frameData.getBytes(&frameBytes, length: count) if frameBytes[0] != EddystoneEIDFrameTypeID { @@ -203,14 +200,14 @@ class BeaconInfo : NSObject { class func parseURLFromFrame(frameData: NSData) -> NSURL? { if frameData.length > 0 { let count = frameData.length - var frameBytes = [UInt8](count: count, repeatedValue: 0) + var frameBytes = [UInt8](repeating: 0, count: count) frameData.getBytes(&frameBytes, length: count) - if let URLPrefix = URLPrefixFromByte(frameBytes[2]) { + if let URLPrefix = URLPrefixFromByte(schemeID: frameBytes[2]) { var output = URLPrefix for i in 3..