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 中提供一个数组(错误的名称标准,因为注释也在内部进行)
- 我尝试将 mapView 发送到函数但没有结果
- 我试过不调用 mapView 形式 ViewController
在函数内
self.mapView.addAnnotation(test)
没有
结果
- 我试过从 SQL 检索 class 没有结果
断点 - 错误发生在我调用 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)
我正在开发一个使用 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 中提供一个数组(错误的名称标准,因为注释也在内部进行)
- 我尝试将 mapView 发送到函数但没有结果
- 我试过不调用 mapView 形式 ViewController
在函数内
self.mapView.addAnnotation(test)
没有 结果 - 我试过从 SQL 检索 class 没有结果
断点 - 错误发生在我调用 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)