MapView 未在函数中实例化

MapView isn't instanciated in function

我正在开发一个使用 MKMapView 的应用程序,我希望根据从 MySQL 加载数据的 PHP 文件放置注释。我在 iOS 编程方面没有那么丰富的经验,但我正在学习,我无法集中精力解决发生在我身上的问题。

我已经设法将数据获取到 MSMutableArray 并将其转换为 NSDirctionary 并为每个对象使用一个对象 class。当我试图在地图上放置图钉(注释)时出现错误 fatal error: unexpectedly found nil while unwrapping an Optional value 我查看了调试并发现 mapView 为 nil 并得出结论,当我尝试放置一个注释程序没有引用应该放置注释的位置。

当我放置对象的创建并在 viewDidLoad() function/method 中调用 mapView.addAnnotation(对象)时,我已经设法让注释显示出来。但是每当我将 mapView 嵌套到 class (ViewController) 中的另一个函数时,它就会中断。

forwardGeoCoding 方法是将我以纯文本形式获取的地址转换为坐标,以便能够将它们正确放置在地图上。 setArray 正在从 MySQL/PHP class 中获取数据并在 ViewController 中提供一个数组(错误的名称标准,因为注释也在内部进行)



断点 - 错误发生在我调用 forwardGeocoding 函数的地方,因为 mapView 控件为 nil。


ViewController.swift

//  Created by Tony Langlet on 2016-05-18.
//  Copyright © 2016 Tony Langlet. All rights reserved.
//

import UIKit
import MapKit
import CoreLocation

class ViewController: UIViewController, MKMapViewDelegate, HomeModelProtocal {

    var feedItems: NSArray = NSArray()
    var selectedLocation : LocationModel = LocationModel()
    var popViewController : PopUpViewControllerSwift! = PopUpViewControllerSwift(nibName: "PopUpViewController", bundle: nil)

    @IBOutlet weak var mapView: MKMapView!

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: NSBundle!) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        let deviceItem = UIScreen.mainScreen().traitCollection.userInterfaceIdiom

        switch (deviceItem) {
        case .Phone:
            if UIScreen.mainScreen().scale == 3 {
                popViewController = PopUpViewControllerSwift(nibName: "PopUpViewController_iPhone6Plus", bundle: nil)
            } else {
                popViewController = PopUpViewControllerSwift(nibName: "PopUpViewController_iPhone6", bundle: nil)
            }
        case .Pad:
            popViewController = PopUpViewControllerSwift(nibName: "PopUpViewController_iPad", bundle: nil)
        case .Unspecified:
            popViewController = PopUpViewControllerSwift(nibName: "PopUpViewController", bundle: nil)
        default:
            popViewController = PopUpViewControllerSwift(nibName: "PopUpViewController", bundle: nil)
        }

        mapView.delegate = self

        let homeModel = HomeModel()
        homeModel.delegate = self
        homeModel.downloadItems()

    }

    func itemsDownloaded(items: NSArray) {
        feedItems = items

        //self.listTableView.reloadData()
    }

    func setArray(array: NSMutableArray) {
        var jsonElement: NSDictionary = NSDictionary()

        for item in array {
            jsonElement = item as! NSDictionary
            let id = jsonElement["id"] as? String
            let name = jsonElement["name"] as? String
            let address = jsonElement["address"] as? String
            let city = jsonElement["city"] as? String
            let country = jsonElement["country"] as? String
            let typ = jsonElement["typ"] as? String
            let lastresult = jsonElement["lastresult"] as? String

            let myaddress = ("\(address), \(city), \(country)")
            //print(array)
            forwardGeocoding(self.mapView, coordAddress: myaddress, id: id!, name: name!, address: address!, typ: typ!, lastresult: last result!) // <-- This is where it breaks.

        }
    }

    func forwardGeocoding(mv: MKMapView, coordAddress: String, id: String, name: String, address: String, typ: String, lastresult: String) {

        CLGeocoder().geocodeAddressString(coordAddress, completionHandler: { (placemarks, error) in
            if error != nil {
                print(error)
                return
            }

            if placemarks?.count > 0 {
                let placemark = placemarks?[0]
                let location = placemark?.location
                let coordinate = location?.coordinate
                //print("\(name) \n\(address) \n\(typ) \n\(lastresult) \nlat: \(coordinate!.latitude), long: \(coordinate!.longitude)")

                let test = restObject(id: id, name: name, address: address, coordinate: CLLocationCoordinate2D(latitude: (coordinate!.latitude), longitude: (coordinate!.longitude)), typ: typ, lastresult: lastresult)


                mv.addAnnotation(test)

            }
        })
    }


    func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
        let identifier = "restObject"

        if annotation.isKindOfClass(restObject.self) {
            if let annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier) {
                annotationView.annotation = annotation
                return annotationView
            } else {
                let annotationView = MKPinAnnotationView(annotation:annotation, reuseIdentifier:identifier)
                annotationView.enabled = true
                annotationView.canShowCallout = true

                let btn = UIButton(type: .DetailDisclosure)
                annotationView.rightCalloutAccessoryView = btn
                return annotationView
            }
        }

        return nil
    }


    func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
        let restaurant = view.annotation as! restObject
        let name = restaurant.name
        let address = restaurant.address
        let typ = restaurant.typ
        let lastresult = restaurant.lastresult

        popViewController.title = title
        popViewController.showInView(self.view, argStatusImg: UIImage(named: "icon-nogood"), argTitle: name, argAddress: address, argType: typ, argLastresult: lastresult, argDate: "2016-01-01", animated: true)

    }
}

HomeModel.swift(从 PHP/MYSQL 检索数据)

//  Created by Tony Langlet on 2016-06-10.
//  Copyright © 2016 Tony Langlet. All rights reserved.
//

import Foundation

protocol HomeModelProtocal: class {
    func itemsDownloaded(items: NSArray)
}

class HomeModel: NSObject, NSURLSessionDataDelegate {

    weak var delegate: HomeModelProtocal!

    var data : NSMutableData = NSMutableData()

    let urlPath: String = "path to PHP file"

    func downloadItems() {

        let url: NSURL = NSURL(string: urlPath)!
        var session: NSURLSession!
        let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()

        session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: nil)

        let task = session.dataTaskWithURL(url)

        task.resume()
    }

    func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
        self.data.appendData(data)
    }

    func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?){
        if error != nil {
            print("Failed to download data")
        } else {
            print("Data downloaded")
            var jsonResult: NSMutableArray = NSMutableArray()

            do {
                jsonResult = try NSJSONSerialization.JSONObjectWithData(self.data, options:NSJSONReadingOptions.AllowFragments) as! NSMutableArray
            } catch let error as NSError {
                print(error)
            }

            let VC = ViewController()
            VC.setArray(jsonResult)

        }
    }
}

restObject.swift(对象class)

//  Created by Tony Langlet on 2016-05-18.
//  Copyright © 2016 Tony Langlet. All rights reserved.
//


import MapKit
import UIKit

class restObject: NSObject, MKAnnotation {
    var id: String
    var name: String
    var address: String
    var coordinate: CLLocationCoordinate2D
    var typ: String
    var lastresult: String

    init(id: String, name: String, address: String, coordinate: CLLocationCoordinate2D, typ: String, lastresult: String) {

        self.id = id
        self.name = name
        self.address = address
        self.coordinate = coordinate
        self.typ = typ
        self.lastresult = lastresult

    }
}

编辑 2:

func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?){
    if error != nil {
        print("Failed to download data")
    } else {
        print("Data downloaded")
        var jsonResult: NSMutableArray = NSMutableArray()

        do {
            jsonResult = try NSJSONSerialization.JSONObjectWithData(self.data, options:NSJSONReadingOptions.AllowFragments) as! NSMutableArray
        } catch let error as NSError {
            print(error)
        }

        //let VC = ViewController()
        //VC.setArray(jsonResult)
        // Here you are creating new view controller, it's not same controller which you are seeing on screen, and in this init controllers view is not loaded from xib and that's why mapView is nil  
        delegate?.itemsDownloaded()

    }

编辑:在 forwardGecoding 中添加断点并检查所有变量,coordinate 可能为零,然后它崩溃了。

override init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: NSBundle!) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    }

您应该在此方法中传递您的 xib 文件的名称,以便它加载视图。 super.init(nibName: NAME_OF_XIB, bundle: nibBundleOrNil)