i have an App that does actions on didEnterRegion and didExitRegion of CLBeaconRegions. Those are both on my viewcontroller class. Now the user should be able to set the UUID by himself. Therefor I made a second view controller (setibeaconVC) to change the string of the UUID.
It does work however the regions increase overtime the user changes the UUID in the App. So the Actions are called first one time after changing the UUID once the actions are called two times and so on.
Is there any command to clear the cache of those regions before I change the UUID?
Here´s part of my code.
ViewController:
var ibeaconuuid:String! = "B9407F30-F5F8-466E-AFF9-25556B57FE6D"
let locationManager = CLLocationManager()
var beaconUUID:NSUUID!
var region:CLBeaconRegion!
override func viewDidLoad() {
super.viewDidLoad()
beaconUUID = NSUUID(UUIDString: ibeaconuuid)
region = CLBeaconRegion(proximityUUID: beaconUUID, identifier: "Beacon")
locationManager.delegate = self
locationManager.pausesLocationUpdatesAutomatically = false
region.notifyOnEntry = true
region.notifyOnExit = true
region.notifyEntryStateOnDisplay = false
if (CLLocationManager.authorizationStatus() != CLAuthorizationStatus.AuthorizedAlways) {
locationManager.requestAlwaysAuthorization()
}
if (CLLocationManager .isMonitoringAvailableForClass(CLBeaconRegion))
{
print("OK")
}
else {
print("Problem")
}
locationManager.startMonitoringForRegion(region)
locationManager.startRangingBeaconsInRegion(region)
locationManager.startUpdatingLocation()
}
And here the setiBeaconVC:
class setibeaconVC: UIViewController {
#IBOutlet weak var ibeaconuuidtext: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let DestViewController: ViewController = segue.destinationViewController as! ViewController
DestViewController.ibeaconuuid = ibeaconuuidtext.text!
}
}
Many Thanks
Stephan
Before re-creating the CLBeaconRegion in your view controller call locationManager.stopMonitoringForRegion(region).
You will need to check this contains a region before calling as on first run it won't. Easiest way to do this is to change region to an optional rather than forced unwrapped optional. Then check like this:
var region:CLBeaconRegion? // Update to this.
if let r = region {
locationManager.stopMonitoringForRegion(r)
}
Related
I am using MapKit on Xcode to create a "nearby" hospital/mental health center/call center location app. I want the user to be able to filter the map's results. For instance, if I am looking for hospitals, I only want to see hospital locations appear on the map. So far, to do this, I created a sliding hamburger menu with checkbox-like buttons to use as filters. So for example, you tap the hamburger menu button and you check the box with hospitals so that you only get hospital results on the map. However, I must have messed it up somehow because when I get to the MapViewController, only a black screen appears. Please advise how I can fix this or maybe use a different method entirely to achieve the same goal.
import UIKit
import MapKit
class MapViewController: NSObject, CLLocationManagerDelegate {
#IBOutlet weak var mapView: MKMapView!
#IBOutlet weak var trailingMap: NSLayoutConstraint!
#IBOutlet weak var leadingMap: NSLayoutConstraint!
func viewDidLoad() {
mapView.delegate = self as? MKMapViewDelegate
let locationManager = CLLocationManager()
let regionRadius:CLLocationDistance = 1000
locationManager.requestWhenInUseAuthorization()
mapView.showsUserLocation = true
locationManager.startUpdatingLocation()
}
var hamburgerMenuIsVisible = false
#IBAction func hamburgerMenu(_ sender: Any) {
if hamburgerMenuIsVisible {
leadingMap.constant = 150
trailingMap.constant = -150
hamburgerMenuIsVisible = true
} else {
leadingMap.constant = 0
trailingMap.constant = 0
hamburgerMenuIsVisible = false
}
}
var mapItems: [MKMapItem] = []
var place = MKLocalSearch.Request() //user's facility search options
var naturalLanguageQuery: String? {
place.naturalLanguageQuery = "hospital"
let place2 = MKLocalSearch.Request()
place2.naturalLanguageQuery = "Mental Health Facility"
let place3 = MKLocalSearch.Request()
place3.naturalLanguageQuery = "Women's Center"
let place4 = MKLocalSearch.Request()
place4.naturalLanguageQuery = "Call Center"
place.region = self.mapView.region
place2.region = self.mapView.region
place3.region = self.mapView.region
place4.region = self.mapView.region
return place.naturalLanguageQuery
}
#IBAction func hospitalButton(_ sender: Any) {
print(mapItems)
}
#IBAction func callCenterButton(_ sender: Any) {
print(mapItems)
}
}
Your ViewController is subclass of UIViewController, so you have to use inheritance from UIViewController instead of NSObject
So, replace this
class MapViewController: NSObject, CLLocationManagerDelegate {
with this
class MapViewController: UIViewController, CLLocationManagerDelegate {
also fix your viewDidLoad method by adding override keyword before func keyword of your viewDidLoad function. That's because you override function from UIViewController. You will have to call super.viewDidLoad() at the begining of this function. So viewDidLoad should look like this
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self as? MKMapViewDelegate
let locationManager = CLLocationManager()
let regionRadius:CLLocationDistance = 1000
locationManager.requestWhenInUseAuthorization()
mapView.showsUserLocation = true
locationManager.startUpdatingLocation()
}
Im using Xcode 8 and swift 3
I created a new project selecting new "Tabbed Application" when i created it. It provided two UIViewControllers embedded in one tab bar controller. I'm trying to pass two variables between the view controllers.
The problem is that the prepare for segue function is never called. I added a print statement in it that never prints. I added the prepare function in both view controllers and can tab back and forth with no prints.
Some code:
import UIKit
import MapKit
import CoreLocation
class FirstViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate{
#IBOutlet weak var mapView: MKMapView!
var locationManager:CLLocationManager?
var currentLocation:CLLocation?
var destPin: MapPin?
var isTracking: Bool? = false
override func viewDidLoad() {
super.viewDidLoad()
locationManager = CLLocationManager()
locationManager?.delegate = self
locationManager?.startUpdatingLocation()
locationManager?.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager?.requestAlwaysAuthorization()
updateTracking()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
self.currentLocation = locations[0]
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print(error)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func getMapView()-> MKMapView{
return mapView
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
if(self.isTracking!){
print("Istracking bool is true")
}
else{
print("Istracking bool is false")
}
updateTracking()
locationManager?.stopUpdatingLocation()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
print("Preparing")
let barViewControllers = segue.destination as! UITabBarController
let destinationViewController = barViewControllers.viewControllers![1] as! FirstViewController
destinationViewController.destPin = self.destPin
destinationViewController.isTracking = self.isTracking
}
}
The contents of the prepare function may very well be wrong as well but without the function even being called it hardly matters. The other view controller is also embedded in the tab bar controller and also has a prepare function that does not execute.
If you'd like, its in this github repo
It is easy to do:
The result:
For example, there are FirstViewController and SecondViewController embeded in tabViewController:
In your firstViewController.swift:
import UIKit
class FirstViewController: UIViewController {
var vc1_variable:String = "first vc's variable."
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
In your secondViewController.swift:
import UIKit
class SecondViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let first_vc:FirstViewController = self.tabBarController?.viewControllers![0] as! FirstViewController
print("\(first_vc.vc1_variable)")
}
}
I wanna get object of AppDelegate.
This program can build but it will stop running with lldb error.
Maybe the problem is the dirrerence of Swift2.0 and 3.0.
My textbook is for swift2.0 but I am using xcode8.0 and Swift3.0.
Error is here.
let ap = UIApplication.shared.delegate as! AppDelegate
I used this page for fixing.
How do I get a reference to the app delegate in Swift?
import UIKit
class FirstViewController: UIViewController {
#IBOutlet weak var dataTextField: UITextField!
let ap = UIApplication.shared.delegate as! AppDelegate
override func viewWillAppear(_ animated: Bool) {
dataTextField.text = String(ap.cmValue)
}
#IBAction func tapInpu() {
dataTextField.resignFirstResponder()
if let text = dataTextField.text{
if let cmValue = Double(text){
ap.cmValue = cmValue
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
If you remove ap initialization and ap.cmValue = cmValue, does it works ?
If it does work check your outlet referencing in your storyboard you may have old non existent references
I can add Annotation on MapView using "first" button, but I would like to add a new option which enables the removing of the annotation using the "second" button. I have no problem with adding annotation, but I cannot remove it from the map view. Can somebody help me in it?
Here is my code:
class ViewController: UIViewController {
#IBOutlet weak var mapViewOutlet: MKMapView!
var lm = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
self.lm.requestAlwaysAuthorization()
mapViewOutlet.showsUserLocation = true
mapViewOutlet.userTrackingMode = MKUserTrackingMode.Follow
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// HERE IS FUNCTION ADDANNOTATION
#IBAction func tagMyCar(sender: UIButton) {
let coordinate = lm.location?.coordinate
let CarCoordinates = CarAdnotaion(coordinate: coordinate!)
mapViewOutlet.addAnnotation(CarCoordinates)
let region = CLCircularRegion(center: coordinate!, radius: 5, identifier: "My Car")
region.notifyOnEntry = true
region.notifyOnExit = true
lm.startMonitoringForRegion(region)
}
// HERE IS FUNCTION REMOVEANNOTATION
#IBAction func removeAnnotationfromMap(sender: AnyObject) {
let region = CLCircularRegion(center: (lm.location?.coordinate)!, radius: 5, identifier: "Mój samochód")
self.mapViewOutlet.removeAnnotation(CarAdnotaion(coordinate: (lm.location?.coordinate)!))
lm.stopMonitoringForRegion(region)
}
}
I think the problem is here:
self.mapViewOutlet.removeAnnotation(CarAdnotaion(coordinate: (lm.location?.coordinate)!))
You are removing annotation that you just created in this very statemen. Instead, move let CarCoordinates up (and give it more sensible name and lowercase letter in the beginning). Then call removeAnnotation on that object.
I have a solution of my problem. It works!
import UIKit
import CoreLocation
import MapKit
class ViewController: UIViewController {
#IBOutlet weak var mapViewOutlet: MKMapView!
let lm = CLLocationManager()
var carAnnotation: CarAnnotationOnMap?
var region: CLCircularRegion?
override func viewDidLoad() {
super.viewDidLoad()
self.lm.requestAlwaysAuthorization()
mapViewOutlet.userTrackingMode = MKUserTrackingMode.Follow
mapViewOutlet.showsUserLocation = true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// ADD ANNOTATION ON MAP
#IBAction func tagMyCar(sender: UIButton) {
let coordinates = lm.location?.coordinate
carAnnotation = CarAnnotationOnMap(coordinates: coordinates!)
region = CLCircularRegion(center: coordinates!, radius: 5, identifier: "My Zone")
region!.notifyOnEntry = true
region!.notifyOnExit = true
self.lm.startMonitoringForRegion(region!)
mapViewOutlet.addAnnotation(carAnnotation!)
}
// REMOVE ANNOTATION FROM MAP
#IBAction func removePinFromMyCar(sender: AnyObject) {
self.lm.stopMonitoringForRegion(region!)
mapViewOutlet.removeAnnotation(carAnnotation!)
}
}
In the main UIViewController, I want to store the coordinates of the user in a variable when they press a UIButton. This variable will be used in another UIViewController with a MapView.
I tried setting up a locationManager(), but I could not get the button to work with it. Can anyone help?
Here is code that will help you:
var location: CLLocation! //to store location
lazy var locationManager: CLLocationManager = {
let _locationManager = CLLocationManager()
_locationManager.requestWhenInUseAuthorization()
// adjsut _locationManager
return _locationManager
}()
override func viewDidLoad() {
super.viewDidLoad()
locationManager.startUpdatingLocation()
}
#IBAction func buttonDidClick(sender: AnyObject) { //event handler
location = locationManager.location //set current location
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "MyViewControllerSegue" { //before showing controller
let dvc = segue.destinationViewController as! ViewController
dvc.location = location //set the current location
}
}