我使用自定义委托在我的应用程序中调用LocationManagerDelegate函数。我想调用的委托函数名为:locationFound
并在我的LocationService类中定义。我声明了委托并为我的控制器分配了self
,但仍然不会调用该方法。我错过了什么吗?
这是我在控制器中的代码:
class MapViewController: UIViewController, LocationServiceDelegate {
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if let mapView = self.mapView {
mapView.delegate = self
}
mapView.showsUserLocation = true
let locationService = LocationService.sharedInstance
locationService.delegate = self
locationService.showVerboseMessage = true
locationService.autoUpdate = false
locationService.startUpdatingLocationWithCompletionHandler { (latitude, longitude, status, verboseMessage, error) in
self.currentLocation = CLLocation(latitude: latitude, longitude: longitude)
print("LOCATION: \(self.currentLocation)")
}
}
这是我想要使用的委托函数:
func locationFound(latitude: Double, longitude: Double) {
self.currentLocation = CLLocation(latitude: latitude, longitude: longitude)
let locationService = LocationService.sharedInstance
locationService.reverseGeocodeLocationWithLatLng(latitude: latitude, longitude: longitude) { (reverseGeocodeInfo, placemark, error) in
if let reverseGeocodeInfoDictionary = reverseGeocodeInfo {
print("LocationUpdate: \(reverseGeocodeInfoDictionary)")
}
}
}
}
这是LocationService:
import Foundation
import MapKit
import CoreLocation
import Contacts
typealias IFLocationCompletionHandler = ((latitude:Double, longitude:Double, status:String, verboseMessage:String, error:String?)->())?
typealias IFReverseGeocodeCompletionHandler = ((reverseGeocodeInfo:NSDictionary?, placemark:CLPlacemark?, error:String?)->Void)?
typealias IFGeocodeCompletionHandler = ((geocodeInfo:NSDictionary?, placemark:CLPlacemark?, error:String?)->Void)?
enum GeoCodingType {
case Geocoding
case ReverseGeocoding
}
class LocationService: NSObject, CLLocationManagerDelegate {
var completionHandler:IFLocationCompletionHandler
var reverseGeocodingCompletionhandler:IFReverseGeocodeCompletionHandler
var geocodingCompletionHandler:IFGeocodeCompletionHandler
var locationStatus: NSString = "Calibrating"
var locationManager: CLLocationManager!
var verboseMessage = "Calibrating"
private let verboseMessageDictionary = [CLAuthorizationStatus.NotDetermined:"You have not yet made a choice with regards to this application.",
CLAuthorizationStatus.Restricted: "This application is not authorized to use location services. Due to active restrictions on location services, the user cannot change this status, and may not have personally denied authorization.",
CLAuthorizationStatus.Denied: "You have explicitly denied authorization for this application, or location services are disabled in Settings.",
CLAuthorizationStatus.AuthorizedAlways: "App is authorized to use location services.",
CLAuthorizationStatus.AuthorizedWhenInUse: "You have granted Authorization to use your loation only when th app is visible to you."]
var delegate:LocationServiceDelegate? = nil
var latitude: Double = 0.0
var longitude: Double = 0.0
var latitudeAsString: String = ""
var longitudeAsString: String = ""
var lastKnownLatitude: Double = 0.0
var lastKnownLongitude: Double = 0.0
var lastKnownLatitudeAsString: String = ""
var lastKnownLongitudeAsString: String = ""
var keepLastKnownLocation: Bool = true
var hasLastKnownLocation: Bool = true
var autoUpdate:Bool = false
var showVerboseMessage = false
var isRunning = false
var notificationCenter: NSNotificationCenter = NSNotificationCenter.defaultCenter()
class var sharedInstance: LocationService {
struct Static {
static let instance : LocationService = LocationService()
}
return Static.instance
}
private override init() {
super.init()
if (!autoUpdate) {
autoUpdate = !CLLocationManager.significantLocationChangeMonitoringAvailable()
}
}
private func resetLatLng() {
latitude = 0.0
longitude = 0.0
latitudeAsString = ""
longitudeAsString = ""
}
private func resetLastKnownLatLng() {
hasLastKnownLocation = false
lastKnownLatitude = 0.0
lastKnownLongitude = 0.0
lastKnownLatitudeAsString = ""
lastKnownLongitudeAsString = ""
}
func startUpdatingLocationWithCompletionHandler(completionHandler:((latitude:Double, longitude:Double, status:String, verboseMessage:String, error:String?)->())? = nil) {
self.completionHandler = completionHandler
initLocationManager()
}
func startUpdatingLocation() {
initLocationManager()
}
func stopUpdatingLocation() {
if (autoUpdate) {
locationManager?.stopUpdatingLocation()
} else {
locationManager?.stopMonitoringSignificantLocationChanges()
}
resetLatLng()
if(!keepLastKnownLocation) {
resetLastKnownLatLng()
}
}
func initLocationManager() {
locationManager = CLLocationManager()
locationManager?.delegate = self
locationManager?.desiredAccuracy = kCLLocationAccuracyBest
let Device = UIDevice.currentDevice()
let iOSVersion = NSString(string: Device.systemVersion).doubleValue
let iOS8 = iOSVersion >= 8
if (iOS8) {
locationManager?.requestWhenInUseAuthorization()
}
startLocationManager()
}
func startLocationManager() {
if (autoUpdate) {
locationManager?.startUpdatingLocation()
} else {
locationManager?.startMonitoringSignificantLocationChanges()
}
isRunning = true
}
func stopLocationmanager() {
if (autoUpdate) {
locationManager?.stopUpdatingLocation()
} else {
locationManager?.stopMonitoringSignificantLocationChanges()
}
isRunning = false
}
internal func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
stopLocationmanager()
resetLatLng()
if (!keepLastKnownLocation) {
resetLatLng()
}
var verbose = ""
if (showVerboseMessage) {
verbose = verboseMessage
}
completionHandler?(latitude: 0.0, longitude: 0.0, status: locationStatus as String, verboseMessage:verbose, error: error.localizedDescription)
if ((delegate != nil) && (delegate!.respondsToSelector(Selector("locationManagerReceivedError:")))) {
delegate?.locationManagerReceivedError!(error.localizedDescription)
}
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let arrayOfLocation = locations as NSArray
let location = arrayOfLocation.lastObject as! CLLocation
let coordLatLng = location.coordinate
latitude = coordLatLng.latitude
longitude = coordLatLng.longitude
latitudeAsString = coordLatLng.latitude.description
longitudeAsString = coordLatLng.longitude.description
var verbose = ""
if (showVerboseMessage) {
verbose = verboseMessage
}
if (completionHandler != nil) {
completionHandler?(latitude: latitude, longitude: longitude, status: locationStatus as String, verboseMessage: verbose, error: nil)
}
lastKnownLatitude = coordLatLng.latitude
lastKnownLongitude = coordLatLng.longitude
lastKnownLatitudeAsString = coordLatLng.latitude.description
lastKnownLongitudeAsString = coordLatLng.longitude.description
hasLastKnownLocation = true
if (delegate != nil) {
if ((delegate?.respondsToSelector(Selector("locationFoundGetAsString:longitude:")))!) {
delegate?.locationFoundGetAsString!(latitudeAsString, longitude: longitudeAsString)
}
if ((delegate?.respondsToSelector(Selector("locationFound:longitude:")))!) {
delegate?.locationFound(latitude, longitude:longitude)
}
}
}
internal func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
var hasAuthorized = false
let verboseKey = status
switch status {
case CLAuthorizationStatus.Restricted:
locationStatus = "Restricted Access"
case CLAuthorizationStatus.Denied:
locationStatus = "Denied Access"
case CLAuthorizationStatus.NotDetermined:
locationStatus = "Not determined"
default:
locationStatus = "Allowed Access"
hasAuthorized = true
}
verboseMessage = verboseMessageDictionary[verboseKey]!
if (hasAuthorized == true) {
startLocationManager()
} else {
resetLatLng()
if (!locationStatus.isEqualToString("Denied access")) {
var verbose = ""
if showVerboseMessage {
verbose = verboseMessage
if ((delegate != nil) && (delegate?.respondsToSelector(Selector("locationManagerVerboseMessage:")))!) {
delegate?.locationManagerVerboseMessage!(verbose)
}
}
if (completionHandler != nil) {
completionHandler?(latitude: latitude, longitude: longitude, status: locationStatus as String, verboseMessage: verbose, error: nil)
}
}
if ((delegate != nil) && (delegate?.respondsToSelector(Selector("locationManagerStatus:")))!) {
delegate?.locationManagerStatus!(locationStatus)
}
}
}
func reverseGeocodeLocationWithLatLng(latitude latitude:Double, longitude:Double, onReverseGeocodingCompletionHandler:IFReverseGeocodeCompletionHandler) {
let location: CLLocation = CLLocation(latitude: latitude, longitude: longitude)
reverseGeocodeLocationWithCoordinates(location, onReverseGeocodingCompletionHandler: onReverseGeocodingCompletionHandler)
}
func reverseGeocodeLocationWithCoordinates(coord:CLLocation, onReverseGeocodingCompletionHandler:IFReverseGeocodeCompletionHandler) {
self.reverseGeocodingCompletionhandler = onReverseGeocodingCompletionHandler
reverseGeocode(coord)
}
func reverseGeocode(location:CLLocation) {
let geocoder: CLGeocoder = CLGeocoder()
geocoder.reverseGeocodeLocation(location, completionHandler: {(placemarks, error) -> Void in
if (error != nil) {
self.reverseGeocodingCompletionhandler!(reverseGeocodeInfo:nil, placemark: nil, error: error!.localizedDescription)
} else {
if let placemark = placemarks?.first {
let address = AddressParser()
address.parseAppleLocationData(placemark)
let addressDict = address.getAddressDictionary()
self.reverseGeocodingCompletionhandler!(reverseGeocodeInfo: addressDict, placemark: placemark, error: nil)
} else {
self.reverseGeocodingCompletionhandler!(reverseGeocodeInfo: nil, placemark:nil, error: "No placemarks found")
}
}
})
}
func geocodeAddressString(address address:NSString, onGeocodingCompletionHandler:IFGeocodeCompletionHandler) {
self.geocodingCompletionHandler = onGeocodingCompletionHandler
geoCodeAddress(address)
}
private func geoCodeAddress(address:NSString) {
let geocoder = CLGeocoder()
geocoder.geocodeAddressString(address as String, completionHandler: {(placemarks: [CLPlacemark]?, error: NSError?) -> Void in
if (error != nil) {
self.geocodingCompletionHandler!(geocodeInfo:nil, placemark:nil, error: error!.localizedDescription)
} else {
if let placemark = placemarks?.first {
let address = AddressParser()
address.parseAppleLocationData(placemark)
let addressDict = address.getAddressDictionary()
self.geocodingCompletionHandler!(geocodeInfo: addressDict, placemark: placemark, error: nil)
} else {
self.geocodingCompletionHandler!(geocodeInfo: nil, placemark: nil, error: "invalid address: \(address)")
}
}
})
}
func geocodeUsingGoogleAddressString(address address:NSString, onGeocodingCompletionHandler:IFGeocodeCompletionHandler) {
self.geocodingCompletionHandler = onGeocodingCompletionHandler
geoCodeUsingGoogleAddress(address)
}
private func geoCodeUsingGoogleAddress(address:NSString) {
var urlString = "http://maps.googleapis.com/maps/api/geocode/json?address=\(address)&sensor=true" as NSString
urlString = urlString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
performOperationForURL(urlString, type: GeoCodingType.Geocoding)
}
func reverseGeocodeLocationUsingGoogleWithLatLng(latitude latitude:Double, longitude: Double, onReverseGeocodingCompletionHandler: IFReverseGeocodeCompletionHandler) {
self.reverseGeocodingCompletionhandler = onReverseGeocodingCompletionHandler
reverseGeocodeUsingGoogle(latitude: latitude, longitude: longitude)
}
func reverseGeocodeLocationUsingGoogleWithCoordinates(coord:CLLocation, onReverseGeocodingCompletionHandler: IFReverseGeocodeCompletionHandler) {
reverseGeocodeLocationUsingGoogleWithLatLng(latitude: coord.coordinate.latitude, longitude: coord.coordinate.longitude, onReverseGeocodingCompletionHandler: onReverseGeocodingCompletionHandler)
}
private func reverseGeocodeUsingGoogle(latitude latitude:Double, longitude: Double) {
var urlString = "http://maps.googleapis.com/maps/api/geocode/json?latlng=\(latitude),\(longitude)&sensor=true" as NSString
urlString = urlString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
performOperationForURL(urlString, type: GeoCodingType.ReverseGeocoding)
}
private func performOperationForURL(urlString: NSString, type:GeoCodingType) {
let url:NSURL? = NSURL(string:urlString as String)
let request:NSURLRequest = NSURLRequest(URL:url!)
let queue:NSOperationQueue = NSOperationQueue()
NSURLConnection.sendAsynchronousRequest(request, queue: queue) { (response, data, error) in
if (error != nil) {
self.setCompletionHandler(responseInfo:nil, placemark: nil, error:error!.localizedDescription, type: type)
} else {
let kStatus = "status"
let kOK = "ok"
let kZeroResults = "ZERO_RESULTS"
let kAPILimit = "OVER_QUERY_LIMIT"
let kRequestDenied = "REQUEST_DENIED"
let kInvalidRequest = "INVALID_REQUEST"
let kInvalidInput = "Invalid Input"
let jsonResult: NSDictionary = (try! NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)) as! NSDictionary
var status = jsonResult.valueForKey(kStatus) as! NSString
status = status.lowercaseString
if(status.isEqualToString(kOK)) {
let address = AddressParser()
address.parseGoogleLocationData(jsonResult)
let addressDict = address.getAddressDictionary()
let placemark:CLPlacemark = address.getPlacemark()
self.setCompletionHandler(responseInfo:addressDict, placemark: placemark, error: nil, type: type)
} else if (!status.isEqualToString(kZeroResults) && !status.isEqualToString(kAPILimit) && !status.isEqualToString(kRequestDenied) && !status.isEqualToString(kInvalidRequest)) {
self.setCompletionHandler(responseInfo: nil, placemark: nil, error:kInvalidInput, type: type)
} else {
self.setCompletionHandler(responseInfo:nil, placemark: nil, error:status as String, type: type)
}
}
}
}
private func setCompletionHandler(responseInfo responseInfo: NSDictionary?, placemark: CLPlacemark?, error: String?, type: GeoCodingType) {
if (type == GeoCodingType.Geocoding) {
self.geocodingCompletionHandler!(geocodeInfo: responseInfo, placemark: placemark, error: error)
} else {
self.reverseGeocodingCompletionhandler!(reverseGeocodeInfo: responseInfo, placemark: placemark, error: error)
}
}
}
@objc protocol LocationServiceDelegate: NSObjectProtocol {
func locationFound(latitude: Double, longitude: Double)
optional func locationFoundGetAsString(latitude: NSString, longitude: NSString)
optional func locationManagerStatus(status: NSString)
optional func locationManagerReceivedError(error: NSString)
optional func locationManagerVerboseMessage(message: NSString)
}
答案 0 :(得分:0)
你不需要像这样迅速检查你的代表:
if (delegate != nil) {
if ((delegate?.respondsToSelector(Selector("locationFoundGetAsString:longitude:")))!) {
delegate?.locationFoundGetAsString!(latitudeAsString, longitude: longitudeAsString)
}
if ((delegate?.respondsToSelector(Selector("locationFound:longitude:")))!) {
delegate?.locationFound(latitude, longitude:longitude)
}
}
当您想要致电delegate
时,您只需写下:
delegate?.locationFoundGetAsString?(latitudeAsString, longitude: longitudeAsString)
delegate?.locationFound?(latitude, longitude:longitude)
说明:
?
已经向你保证价值为零,然后不会调用你表达的右边
答案 1 :(得分:0)
我已经写了一些我已经运行的存根代码和类,希望你会发现有用的。我没有复制所有代码,而是编写了一些大纲类来让代理运行。我对你做的一件事就是我在MapViewController类上专门设置了mapView属性。如果执行以下代码并且未设置mapView属性,则不会设置delegate属性。我可能会在你的代码中遗漏它,但我没有看到它。
if let mapView = self.mapView {
mapView.delegate = self //delegate not set unless mapView is set
}
这是我的代码,可能也有帮助
class MapViewController: UIViewController, LocationServiceDelegate {
var mapView: MapView?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
protocol LocationServiceDelegate {
func locationfound() -> Void
}
class MapView {
var delegate: LocationServiceDelegate?
func locationManager()
{
delegate?.locationfound();
}
}
func locationfound() {
print ("delegate function locationfound is called")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(_ animated: Bool)
{
super.viewWillAppear(animated)
self.mapView = MapView()
if let mapView = self.mapView {
mapView.delegate = self
}
//call the task on mapview that will call the delegate function
mapView?.locationManager()
}
}
如上所述,它只是一个存根,但代理正在工作,它可能会帮助您跟踪错误。