Search code examples
iosswiftmapboxnsnotificationcenterunrecognized-selector

Unrecognized selector, even though selector is properly named


I am using MapBoxNavigation.swift in order to build an app that navigates the user to a location. Up to the point where the navigation starts, everything works fine. But when the Navigation starts and MapBoxNavigation.swift emits posts a NSNotification (see Documentation for how the Library works), the Observer I wrote throws this error message:

app[49184:2686603] -[__NSCFConstantString navProgressDidChange:]: unrecognized selector sent to instance 0x1096dfdb0

This is the code that posts the Notification from MapBoxNavigation.swift:

NotificationCenter.default.post(name: RouteControllerAlertLevelDidChange, object: self, userInfo: [
        RouteControllerAlertLevelDidChangeNotificationRouteProgressKey: routeProgress,
        RouteControllerAlertLevelDidChangeNotificationDistanceToEndOfManeuverKey: userDistance,
        RouteControllerProgressDidChangeNotificationIsFirstAlertForStepKey: isFirstAlertForStep
        ])

This should be all necessary code:

import Foundation
import UIKit
import Mapbox
import MapboxDirections
import MapboxNavigation
import CoreLocation
import Alamofire
import SWXMLHash
import DateTimePicker

//Primary ViewController, used for basically everything
class ViewController: UIViewController, MGLMapViewDelegate, CLLocationManagerDelegate, UITextFieldDelegate, UIGestureRecognizerDelegate {

    lazy var geocoder = CLGeocoder()
    @IBOutlet weak var addressTextField: SearchTextField! //SearchTextField
    @IBOutlet var mapView: MGLMapView! //MapView of MapBox    

    @IBOutlet weak var BookingUIView: UIView!
    @IBOutlet weak var BookingView: UIView!

    //Used to geocode the Addresses
    let locationManager = CLLocationManager()
    var searched = false
    var keyboardEnabled = false
    var navigationStarted = false


    //Getting the route object
    let directions = Directions.shared
    let waitForInterval: TimeInterval = 5

    @IBOutlet weak var arrivalTimeLabel: UILabel!
    @IBOutlet weak var arrivalTimeButton: UIButton!
    @IBOutlet weak var leaveTimeButton: UIButton!
    @IBOutlet weak var searchAddressButton: UIButton!


    /* Overriding Super-Functions */
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        // This is needed.... i don't know why..
        mapView.delegate = self

        //Delegate textField to Self
        addressTextField.delegate = self

        //Dismiss Keyboard on view Touch
        //Looks for single or multiple taps.
        let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
        self.mapView.addGestureRecognizer(tap)
        //Delegate GestureRecognizer to self
        tap.delegate = self

        //Get the users current location and zoom to it
        //Authorization stuff #privacy
        self.locationManager.requestWhenInUseAuthorization()
        //initialize the updating of the location
        if(CLLocationManager.locationServicesEnabled()){
            locationManager.delegate = self
            locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
            locationManager.startUpdatingLocation()
        }

        //Adding TextViewListener
        addressTextField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)

        //Registering PresentNavigationViewControllerObserver :3
        NotificationCenter.default.addObserver(self, selector: #selector(self.enableNavigationMode), name: NSNotification.Name(rawValue: "StartNavigation"), object: nil)
    }
 func enableNavigationMode(){
        //Hiding some elements here
        startNavigation() //Gets called properly
    }


    func navProgressDidChange(_ userInfo: NSNotification){
        print("depart")
        print(userInfo)
    }

    func startNavigation(){
        //Get the JSON File via the MapBox API
        var lat = locationManager.location?.coordinate.latitude
        var long = locationManager.location?.coordinate.longitude
        var depart = CLLocation(latitude: lat!, longitude: long!)
        var start = Waypoint(coordinate: CLLocationCoordinate2D(latitude: lat!, longitude: long!))
        var end = Waypoint(coordinate: CLLocationCoordinate2D(latitude: Shared.shared.selectedParkhouse.latitude, longitude: Shared.shared.selectedParkhouse.longitude))

        var string = "https://api.mapbox.com/directions/v5/mapbox/driving-traffic/" + String(describing: long!) + "%2C" + String(describing: lat!) + "%3B" + String(describing: Shared.shared.selectedParkhouse.longitude) + "%2C" + String(describing: Shared.shared.selectedParkhouse.latitude) + ".json?access_token=mykey;)&steps=true"

//Alamofire request works properly
        Alamofire.request(string).responseData { response in
            if let data = response.data, let utf8Text = String(data: data, encoding: .utf8) {

                let jsoninput = self.convertToDictionary(text: utf8Text)!
                let jsonroute = (jsoninput["routes"] as! [AnyObject]).first as! [String:Any]

                let route = Route(json: jsonroute, waypoints: [start, end], profileIdentifier: MBDirectionsProfileIdentifierAutomobileAvoidingTraffic)
                let routecontroller = RouteController(route: route)

                print("regging")
                NotificationCenter.default.addObserver(RouteControllerAlertLevelDidChange, selector: #selector(self.navProgressDidChange(_:)), name: RouteControllerAlertLevelDidChange, object: routecontroller)
                print("resuming")
                routecontroller.resume()
                print("updating(?)")
                //Everything is fine until this function gets called and
                //MapBoxNavigation.swift posts a Notification   

                routecontroller.locationManager(routecontroller.locationManager, didUpdateLocations: [depart])

            }
        }
    }

I used the NotificationCenter a few times already, that's why i'm coming here for help. I also tried different function names and parameters from no parameters over navProgressDidChange(userInfo: Notification) to the one that's currently in my code. I don't know the reason why this happens and it also doesn't make sense in my mind, because the selector seems fine to me.

If you need any more information, just ask. Thanks for every answer already!!


Solution

  • Your syntax here is incorrect:

    NotificationCenter.default.addObserver(RouteControllerAlertLevelDidChange, selector: #selector(self.navProgressDidChange(_:)), name: RouteControllerAlertLevelDidChange, object: routecontroller)
    

    You're subscribing the string RouteControllerAlertLevelDidChange to the notification. You meant to subscribe self. You can see that in the error message:

    app[49184:2686603] -[__NSCFConstantString navProgressDidChange:]: unrecognized selector sent to instance 0x1096dfdb0
    

    It's complaining that it's trying to send the message to a constant string.