0

So I have a navigation controller that consist of a view controller and a UITableViewController. The view controller contains a mapview and a textfield and the tableviewcontroller searches for the locations. enter image description here

When i choose a location in the table view controller, I would like to be able to store the address in the textfield. I can get the address that I want to print enter image description here

However whenever I try to assign that address to the textfield, the app crashes with a "fatal error: unexpectedly found nil while unwrapping an Optional value" Does anyone know why? This is my tableview controller code:

import UIKit
import MapKit

class LocationSearchTable: UITableViewController {


    weak var handleMapSearchDelegate: HandleMapSearch?
    var matchingItems: [MKMapItem] = []
    var mapView: MKMapView?


    func parseAddress(_ selectedItem:MKPlacemark) -> String {

        // put a space between "4" and "Melrose Place"
        let firstSpace = (selectedItem.subThoroughfare != nil &&
                            selectedItem.thoroughfare != nil) ? " " : ""

        // put a comma between street and city/state
        let comma = (selectedItem.subThoroughfare != nil || selectedItem.thoroughfare != nil) &&
                    (selectedItem.subAdministrativeArea != nil || selectedItem.administrativeArea != nil) ? ", " : ""

        // put a space between "Washington" and "DC"
        let secondSpace = (selectedItem.subAdministrativeArea != nil &&
                            selectedItem.administrativeArea != nil) ? " " : ""

        let addressLine = String(
            format:"%@%@%@%@%@%@%@",
            // street number
            selectedItem.subThoroughfare ?? "",
            firstSpace,
            // street name
            selectedItem.thoroughfare ?? "",
            comma,
            // city
            selectedItem.locality ?? "",
            secondSpace,
            // state
            selectedItem.administrativeArea ?? ""


        )

        return addressLine
    }



}

extension LocationSearchTable : UISearchResultsUpdating {

    func updateSearchResults(for searchController: UISearchController) {
        guard let mapView = mapView,
            let searchBarText = searchController.searchBar.text else { return }

        let request = MKLocalSearchRequest()
        request.naturalLanguageQuery = searchBarText
        request.region = mapView.region
        let search = MKLocalSearch(request: request)

        search.start { response, _ in
            guard let response = response else {
                return
            }
            self.matchingItems = response.mapItems
            self.tableView.reloadData()


        }

    }

}

extension LocationSearchTable {

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return matchingItems.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell")!
        let selectedItem = matchingItems[indexPath.row].placemark
        cell.textLabel?.text = selectedItem.name
        cell.detailTextLabel?.text = parseAddress(selectedItem)

       // let right = (cell.detailTextLabel?.text)!

       // print(right)

        //print(selectedItem.name)
      //  print(parseAddress(selectedItem))

        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let selectedItem = matchingItems[indexPath.row].placemark
        handleMapSearchDelegate?.dropPinZoomIn(selectedItem)
        dismiss(animated: true, completion: nil)

         let cell = tableView.dequeueReusableCell(withIdentifier: "cell")!


         cell.detailTextLabel?.text = parseAddress(selectedItem)






        DispatchQueue.main.async {
        let right = cell.detailTextLabel?.text
        print (right!)
        let vc = ViewController()
        vc.testTxt.text = right!

        }


}
}
codeislife
  • 97
  • 2
  • 11
  • Which line does that error appears on? – user3407319 Jun 29 '17 at 03:09
  • vc.testTxt.text = right! – codeislife Jun 29 '17 at 03:10
  • You're instantiating a new `ViewController`, not referencing the existing one that is already instantiated. – paulvs Jun 29 '17 at 03:12
  • Did you try making a custom class for your cell and then making an outlet for the text field there and downcasting the cell? – user3407319 Jun 29 '17 at 03:12
  • Use the [Delegate Pattern](https://stackoverflow.com/a/33229483/1305067) to pass data back through the view controller stack. – paulvs Jun 29 '17 at 03:15
  • I have not, how do i do this? and what should i do to reference my view controller? – codeislife Jun 29 '17 at 03:17
  • Make a class that subclasses UITableViewCell and in the identity inspector put the name of the class under Class then downcast the cell dequeued to the name of the class, to reference the view controller use UIApplication.shared.keyWindow?.rootViewController since it is the root view controller – user3407319 Jun 29 '17 at 03:28
  • im very new to swift so I'm not too sure how to do this. Can you provide sample code please? – codeislife Jun 29 '17 at 03:32
  • There is no code :) just follow the steps and tell me if you need any help – user3407319 Jun 29 '17 at 03:34
  • If you are asking about the downcasting code, use as! followed by the class name of cell – user3407319 Jun 29 '17 at 03:35
  • This should help you: https://developer.apple.com/library/content/referencelibrary/GettingStarted/DevelopiOSAppsSwift/CreateATableView.html#//apple_ref/doc/uid/TP40015214-CH8-SW1 – user3407319 Jun 29 '17 at 03:36

2 Answers2

0

You should not be doing this cell = tableView.dequeueReusableCell(withIdentifier: "cell")! in your didSelectRow method. If you want to see which item is selected, you need to get it from array by indexPath.row as index like this

verride func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let selectedItem = matchingItems[indexPath.row].placemark
}

To pass this data to the previous view controller, you need an unwind segue like this post.

Fangming
  • 24,551
  • 6
  • 100
  • 90
0

In your extension in the didSelectRow you're dismissing the controller then trying to dequeue the cell. Since the controller no longer exists I think tableView is nil and dequeueing causes a crash. What you probably want to do is when pushing the TableViewController you should pass in the reference of the current controller and then use that to set the textfield property

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let selectedItem = matchingItems[indexPath.row].placemark
        handleMapSearchDelegate?.dropPinZoomIn(selectedItem)
        dismiss(animated: true, completion: nil)

         let cell = tableView.dequeueReusableCell(withIdentifier: "cell")!

         cell.detailTextLabel?.text = parseAddress(selectedItem)
}
Harry Singh
  • 826
  • 5
  • 11