2

According to the Swift 2.0 documentation for CLBeaconRegion, it should still be possible to pass the output of the peripheralDataWithMeasuredPower: method to the startAdvertising: method of CLPeripheralManager.

Getting Beacon Advertisement Data

- peripheralDataWithMeasuredPower:

Retrieves data that can be used to advertise the current device as a beacon.

Declaration

SWIFT

func peripheralDataWithMeasuredPower(_measuredPower: NSNumber?) -> NSMutableDictionary

OBJECTIVE-C

- (NSMutableDictionary<NSString *,id> * _Nonnull)peripheralDataWithMeasuredPower:(NSNumber * _Nullable)measuredPower

Parameters

measuredPower The received signal strength indicator (RSSI) value (measured in decibels) for the device. This value represents the measured strength of the beacon from one meter away and is used during ranging. Specify nil to use the default value for the device.

Return Value

A dictionary of data that you can use in conjunction with a CBPeripheralManager to advertise the current device as a beacon.

Discussion

The returned dictionary encodes the beacon’s identifying information along with other information needed to advertise the beacon. You should not need to access the dictionary contents directly. Pass the dictionary to the startAdvertising: method of a CBPeripheralManager to begin advertising the beacon.

Availability

Available in iOS 7.0 and later.

However, peripheralDataWithMeasuredPower: returns an NSMutableDictionary whereas the startAdvertising: method of CLPeripheralManager accepts a Swift Dictionary of [String : AnyObject]?, although the documentation contends that it accepts an NSDictionary. The following code that worked in Swift 1.0:

// Set up a beacon region with the UUID, Major and Minor values
let region = CLBeaconRegion(proximityUUID:beaconUUID!, major:withMajor.unsignedShortValue, minor:withMinor.unsignedShortValue, identifier:"com.example.beacon")

// Attempt to set up a peripheral with the measured power
let peripheralData = region.peripheralDataWithMeasuredPower(withPower) 
_peripheralManager!.startAdvertising(peripheralData)

In Swift 2.0 the same code fails to compile with a warning: fails to compile, with a warning:

NSDictionary is not convertible to [String : AnyObject]; did you mean to use as! to force downcast?

However, forcing a downcast always fails.

Is this a documentation bug, a bug in Swift 2.0, or am I missing something?

PassKit
  • 12,231
  • 5
  • 57
  • 75
  • Hopefully, somebody better at Swift than me will have an answer. I am seeing the same thing as you! – davidgyoung Sep 29 '15 at 02:49
  • My solution is to cast to a dictionary then an optional cast in the function call. `let peripheralData = region.peripheralDataWithMeasuredPower(withPower) as Dictionary; _peripheralManager!.startAdvertising(peripheralData as? [String : AnyObject])`. – PassKit Sep 29 '15 at 03:16
  • Yes, that works for me, too. The key is adding the `as Dictionary` to the `peripheralData` assignment. Without it you cannot do the downcast. I'd love to see somebody offer a more elegant answer, but I have none. – davidgyoung Sep 29 '15 at 03:38

1 Answers1

3

The problem seems to be that NSMutableDictionary is not easily convertible to Swift's Dictionary, but NSDictinoary is. So I ended up converting the NSMutableDictionary to a NSDictinoary first:

let pd = NSDictionary(dictionary: region.peripheralDataWithMeasuredPower(nil))
         as! [String: AnyObject]
peripheralManager.startAdvertising(pd)

And it works!

fabian789
  • 8,348
  • 4
  • 45
  • 91