Reputation: 9153
When my view appears:
struct TurnOnLocation: View {
var body: some View {
ZStack {
Color.orange
.edgesIgnoringSafeArea(.all)
VStack {
Spacer()
Image(systemName: "globe")
.resizable()
.aspectRatio(contentMode: .fill)
.foregroundColor(.white)
Spacer()
Button(action: {
let locationManager = LocationManager()
locationManager.locationManager.requestWhenInUseAuthorization()
locationManager.locationManager.startUpdatingLocation()
}) {
Text("Turn on location")
}.foregroundColor(Color.black)
.font(Font.system(size:22))
.padding(20)
.background(
Rectangle()
.fill(Color.white)
.border(Color.white, width:1)
)
.cornerRadius(50)
.shadow(radius: 10)
.padding(50)
}
}
}
}
It asks the user for location before the Button
is tapped. Why is this? I've added my model below to be fired when it's initialised (which should be when the button is clicked).
class LocationManager: NSObject, ObservableObject {
@Published var locationStatus: CLAuthorizationStatus? = CLAuthorizationStatus.notDetermined
@Published var locationPermissionStatus = PermissionStatus.unknown
@Published var location: CLLocation?
let locationManager = CLLocationManager()
override init(){
super.init()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
}
enum PermissionStatus {
case unknown
case authorizedWhenInUse
case authorizedAlways
case restricted
case denied
}
func getLocation() -> CLLocationCoordinate2D? {
return self.location?.coordinate
}
}
Any idea how I can ensure the dialog only shows after the button is clicked?
EDIT:
I have updated the code:
Button(action: {
let locationManager = LocationManager()
locationManager.requestPermission()
})
Model
class LocationManager: NSObject, ObservableObject , CLLocationManagerDelegate {
@Published var locationStatus: CLAuthorizationStatus? = CLAuthorizationStatus.notDetermined
@Published var locationPermissionStatus = PermissionStatus.unknown
@Published var location: CLLocation?
let locationManager = CLLocationManager()
override init(){
super.init()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
}
func requestPermission(){
self.locationManager.requestWhenInUseAuthorization()
}
func locationManager(_ manager: CLLocationManager,
didChangeAuthorization status: CLAuthorizationStatus) { switch status {
case .restricted, .denied:
// Disable your app's location features
print("restricted")
break
case .authorizedWhenInUse:
// Enable your app's location features.
print("authorizedWhenInUse")
self.locationManager.startUpdatingLocation()
break
case .authorizedAlways:
// Enable or prepare your app's location features that can run any time.
print("authorizedAlways")
self.locationManager.startUpdatingLocation()
break
case .notDetermined:
print("notDetermined")
break
}
}
However, when I click the button, the dialog asking for location permissions disappears after one second. Any idea why?
Upvotes: 2
Views: 441
Reputation: 13260
To fix disappearing after 1 sec, try to init location manage like here:
struct TurnOnLocation: View {
let locationManager = LocationManager() <- try to init location manager here
var body: some View {
ZStack {
Color.orange
.edgesIgnoringSafeArea(.all)
VStack {
Spacer()
Image(systemName: "globe")
.resizable()
.aspectRatio(contentMode: .fill)
.foregroundColor(.white)
Spacer()
Button(action: {
locationManager.locationManager.requestWhenInUseAuthorization()
locationManager.locationManager.startUpdatingLocation()
}) {
Text("Turn on location")
}.foregroundColor(Color.black)
.font(Font.system(size:22))
.padding(20)
.background(
Rectangle()
.fill(Color.white)
.border(Color.white, width:1)
)
.cornerRadius(50)
.shadow(radius: 10)
.padding(50)
}
}
}
}
Upvotes: 0
Reputation: 5220
You are requesting authorization in your LocationManager
init method.
you should remove that code from init.
class LocationManager: NSObject, ObservableObject {
@Published var locationStatus: CLAuthorizationStatus? = CLAuthorizationStatus.notDetermined
@Published var locationPermissionStatus = PermissionStatus.unknown
@Published var location: CLLocation?
let locationManager = CLLocationManager()
override init(){
super.init()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
}
func requestAuthorization() {
self.locationManager.requestWhenInUseAuthorization()
}
func startUpdate() {
self.locationManager.startUpdatingLocation()
}
enum PermissionStatus {
case unknown
case authorizedWhenInUse
case authorizedAlways
case restricted
case denied
}
func getLocation() -> CLLocationCoordinate2D? {
return self.location?.coordinate
}
}
and in your view:
struct TurnOnLocation: View {
var body: some View {
ZStack {
Color.orange
.edgesIgnoringSafeArea(.all)
VStack {
Spacer()
Image(systemName: "globe")
.resizable()
.aspectRatio(contentMode: .fill)
.foregroundColor(.white)
Spacer()
Button(action: {
let locationManager = LocationManager()
locationManager.requestAuthorization()
// you should check for authorization result first
locationManager.startUpdatingLocation()
}) {
Text("Turn on location")
}.foregroundColor(Color.black)
.font(Font.system(size:22))
.padding(20)
.background(
Rectangle()
.fill(Color.white)
.border(Color.white, width:1)
)
.cornerRadius(50)
.shadow(radius: 10)
.padding(50)
}
}
}
}
Upvotes: 0
Reputation: 1933
There are two things to fix:
You're already calling requestWhenInUseAuthorization
in init
, which is why you're seeing the alert when the button is constructed. You should remove requestWhenInUseAuthorization
in init
.
You should call startUpdatingLocation
after you're sure that you have authorization, in LocationManager
.
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { switch status { case .authorizedAlways, .authorizedWhenInUse: manager.startUpdatingLocation() default: print("no auth") } }
Upvotes: 2