Доступ к @IBOutlet из другого класса - PullRequest
0 голосов
/ 12 марта 2019

В настоящее время я делаю приложение для отслеживания маршрута, чтобы научить себя быстро. У меня была базовая функциональность, работающая с отслеживаемым маршрутом и рисованием полилиний внутри одного класса SessionController, но я хотел разделить класс на отдельные объекты.

Вот тут я и столкнулся с проблемами. Я поместил весь код, который обновляет местоположение и рисует многоугольники и т. Д., В его собственный класс, называемый MapView.swift, и оставил @IBOutlets для кнопок, mapView и т. Д. В SessionController.swift, но теперь я не могу получить доступ к @IBOutlet чтобы mapView позволил новому классу MapView.swift обновлять текущее местоположение, обновлять полилинии и т. д.

Когда я пытаюсь ctrl + перетащить mapView @IBOutlet в MapView.swift ViewController, ничего не происходит.

Итак, я спрашиваю, как мне связать два класса, чтобы разрешить доступ к mapView в SessionController для обновления с текущим местоположением.

Я смотрю на протоколы и делегатов, но я не слишком уверен, как их реализовать, или даже если это правильный путь.

Код для SessionController можно увидеть ниже:

class SessionController: UIViewController 
{

    // Creates an outlet link to the corrosponding interfaces on the storyBoard
    @IBOutlet weak var mapView: MKMapView!
    @IBOutlet weak var startButton: UIButton!
    @IBOutlet weak var stopButton: UIButton!

    var mapScreen: MapView! = nil

    // Had to change from viewOnLoad so that the custom alert class could be utilised.
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidLoad()
        startButton.layer.cornerRadius = startButton.frame.size.height/2
        stopButton.layer.cornerRadius = stopButton.frame.size.height/2

        mapScreen = (storyboard?.instantiateViewController(withIdentifier: "mapScreen") as! MapView)

        // does the initial check whether the location services are enabled
        mapScreen.checkLocationServices()
    }

    // ends the current session, resets buttons, stops updating location and changes to history tab.
    func endSession() {
        stopButton.isHidden = true
        startButton.isHidden = false
        mapScreen.stopUpdatingLocation()
    }

    // action for when the start button is presssed.
    @IBAction func startButtonPressed(_ sender: Any) {
        mapScreen!.startUpdatingLocation()
        startButton.isHidden = true
        stopButton.isHidden = false
    }

    // action for when the stop button is pressed.
    @IBAction func stopButtonPressed(_ sender: Any) {
        presentAlertWithTitle(title: "End Session?", message: "Do you wish to end your session?", options: "Cancel", "Yes") { (option) in
            switch(option) {
            case 0:
                break
            case 1:
                self.endSession()
            default:
                break
            }
        }
    }
}

Код для MapView можно увидеть ниже:

    class MapView: UIViewController 
    {

        let locationManager = CLLocationManager()
        var myLocations: [CLLocation] = []
        let regionInMeters: Double = 500
        var mapView: MKMapView!

        //  Checks the users location services are enabled otherwise give them an alert.
        func checkLocationServices() {
            if CLLocationManager.locationServicesEnabled() {
                setupLocationManager()
                checkLocationAuthorisation()
            } else {
                // show an alert instructing on how to enable location services.
                presentAlertWithTitle(title: "Location Services Disabled", message: "Please enable your location services by navigating to Settings/Privacy/Location Services and turning on.", options: "OK") { _ in }
            }
        }

        // Setup the location manager
        func setupLocationManager() {
            locationManager.delegate = self
            locationManager.desiredAccuracy = kCLLocationAccuracyBest
        }

        // Checks whether the user has authorised location tracking via permissions.
        func checkLocationAuthorisation() {
            switch CLLocationManager.authorizationStatus() {
            case .authorizedWhenInUse:
                centerViewOnUserLocation()
            case .denied:
                // show alert detailing that the user has denied access to the location services.
                presentAlertWithTitle(title: "Access Denied", message: "Request of access has been denied to the location services", options: "OK") { _ in }
            case .notDetermined:
                locationManager.requestWhenInUseAuthorization()
            case .restricted:
                // show an alert instructing that the location services are restricted i.e. child account
                presentAlertWithTitle(title: "Access Restricted", message: "Access has been restricted to the location services", options: "OK") { _ in }
                break
            case .authorizedAlways:
                break
            }
        }

        // Centers the position onto the at the specified height by using the regionInMeters variable
        func centerViewOnUserLocation() {
            if let location = locationManager.location?.coordinate {
                let region = MKCoordinateRegion.init(center: location, latitudinalMeters: regionInMeters, longitudinalMeters: regionInMeters)
                mapView.setRegion(region, animated: true)
            }
        }

        func updatePolyLine() {
            if (myLocations.count > 1){
                // get my old location
                let sourceIndex = myLocations.count - 1
                // get the new location
                let destinationIndex = myLocations.count - 2

                // get the coordinates for both the old and the new locations
                let sourceIndexCoordinate = myLocations[sourceIndex].coordinate
                let destinationIndexCoordinate = myLocations[destinationIndex].coordinate

                // put these coordinates in to a new array so that we can get a reference to a pointer so that the MKPolyline can make use of it's position in the registry.
                var sourcePlusDestination = [sourceIndexCoordinate, destinationIndexCoordinate]

                // pass the reference of the array pointer into the constructor of MKPolyline so that a line can be drawn between the two points.
                let polyline = MKPolyline(coordinates: &sourcePlusDestination, count: sourcePlusDestination.count)

                // adds and then updates the polyline on the map.
                mapView.addOverlay(polyline)
            }
        }

        func startUpdatingLocation()
        {
            locationManager.startUpdatingLocation()
        }

        func stopUpdatingLocation()
        {
            locationManager.stopUpdatingLocation()
            tabBarController?.selectedIndex = 1

            for overlay in mapView.overlays {
                mapView.removeOverlay(overlay)
            }
        }
    }

// an extension for SessionController that uses delegates to listen for changes in the location and authorisation
extension MapView: CLLocationManagerDelegate 
{

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) 
    {
        guard let location = locations.last else { return }
        let center = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
        let region = MKCoordinateRegion.init(center: center, latitudinalMeters: regionInMeters, longitudinalMeters: regionInMeters)
        mapView.setRegion(region, animated: true)

        myLocations.append(locations[0] as CLLocation)
        updatePolyLine()
    }

    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) 
    {
        checkLocationAuthorisation()
    }
}

extension MapView: MKMapViewDelegate 
{

    func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer 
    {
        if overlay is MKPolyline 
        {
            let polylineRenderer = MKPolylineRenderer(overlay: overlay)
            polylineRenderer.strokeColor = UIColor.blue
            polylineRenderer.lineWidth = 4
            return polylineRenderer
        }
        return MKPolygonRenderer()
    }
}

1 Ответ

0 голосов
/ 13 марта 2019

Я немного смущен вашим кодом и вопросом, но, надеюсь, это поможет вам выбрать правильный путь ...

Вы создаете свою карту на экране здесь:

mapScreen = (storyboard?.instantiateViewController(withIdentifier: "mapScreen") as! MapView)

но никогда не устанавливайте это свойство mapView следующим образом:

mapScreen = (storyboard?.instantiateViewController(withIdentifier: "mapScreen") as! MapView)
mapScreen.mapView = mapView

Также похоже, что вы хотите установить делегат вашего MKMapView на mapScreen, учитывая, что вы его реализовали (extension MapView: MKMapViewDelegate)

например,

mapScreen = (storyboard?.instantiateViewController(withIdentifier: "mapScreen") as! MapView)
mapScreen.mapView = mapView
mapView.delegate = mapScreen

Кроме того, я думаю, что вам нужна слабая ссылка на MKMapView внутри MapView.

Я также не понимаю, как вывы представляете mapScreen, вы, кажется, создаете его экземпляр, но на самом деле не представляете его.Я думаю, что скриншот вашей раскадровки или еще немного вашего кода могут помочь.

...