通信协议/代理上的Swift错误

时间:2017-07-03 13:09:22

标签: ios swift delegates protocols

我正在使用Swift 3开发一个应用程序。我必须在两个视图控制器之间传递一个值(使用协议和委托)。我收到错误:

  

致命错误:在打开可选项时意外发现nil   值。

因为delegate变量的值为nil。 代理人定义为var delegate: LeftSideDelegate!,我将其称为delegate.sendShapeDelivery()

它被称为didTappedSwicht的位置的函数是另一种协议的方法(它不必影响它?)。

有谁知道为什么会出现这个错误?

import UIKit

protocol LeftSideDelegate {
    func sendShapeDelivery(deliveryPos: Int)
}

class LeftSideViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, customCellDelegate {

    var selectedIndex = -1
    var feedModelDeliveries: [deliveriesLeftTableModel] = [deliveriesLeftTableModel]()
    var delegate: LeftSideDelegate!

    @IBOutlet weak var tableSideLeft: UITableView!
    @IBAction func opacityDelivery(_ sender: UISlider) {
        print(sender.value)
    }

    //var delegate = OptionDelegate()?

    override func viewDidLoad() {
        super.viewDidLoad()
        //tableSideLeft.isEditing = true

        fillDataDeliveries()
    }

    func fillDataDeliveries() {
        for i in 0...snapShotsLegend.legendEntries[0].deliverables.count - 1 {
            let newModel = deliveriesLeftTableModel()

            newModel.firstViewLabel = snapShotsLegend.legendEntries[0].deliverables[i].type
            newModel.secondViewLabel = "Option " + snapShotsLegend.legendEntries[0].deliverables[i].type
            newModel.idDeliveryResponse = snapShotsLegend.legendEntries[0].deliverables[i].options[0].id
            newModel.initialMaxDeliveryResponse = String(snapShotsLegend.legendEntries[0].deliverables[i].options[0].initial_max_value)
            newModel.initialMinDeliveryResponse = String(snapShotsLegend.legendEntries[0].deliverables[i].options[0].initial_min_value)
            newModel.maxRangeDeliveryResponse = String(snapShotsLegend.legendEntries[0].deliverables[i].options[0].max_range)
            newModel.minRangeDeliveryResponse = String(snapShotsLegend.legendEntries[0].deliverables[i].options[0].min_range)
            feedModelDeliveries.append(newModel)
        }

        tableSideLeft.delegate = self
        tableSideLeft.dataSource = self
    }

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return snapShotsLegend.legendEntries[0].deliverables.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
        let cellIdentifier = "Cell"
        let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! customCell
        cell.setupWithModel(model: feedModelDeliveries[indexPath.row])
        cell.delegate = self as customCellDelegate

        return cell
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        if (selectedIndex == indexPath.row) {
            return 300
        } else {
            return 60
        }
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if (selectedIndex == indexPath.row) {
            selectedIndex = -1
        } else {
            selectedIndex = indexPath.row
        }

        self.tableSideLeft.beginUpdates()
        self.tableSideLeft.reloadRows(at: [indexPath], with: UITableViewRowAnimation.automatic)
        self.tableSideLeft.endUpdates()
    }

    //MARK: FUNCTIONS ALLOWS REORDERING OF CELLS
    func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
        return true
    }

    func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
        let item = snapShotsLegend.legendEntries[0].deliverables[sourceIndexPath.row]
        snapShotsLegend.legendEntries[0].deliverables.remove(at: sourceIndexPath.row)
        snapShotsLegend.legendEntries[0].deliverables.insert(item, at: destinationIndexPath.row)
    }

    func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
        return UITableViewCellEditingStyle.none
    }

    func didTappedSwicht(cell: customCell) {
        let indexPath = tableSideLeft.indexPath(for: cell)

        feedModelDeliveries[(indexPath?.row)!].swichtActiveLayer = cell.swichtActiveLayer.isOn

        if cell.swichtActiveLayer.isOn {
            print("SHOW DELIVERY TO MAP, LAYER -> \( snapShotsLegend.legendEntries[0].deliverables[(indexPath?.row)!].url_layer)")

            // MARK: SWICHT ON (NOT EXIST DELIVERABLE / EXIST DELIVERABLE)
            if feedModelDeliveries[(indexPath?.row)!].tileLayer == nil {
                delegate.sendShapeDelivery(deliveryPos: (indexPath?.row)!)
            // MARK: SWICHT OFF
            } else {
                print("Exist deliverable -> not call WMS")
            }
        } else {
            print("HIDE DELIVERY TO MAP, LAYER -> \( snapShotsLegend.legendEntries[0].deliverables[(indexPath?.row)!].url_layer)")
        }
    }

    func didMoveSlider(cell: customCell) {
        let indexPath = tableSideLeft.indexPath(for: cell)
        feedModelDeliveries[(indexPath?.row)!].sliderOpacity = cell.sliderOpacity.value
    }
}

我调用协议(at ende)函数的代码是:

import UIKit
import GoogleMaps
import MapKit
import ObjectMapper



//MARK: GLOBAL VARIABLES
let showLegend = UserDefaults.standard
let showLegendInformation = "showLegend"
var fields:WFSModel = WFSModel()
var allFields:[Field] = [Field]()
var total_parcels:[Parcel] = [Parcel]()
var poligons: [GMSPolygon] = []
var holes: [GMSMutablePath] = []
var snapShotsLegend : SnapshotsLegendModel = SnapshotsLegendModel()
var allDeliveries: [GMSURLTileLayer] = []

class MainMapVC: UIViewController, UISearchBarDelegate, CLLocationManagerDelegate, GMSMapViewDelegate {

//OUTLETS:
@IBOutlet weak var dragLegend: NSLayoutConstraint!
@IBOutlet weak var iconDragLegend: UIImageView!
@IBOutlet weak var mapView: GMSMapView!
@IBOutlet weak var timer: UIActivityIndicatorView!
@IBOutlet weak var dragLengendView: UIView!
@IBOutlet weak var iconBarLegend: UIBarButtonItem!


//MARK: VARIABLES
let layer: WMSTileOverlay
var window: UIWindow?
var centerContainer: MMDrawerController?
var url = ""
let locationManager = CLLocationManager()
var coordenatesCellSelected: [Double] =  [Double]()
var hole = GMSMutablePath()
var wfs:WFSModel = WFSModel()
var rect = GMSMutablePath()
let start = NSDate();
var polygonSelect = GMSPath()
var posSelecteTable:Int = 0
var menu_vc: LeftSideViewController!



//MARK:VIEWS
override func viewWillAppear(_ animated: Bool) {
    super.viewDidLoad()

    if coordenatesCellSelected.count != 0 {
        let bounds = GMSCoordinateBounds(path: poligons[posSelecteTable].path!)
        self.mapView!.animate(with: GMSCameraUpdate.fit(bounds, withPadding: 15.0))
        poligons[posSelecteTable].fillColor = UIColor(red: 8/256, green: 246/255, blue: 191/255, alpha: 0.9)
        poligons[posSelecteTable].strokeColor = .blue
        poligons[posSelecteTable].strokeWidth = 2
        poligons[posSelecteTable].map = mapView
    }

    if showLegend.bool(forKey: showLegendInformation) == true {

        //self.dragLengendView.isHidden = false
        self.iconBarLegend.isEnabled = true


    }
}




override func viewDidLoad() {
    super.viewDidLoad()

    menu_vc = self.storyboard?.instantiateViewController(withIdentifier: "LeftSideViewController") as! LeftSideViewController

    self.timer.startAnimating()

    locationManager.delegate = self
    locationManager.requestWhenInUseAuthorization()
    mapView.isMyLocationEnabled = true
    mapView.settings.myLocationButton = true

    url = ""

    let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(self.respondToGesture))
    swipeRight.direction = UISwipeGestureRecognizerDirection.right

    let swipeLeft = UISwipeGestureRecognizer(target: self, action: #selector(self.respondToGesture))
    swipeRight.direction = UISwipeGestureRecognizerDirection.left

    self.view.addGestureRecognizer(swipeRight)
    self.view.addGestureRecognizer(swipeLeft)

    if showLegend.bool(forKey: showLegendInformation) == false {


        self.iconBarLegend.tintColor = UIColor.clear
        self.iconBarLegend.isEnabled = false
    }


    if !allFields.isEmpty{
        drawFields()
    }

    if allFields.isEmpty{
        self.getCardfromGeoserver()
    }
    self.mapView.mapType = .satellite

}

@IBAction func menu_action(_ sender: UIBarButtonItem) {

    if AppDelegate.menu_bool{
        show_menu_left()
    }else{
        close_menu_left()
    }

}

func show_menu_left(){

    UIView.animate(withDuration: 0.6) { ()->Void in

        self.menu_vc.view.frame = CGRect(x: 0, y: 60, width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height)
        self.menu_vc.view.backgroundColor = UIColor.black.withAlphaComponent(0.6)
        self.addChildViewController(self.menu_vc)
        self.view.addSubview(self.menu_vc.view)
        AppDelegate.menu_bool = false
    }

}


func close_menu_left(){

    UIView.animate(withDuration: 0.6, animations: { ()->Void in
        self.menu_vc.view.frame = CGRect(x: -UIScreen.main.bounds.size.width, y: 60, width: -UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height)
    }) { (finished) in

        self.menu_vc.view.removeFromSuperview()
    }

    AppDelegate.menu_bool = true

}


func respondToGesture(gesture: UISwipeGestureRecognizer){
    switch gesture.direction{
    case UISwipeGestureRecognizerDirection.right:
        show_menu_left()

    case UISwipeGestureRecognizerDirection.left:
        close_on_swipe()

    default:
        break

    }
}

func close_on_swipe(){

    if AppDelegate.menu_bool{
        show_menu_left()
    }else{
        close_menu_left()
    }

}

//MARK: FUNCITIONS
required init?(coder aDecoder: NSCoder) {
    self.layer = WMSTileOverlay(urlArg: url)
    super.init(coder: aDecoder)
}


func getCardfromGeoserver() {
    mapView.clear()

    //mapView.camera = GMSCameraPosition(target: CLLocationCoordinate2D(latitude: 40.4256572451179, longitude: -3.18201821297407), zoom: 5.5, bearing: 0, viewingAngle: 0)


    //MAP POSITION WITH DIFERENTS LAYERS
    mapView.camera = GMSCameraPosition(target: CLLocationCoordinate2D(latitude: 39.59955969890008, longitude: -0.6421281303940684), zoom: 18.0, bearing: 0, viewingAngle: 0)






    let WFS_JSON = "http://192.168.5.57:8080/geoserver/LordWor/wfs?service=WFS&version=1.0.0&request=GetFeature&typeName=LordWor:hemav-fincas&maxFeatures=1721&outputFormat=json"

    if allFields.isEmpty {
        let mapsFacade = MapsFacade()
        mapsFacade.coordinatesWFS(url: WFS_JSON,
                      callbackFuncionOK: coordinatesWFSOK,
                      callbackFunctionERROR: coordinatesWFSOKERROR)
    }



}



func coordinatesWFSOK( WFS_Response:  WFSModel) {
    let fields = WFS_Response.copyFieldswfs()
    wfs = WFS_Response

        for feature in 1...(wfs.features.count) {
            //MARK: INSERT DATA FIELDS
            DataBaseManagement.shared.addFields(inputPropertyIDFarming : wfs.features[feature - 1].properties.propertyIDFarming,
                                                inputPropertyProducer : wfs.features[feature - 1].properties.propertyProducer,
                                                inputPropertyVariety : wfs.features[feature - 1].properties.propertyVariety,
                                                inputPropertyLand : wfs.features[feature - 1].properties.propertyLand)


            for parcel in 1...(wfs.features[feature - 1].geometry.coordinates.count) {

                if wfs.features[feature - 1].geometry.coordinates[parcel - 1].count == 1{//MARK: Without Hole
                    for poligon in 1...(wfs.features[feature - 1 ].geometry.coordinates[parcel - 1].count) {

                        //MARK: INSERT DATA FIELDS
                        DataBaseManagement.shared.addParcels(inputId_field: feature, inputCoordinatesJSON: String(describing: wfs.features[feature - 1].geometry.coordinates[0][0]))

                    }

                }else{
                    for id in 1...(wfs.features[feature - 1].geometry.coordinates[parcel - 1].count) {//MARK: With Hole

                        if id == 1{
                            //MARK: INSERT COOERDENATES PARCEL
                            DataBaseManagement.shared.addParcels(inputId_field: feature, inputCoordinatesJSON: String(describing: wfs.features[feature - 1].geometry.coordinates[0][0]))

                        }else{
                            //MARK: this row contains all points for create a hole
                           //DataBaseManagement.shared.addHoles(inputId_hole: parcel, inputCoordinatesJSON: String(describing: wfs.features[feature - 1].geometry.coordinates[0][id - 1]))
                            //print("-------FIN PARCELA HOLE \(id - 1)---------")
                        }

                        /*for poligon in 0...(wfs.features[feature].geometry.coordinates[coordinate][id].count - 1  ) {
                            if id == 0{//First polygon is all field without holes


                                let longitude:Double = wfs.features[feature].geometry.coordinates[coordinate][id][poligon][0]
                                let latitude:Double = wfs.features[feature].geometry.coordinates[coordinate][id][poligon][1]
                                rect.add(CLLocationCoordinate2D(latitude: latitude, longitude: longitude))
                            }else{
                                //let insertHole = DataBaseManagement.shared.addParcels(inputId_field: poligon, inputCoordinatesJSON: String(describing: wfs.features[feature].geometry.coordinates))
                                let longitude:Double = wfs.features[feature].geometry.coordinates[coordinate][id][poligon][0]
                                let latitude:Double = wfs.features[feature].geometry.coordinates[coordinate][id][poligon][1]
                                hole.add(CLLocationCoordinate2D(latitude: latitude, longitude: longitude))
                                holes.append(hole)
                            }

                        }*/
                    }

                }
            }

    }

    //MARK: Get all group of Parcels
if allFields.count == 0 {
    allFields = DataBaseManagement.shared.showAllFields()
    total_parcels = DataBaseManagement.shared.showAllParcels()
}

    drawFields()
}

func deleteAllParcels(){

    for i in 0...total_parcels.count - 1 {
        DataBaseManagement.shared.deleteAllParcels(inputId: i)
    }
}

func deleteAllFields(){
    for i in 0...allFields.count - 1 {
        DataBaseManagement.shared.deleteAllFields(inputId: i)
    }
}

func drawFields(){
    //MARK: Field All Array wiht all (properrties for field and yours parcels)
    for i in 0...allFields.count - 1{

        let arr = try! JSONSerialization.jsonObject(with: total_parcels[i]._json_Parcel.data(using: .utf8)!, options: []) as! [[Double]]
        allFields[i]._parcel.append(total_parcels[i]._json_Parcel);
        //MARK: SAVE LATITUDE AND LONGITUDE IN ARRAY
        for j in 0...arr.count - 1{
            let longitude = arr[j][0]//latitud
            let latitude = arr[j][1]//longitud

            rect.add(CLLocationCoordinate2D(latitude: latitude, longitude: longitude))
        }



        //MARK: DRAW ON THE MAP
        let polygon = GMSPolygon()
        polygon.path = rect
        poligons.append(polygon)
        rect = GMSMutablePath()
        polygon.fillColor = UIColor(red: 8/256, green: 246/255, blue: 191/255, alpha: 0.3)
        polygon.strokeColor = .blue
        polygon.strokeWidth = 2
        polygon.map = mapView


    }

    let end = NSDate()
    self.timer.stopAnimating()
    print("TIME CHARGE 'MAIN MAP'")
    print(start)
    print(end)  
}

let urlSnapshot = "..."
func getDeliverablesForField(){
    let deliverablesFacade = DeliverablesFacade()
    deliverablesFacade.snapshots(url: urlSnapshot,
                              callbackFuncionOK: snapshotsOK,
                              callbackFunctionERROR: snapshotsERROR)
}



func snapshotsOK( snapshotsResponse:  SnapshotsLegendModel) {

    snapShotsLegend = snapshotsResponse.copySnapshots()
    print("end recover fields")

}



func snapshotsERROR(_ httpCode: Int,nsError: NSError) {
    if httpCode == -1 {
        print(nsError)
        print(httpCode)
    }else{
        print(nsError)
        print(httpCode)
    }
}

var onlyOnetime = 0

func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D) {

    for polygon in poligons{

        if (GMSGeometryContainsLocation(CLLocationCoordinate2D(latitude: coordinate.latitude, longitude: coordinate.longitude), polygon.path!, true)) {
            onlyOnetime = onlyOnetime + 1

            if onlyOnetime == 1{
                getDeliverablesForField()
                showLegend.setValue(true, forKey: showLegendInformation)
                let bounds = GMSCoordinateBounds(path: polygon.path!)
                self.mapView!.animate(with: GMSCameraUpdate.fit(bounds, withPadding: 15.0))
                self.iconBarLegend.isEnabled = true
                self.iconBarLegend.tintColor = UIColor.black
            }

            polygon.fillColor = UIColor(red: 8/256, green: 246/255, blue: 191/255, alpha: 0.9)
            polygon.strokeColor = .blue
            polygon.strokeWidth = 2
            polygon.map = mapView

            //self.viewDidLoad()
        }

        else{
            polygon.fillColor = UIColor(red: 8/256, green: 246/255, blue: 191/255, alpha: 0.3)
            polygon.strokeColor = .blue
            polygon.strokeWidth = 2
            polygon.map = mapView
        }
    }
}



func coordinatesWFSOKERROR(_ httpCode: Int,nsError: NSError) {
    if httpCode == -1 {
        print(nsError)
        print(httpCode)
    }else{
        print(nsError)
        print(httpCode)
    }
}

@IBAction func goToAdvancedSearch(_ sender: Any) {
    let advancedSearch:  AdvancedSearchVC = UIStoryboard(name: "AdvancedSearch", bundle: nil).instantiateViewController(withIdentifier: "AdvancedSearchVC") as! AdvancedSearchVC
    self.navigationController?.pushViewController(advancedSearch, animated: false)
}

}

扩展名MainMapVC:LeftSideDelegate {

func sendShapeDelivery(deliveryPos : Int){

    print("Not exist deliverable -> call WMS")
    let nameDelivery = snapShotsLegend.legendEntries[0].deliverables[deliveryPos].url_layer
    let urls: GMSTileURLConstructor = { (x: UInt, y: UInt, zoom: UInt) -> URL in

        let bbox = self.layer.bboxFromXYZ(x, y: y, z: zoom)
        let urlKN = "http://192.168.5.57:8080/geoserver/LordWor/wms?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&FORMAT=image%2Fpng&TRANSPARENT=true&tiled=true&STYLES=line&layers=LordWor:\(nameDelivery)&styles=&WIDTH=256&HEIGHT=256&SRS=EPSG:3857&BBOX=\(bbox.left),\(bbox.bottom),\(bbox.right),\(bbox.top)"
        print("PETICION WMS DEL LALER: \(nameDelivery)")

        return URL(string: urlKN)!
    }



    let tileLayer: GMSURLTileLayer = GMSURLTileLayer(urlConstructor: urls)
    allDeliveries.append(tileLayer)

    tileLayer.opacity = 0.5
    tileLayer.map = mapView


}

}

2 个答案:

答案 0 :(得分:0)

出现错误是因为delegatenil。我在初始化它的代码中看不到。您应该传递其他viewController并将其设置为delegate

此外,宣布像这样的代表更安全:

weak var delegate: LeftSideDelegate?

weak部分是为了防止内存保留周期)

然后像这样使用它:

if let delegate = delegate {
    delegate.sendShapeDelivery(deliveryPos: (indexPath?.row)!) 
}

这样应用程序不会崩溃。

答案 1 :(得分:0)

内部类MainMapVC,在行

之后
menu_vc = self.storyboard?.instantiateViewController(withIdentifier: "LeftSideViewController") as! LeftSideViewController

您必须设置其委托,如下所示:

menu_vc.delegate = self