2017-07-03 112 views
0

我正在用Swift 3開發一個應用程序。到了必須在兩個視圖控制器之間傳遞一個值(使用協議和委託)的時候。我得到的錯誤:通信協議/委託快速錯誤

fatal error: unexpectedly found nil while unwrapping an optional value.

因爲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 
    } 
} 

其中我所說的協議(在恩德)代碼的功能是:

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 


} 

} 
+1

補充的嗎?代替 !到這一行的最後部分「var delegate:LeftSideDelegate!」 –

+1

你在哪裏爲'delegate'變量賦值? –

+1

@jordi Gallen Renau委託用於實現多重繼承(在ex中稱爲java的接口)。你在哪裏確認你的代表並告訴它它需要從哪個控制器類工作? –

回答

0

內部類MainMapVC,行

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

你要設置其委託,像這樣經過:

menu_vc.delegate = self 
+0

完美!!!!謝謝 :) !!!它的解決方案 –

0

出現錯誤,因爲您的delegatenil。我無法在提供的代碼中看到它初始化的位置。您應該通過您的其他viewController並將其設置爲delegate

此外,它更安全聲明這樣的委託:

weak var delegate: LeftSideDelegate? 

(該weak部分是爲了防止記憶保留週期)

,然後用它是這樣的:

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

這種方式應用程序不會崩潰。

+0

謝謝@Max Pevsner! 你的解決方案永遠不會進入if :(。爲什麼代理的價值是零??? –

+1

你可以在網上找到很多關於'weak'的解釋當你創建你的'LeftSideViewController'實例時,設置'這樣的代理':'leftSideViewControllerInstance.delegate = mainMapVCInstance'。 –

+0

因爲你的'委託'仍然是'nil',所以你必須初始化它。 –