iosswiftsubclassingclbeacon

CLBeacon subclass error


i want to pass some extra information through CLBeacon so i create a subclass of it called CLBeaconExtender. the problem is while executing the code, it give me this error

NSArray element failed to match the Swift Array Element type

this is the code:


Subclass of CLBeacon

class CLBeaconExtender: CLBeacon{
    var id: String!
}

MainClass

class beaconController_1: UIViewController, CLLocationManagerDelegate {

    var beacon_collection: UICollectionView!
    var location_manager = CLLocationManager()
    var beacon_manager = [CLBeaconExtender]()
    var beacon_region = [CLBeaconRegion]()

  // Other code that i don't paste

  func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) {
        if !beacons.isEmpty {
            beacon_manager = beacons as! [CLBeaconExtender]
            beacon_manager[0].id = "hello world"  // here appear the error
            beacon_collection.reloadData()
        }
        else{
            if beacon_manager.count != 0 {
                beacon_manager = beacons as! [CLBeaconExtender]
                beacon_collection.reloadData()
            }
        }
    }

can anyone solve me this problem or show me an example?

Edit

i think the error is caused by this line:

beacon_manager = beacons as! [CLBeaconExtender]

Edit 2

Sorry for my english, my goal is to create a collectionview that display all the beacons around me, and update the list every time that didRangBeacons is called, in addition every collectionviewcell should contain a specific file audio referring to the respective beacon. So when i tap a specific cell of a specific beacon it start to play a specific sound. My problem is handle the beacon_manager array. In the first cycle of didRangeBeacons everything goes fine because !beacon_manager.indices.contains(i) return !false so it will execute the if condition, and it will populate all the beacon_manager. than in the second cycle of didRangeBeacons the if condition will return !true so the code executed will be the else condition. here the system will crash executing beacon_manager.remove(at: i) where i is 0 and beacon_manager[0] exist.

the crash show me the AppDelegate class with the error:

EXEC_BAD_ACCESS code=1 address= 0x8

Hope you'll understand it now.

   func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) {
    if !beacons.isEmpty {
        var i = 0
        for beacon in beacons {
            let bx = CLBeaconExtender(b: beacon, sID: "hello world")
            if(!beacon_manager.indices.contains(i)){  //check if beacon_manager array exist at i if no create it, if yes update it
                beacon_manager.insert(bx, at: i)
            }
            else{
                beacon_manager.remove(at: i)
                beacon_manager.insert(bx, at: i)

            }
            print(beacon_manager[i].id)
            i+=1
        }

        print(beacon_manager.count,beacons.count)
        beacon_collection.reloadData()
    }
    else{
        if beacon_manager.count != 0 {
            //do other things
        }
    }
}

Solution

  • You cannot simply say "this object is now another type" and magically change the object. For example:

        let x = UIView()
        let y = x as! UIImageView
    

    If you tried to run those two lines, you'd get an error like:

    Could not cast value of type 'UIView' (0x107fa44c0) to 'UIImageView' (0x107fa5c08).

    So, that's what you are trying to do here:

    beacon_manager = beacons as! [CLBeaconExtender]
    

    You are saying "I declare this NSArray of CLBeacon objects is now an Array of CLBeaconExtender objects!" and things just don't work like that.

    One approach to what you're trying to do would be to define your CLBeaconExtender class as:

    class CLBeaconExtender: CLBeacon {
        var id: String!
        var bcn: CLBeacon!
    
        convenience init(b: CLBeacon, sID: String) {
            self.init()
            bcn = b
            id = sID
        }
    }
    

    Then, in your didRangeBeacons function:

    func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) {
    
        for beacon in beacons {
            let bx = CLBeaconExtender(b: beacon, sID: "hello world")
            beacon_manager.append(bx)
        }
    
        // other code...
    }
    

    Of course, you won't want to do that, as you'd end up appending lots of the same beacon object, all with the id of "hello world". But, hopefully that helps you understand the error you were getting, and gets you on your way to fixing it.