自定义委托未调用

时间:2016-04-18 13:56:05

标签: swift

我使用自定义委托在我的应用程序中调用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)
}

2 个答案:

答案 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()
}

}

如上所述,它只是一个存根,但代理正在工作,它可能会帮助您跟踪错误。