How to play a video after iBeacon detection?

2019-07-30 15:30发布

问题:

I am new in the iBeacon and Swift development and I have some problems with my application. In the following code bellow, I am trying to detect iBeacon and when I detect the minor value of the beacon I attach it to the link I want to play. The problem occurs when I start the program. The video starts playing for a second and then the whole application stops with the following error:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Application tried to present modally an active controller .libc++abi.dylib: terminating with uncaught exception of type NSException.

var captureSession: AVCaptureSession?
var videoPreviewLayer: AVCaptureVideoPreviewLayer?

var avPlayerViewController = AVPlayerViewController()
var avPlayer:AVPlayer?

let locationManager = CLLocationManager()
let region = CLBeaconRegion(proximityUUID: UUID(uuidString: "8492E75F-4FD6-469D-B132-043FE94921D8")!, identifier: "Estimotes")


   let videos = [


    19987: NSURL ( string: "http://techslides.com/demos/sample-videos/small.mp4"),


                ]



   func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) {

    let knownBeacons = beacons.filter{ $0.proximity != CLProximity.unknown }
    if (knownBeacons.count > 0) {
        let closestBeacon = knownBeacons[0] as CLBeacon

        if let url = self.videos[closestBeacon.minor.intValue] {


            self.avPlayer = AVPlayer(url: url as! URL)
            self.avPlayerViewController.player = self.avPlayer

        }
        self.present(self.avPlayerViewController,animated: true) { () -> Void in
            self.avPlayerViewController.player?.play()
        }
    }
}

Would you please advice me how to fix that error?

回答1:

The problem is that the func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) ranging callback gets called every second. So your code to present the video player will execute every second. This might work the first time, but the second time, you'll get an error because the call to self.present(...) is trying to present the same view controller that you already presented. You can't present the same view controller over and over again.

The solution depends on how you want this to work. Do you just want this presentation to happen once? If so, you could do:

if (knownBeacons.count > 0) {
    let closestBeacon = knownBeacons[0] as CLBeacon

    if let url = self.videos[closestBeacon.minor.intValue] {

        // only execute this code once, if avPlayer not created yet
        if self.avPlayer == nil { 
            self.avPlayer = AVPlayer(url: url as! URL)
            self.avPlayerViewController.player = self.avPlayer
            self.present(self.avPlayerViewController,animated: true) { () -> Void in
                self.avPlayerViewController.player?.play()
            }
        }
    }
}