Reputation: 1799
I am getting error when I navigate to other screen (onBackButton) after adding my iBeacon code to find distance between two devices.
Here is my sample code:
import Foundation
import UIKit
import SlideMenuControllerSwift
import CoreLocation
import QuartzCore
import CoreLocation
import CoreBluetooth
class PokemonViewController: UIViewController , CLLocationManagerDelegate, CBPeripheralManagerDelegate{
var beaconRegion: CLBeaconRegion!
var bluetoothPeripheralManager: CBPeripheralManager!
var isBroadcasting = false
var dataDictionary = NSDictionary()
var isSearchingForBeacons = false
var lastFoundBeacon: CLBeacon! = CLBeacon()
var lastProximity: CLProximity! = CLProximity.unknown
var locationManager: CLLocationManager!
var my_uuid : String = ""
var other_uuid : String = ""
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Find Me"
var image = UIImage(named: "arrow")
image = image?.withRenderingMode(UIImageRenderingMode.alwaysOriginal)
self.navigationItem.leftBarButtonItem = UIBarButtonItem(image: Shared().imageRotatedByDegrees(oldImage: image!, deg: 180), style: UIBarButtonItemStyle.plain, target: self, action: #selector(onBackButton))
navigationController?.navigationBar.barTintColor = UIStyle().hexStringToUIColor("#e2041a")
}
override func viewDidAppear(_ animated: Bool) {
self.navigationController?.navigationBar.titleTextAttributes = [ NSFontAttributeName: UIFont(name: "Avenir Next", size: 20)!]
Pokemon.isPokemon = true
self.bluetoothPeripheralManager = CBPeripheralManager(delegate: self, queue: nil, options: nil)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.slideMenuController()?.removeLeftGestures()
self.slideMenuController()?.removeRightGestures()
//self.setNavigationBarItem()
let nav = self.navigationController?.navigationBar
nav?.barStyle = UIBarStyle.black
nav?.tintColor = UIColor.white
nav?.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.white]
let url = "\(Webcall().url)getuserdetails?user_id=\(userIdInvite)&token=\(UserDefaults.standard.object(forKey: "user_token") as! String)"
getUserDataRequest(url)
}
override func viewDidDisappear(_ animated: Bool) {
}
override func viewWillDisappear(_ animated: Bool) {
locationManager.stopMonitoring(for: beaconRegion)
locationManager.stopRangingBeacons(in: beaconRegion)
locationManager.stopUpdatingLocation()
isSearchingForBeacons = !isSearchingForBeacons
bluetoothPeripheralManager.stopAdvertising()
isBroadcasting = false
}
func onBackButton() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let resultViewController = storyboard.instantiateViewController(withIdentifier: "RadarViewController") as! RadarViewController
_ = navigationController?.popViewController(animated: true)
}
}
extension PokemonViewController {
func getUserDataRequest(_ url: String) {
var url = url
print(url)
url = url.replacingOccurrences(of: "+", with: "%2B", options: .literal, range: nil)
//present(Validation().waitAlert(), animated: true, completion: nil)
Shared().showLoaderGif(view: self.view)
_ = URLSession.shared
let urlPath = URL(string: url)
let request = NSMutableURLRequest(url: urlPath!)
request.timeoutInterval = 60
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringLocalCacheData
request.addValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
let dataTask = URLSession.shared.dataTask(with: request as URLRequest,completionHandler: {(data, response, error) -> Void in
if((error) != nil) {
}else {
let statusCode = (response as! HTTPURLResponse).allHeaderFields
_ = statusCode["Connection"]!
_ = NSString(data: data!, encoding:String.Encoding.utf8.rawValue)
let _: NSError?
let jsonResult: AnyObject = try! JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
print(jsonResult)
let flag = jsonResult["flag"] as! String
let message = jsonResult["message"] as! String
DispatchQueue.main.async {
Shared().hideLoaderGif(view: self.view)
if flag == "1" {
let data = jsonResult["data"] as? [String: AnyObject]
self.my_uuid = data?["my_udid"]! as! String
self.other_uuid = data?["usr_udid"]! as! String
self.switchBroadcastingState()
}else {
let uiAlert = UIAlertController(title: "Hello \(UserDefaults.standard.object(forKey: "user_name") as! String)", message: message , preferredStyle:.alert)
self.present(uiAlert, animated: true, completion: nil)
uiAlert.addAction(UIAlertAction(title: "Ok", style: .default, handler: { action in}))
}
}
}
})
dataTask.resume()
}
}
//iBeacon
extension PokemonViewController {
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
print("State -> ->", peripheral.state)
switch peripheral.state {
case .poweredOff:
if isBroadcasting {
switchBroadcastingState()
print("Power Off ->->")
}
case .poweredOn:
print("Power On ->->")
case .resetting:
print("resetting ->->")
case .unauthorized:
print("unauthorized ->->")
case .unsupported:
print("unsupported ->->")
default:
print("default ->->")
}
}
func switchBroadcastingState() {
if !isBroadcasting {
if bluetoothPeripheralManager.state == .poweredOn {
print("My UUID: \(self.my_uuid)")
print("Other UUID: \(self.other_uuid)")
/* It prints
My UUID: 1D2E9DF1-7A0E-4299-A755-AE11EBBC2C72
Other UUID: 58B2E595-F4CC-4BAD-8817-F09CD15DB94C*/
let myUuid = UUID(uuidString: "\(self.my_uuid)")
let major: CLBeaconMajorValue = UInt16(Int(1))
let minor: CLBeaconMinorValue = UInt16(Int(1))
beaconRegion = CLBeaconRegion(proximityUUID: myUuid!, major: major, minor: minor, identifier: "com.iMeetUp")
dataDictionary = beaconRegion.peripheralData(withMeasuredPower: nil)
bluetoothPeripheralManager.startAdvertising((dataDictionary as! [String : Any]))
isBroadcasting = true
}
} else {
bluetoothPeripheralManager.stopAdvertising()
isBroadcasting = false
}
self.locationManager = CLLocationManager()
self.locationManager.delegate = self
let otherUuid = UUID(uuidString: "\(self.other_uuid)")
beaconRegion = CLBeaconRegion(proximityUUID: otherUuid!, identifier: "com.iMeetUp")
beaconRegion.notifyOnEntry = true
beaconRegion.notifyOnExit = true
beaconRegion.notifyEntryStateOnDisplay = true
if !isSearchingForBeacons {
locationManager.requestAlwaysAuthorization()
locationManager.startMonitoring(for: beaconRegion)
locationManager.startUpdatingLocation()
} else {
locationManager.stopMonitoring(for: beaconRegion)
locationManager.stopRangingBeacons(in: beaconRegion)
locationManager.stopUpdatingLocation()
}
isSearchingForBeacons = !isSearchingForBeacons
}
func locationManager(_ manager: CLLocationManager!, didStartMonitoringFor region: CLRegion) {
print("Called Called Called 1 -> -> ->")
locationManager.requestState(for: region)
}
func locationManager(_ manager: CLLocationManager!, didDetermineState state: CLRegionState, for region: CLRegion) {
if state == CLRegionState.inside {
print("Called Called Called 2 -> -> ->")
locationManager.startRangingBeacons(in: beaconRegion)
}
else {
print("Called Called Called 3 -> -> ->")
locationManager.stopRangingBeacons(in: beaconRegion)
}
}
func locationManager(_ manager: CLLocationManager!, didEnterRegion region: CLRegion) {
}
func locationManager(_ manager: CLLocationManager!, didExitRegion region: CLRegion) {
}
func locationManager(_ manager: CLLocationManager!, didFailWithError error: Error) {
print("Error -> -> didFailWithError : ", error)
}
func locationManager(_ manager: CLLocationManager!, monitoringDidFailFor region: CLRegion?, withError error: Error) {
print("Error -> -> monitoringDidFailFor : ", error)
}
func locationManager(_ manager: CLLocationManager!, rangingBeaconsDidFailFor region: CLBeaconRegion, withError error: Error) {
print("Error -> -> rangingBeaconsDidFailFor : ", error)
}
func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon]!, in region: CLBeaconRegion) {
print("founddddddd")
var shouldHideBeaconDetails = true
if let foundBeacons = beacons {
if foundBeacons.count > 0 {
if let closestBeacon = foundBeacons[0] as? CLBeacon {
print("Found Device: ", foundBeacons)
if closestBeacon != lastFoundBeacon || lastProximity != closestBeacon.proximity {
//lastFoundBeacon = closestBeacon as CLBeacon
//lastProximity = closestBeacon.proximity
var proximityMessage: String!
print("Distance M: ", closestBeacon.accuracy)
switch closestBeacon.proximity {
case CLProximity.immediate:
proximityMessage = "Distance: \(String(format: "%.2f", closestBeacon.accuracy))m"
case CLProximity.near:
proximityMessage = "Distance: \(String(format: "%.2f", closestBeacon.accuracy))m"
case CLProximity.far:
proximityMessage = "Distance: \(String(format: "%.2f", closestBeacon.accuracy))m"
default:
proximityMessage = "Not Found!"
}
shouldHideBeaconDetails = false
//lblBeaconDetails.text = "Beacon Details:\nMajor = " + String(closestBeacon.major.int32Value) + "\nMinor = " + String(closestBeacon.minor.int32Value) + "\nDistance: " + proximityMessage + "\nDistance (m): \(String(format: "%.2f", closestBeacon.accuracy))"
}
}
}
}
}
}
Here is the screen-shot of the error which I got in Xcode:
Any help will be highly appreciated.
Upvotes: 0
Views: 195
Reputation: 8563
CLLocationManager
delegate is assign (unowned(unsafe)) not weak. You must set the delegate to nil in your deinit.
Upvotes: 0
Reputation: 1421
This is clearly showing that even if you are stopAdvertising BLE
, it is not stoping to advertise data and hence when next advertisement broadcast, it is crashed because it could not find its delegate
.
So my suggestion is to stop everything in deinit
method. Because when we are going back to previous screen, we should deinit
all assign objects, so that app is not crashed.
Make sure it called deinit
function in that class.
Upvotes: 0