I'm trying to implement the CLLocationManagerDelegate
protocol requirements via a protocol extension, but the location manager doesn't see it in the protocol extension and fails. However, it works with the same code when moved into the class.
Here's what I'm doing:
class ViewController: UIViewController, MyLocationProtocol {
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
locationManager.distanceFilter = 1000.0
locationManager.delegate = self
// Below crashes when implementation in protocol extension
locationManager.requestLocation()
}
}
protocol MyLocationProtocol: CLLocationManagerDelegate {
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
func locationManager(manager: CLLocationManager, didFailWithError error: NSError)
}
extension MyLocationProtocol /*where Self: UIViewControll*/ { // Tried using where clause but still no go :(
// Not being triggered by CLLocationManagerDelegate! :(
// Move to ViewController class and error goes away
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("MyLocationProtocol: locationManager: didUpdateLocations")
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print("MyLocationProtocol: locationManager: didFailWithError")
}
}
Notice in extension MyLocationProtocol
I'm putting the didUpdateLocations
and didFailWithError
implementations there. They never get trigger and actually crash saying: 'Delegate must respond to locationManager:didUpdateLocations:'
. If I move the same didUpdateLocations
and didFailWithError
code to ViewController
, everything works as expected.
Is there something I'm missing on why this is not working through protocol extensions? The class is recognized as comforming to CLLocationManagerDelegate
, otherwise it would fail at locationManager.delegate = self
. Any ideas on how to make this work or is there a bug somewhere?
protocol extension is pure Swift staff. The rules for dispatch for protocol extensions are:
IF the inferred type of a variable is the protocol
IF the inferred type of the variable is the type THEN the type’s implementation is called.
Taking all this in account ...
import XCPlayground
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
import Foundation
import MapKit
class Lm: NSObject, CLLocationManagerDelegate {
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [AnyObject]) {
print("\(locations)")
}
}
class C:Lm {
let lm = CLLocationManager()
override init() {
super.init()
lm.delegate = self
lm.startUpdatingLocation()
}
}
let c = C()
/*
2016-02-22 08:41:56.506 Untitled Page 10[32000:11547708] ### Failed to load Addressbook class CNContactNameFormatter
[<+48.71408491,+21.20868516> +/- 65.00m (speed -1.00 mps / course -1.00) @ 22/02/16 08 h 41 min 57 s Central European Standard Time]
[<+48.71408491,+21.20868516> +/- 65.00m (speed -1.00 mps / course -1.00) @ 22/02/16 08 h 41 min 57 s Central European Standard Time]
[<+48.71415732,+21.20859246> +/- 65.00m (speed -1.00 mps / course -1.00) @ 22/02/16 08 h 41 min 57 s Central European Standard Time]
....
*/
other option is to do something like ...
import XCPlayground
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
import Foundation
import MapKit
class MyLocationManager: CLLocationManager, CLLocationManagerDelegate {
override init() {
super.init()
delegate = self
}
}
extension MyLocationManager {
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [AnyObject]) {
print("\(locations)")
}
}
class C {
let lm = MyLocationManager()
init() {
lm.startUpdatingLocation()
}
}
if all types are known at compile time and there is no 'optional' method in protocol, it works 'as expected'
protocol P { func foo() }
extension P { func foo() { print("p") } }
protocol P1: P {}
extension P1 { func foo() { print("p1") } }
class C: P {}
class C1: P1 {}
let c = C()
let c1 = C1()
let p:P = C()
let p1:P = C1()
c.foo() // p
c1.foo() // p1
p.foo() // p
p1.foo() // p1
for further reading see this and this
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With