delegatesclosuresswift4mklocalsearch

Passing data with a delegate from a closure


I have two view controllers and I am trying to pass data from one to the other. The data is returned from an MKLocalSearch closure. But I cannot seem to get my delegate method to run. I hope that someone can shed some light on this? I mocked up a smaller version of what I'm trying to do. Also, I don't use storyboards. I code up everything. Here is the code...

import UIKit
import MapKit

protocol SendDataDelegate {
    func sendData(data: String)
}

class OneViewController: UIViewController {

var delegate: SendDataDelegate?

override func viewDidLoad() {
    super.viewDidLoad()

    doSearch() { coord in
        if let coord = coord {
            //When the execution gets here, coord does have
            //the values to be sent to the nexr view controller.
            self.delegate?.sendData(data: "\(coord)")
            let twoViewController = TwoViewController()
            self.present(twoViewController, animated: true)
        }
    }
}

func doSearch(completion: @escaping (CLLocationCoordinate2D?) -> Void) {

    var coord: CLLocationCoordinate2D?
    let request = MKLocalSearchRequest()

    request.naturalLanguageQuery = "New York"

    let search = MKLocalSearch(request: request)

    search.start(completionHandler: {(response, error) in

        if error != nil {
            print("Error occured in search:\(error!.localizedDescription)")
        } else if response!.mapItems.count == 0 {
            print("No matches found")
        } else {
            print("Matches found")

            coord = response?.mapItems[0].placemark.coordinate
        }
        completion(coord)
    })
  }
}

import UIKit

class TwoViewController: UIViewController, SendDataDelegate {

var myData: String = ""
var oneViewController = OneViewController()

override func viewDidLoad() {
    super.viewDidLoad()
    oneViewController.delegate = self
}

func sendData(data: String) {
    myData = data
    print ("myData: \(myData)")
}

}

Solution

  • In your TwoViewController, you have a property holding another instance of OneViewController and setting the delegate of it to self.

    So, each time you create an instance of TwoViewController, a new instance of OneViewController is created, but none of them are actually the one in due of showing the actual view of OneViewController.

    In your case, delegate pattern is not appropriate and you should better call the method of TwoViewController directly:

    class OneViewController: UIViewController {
    
        //no need to have a delegate
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            doSearch() { coord in
                if let coord = coord {
                    //When the execution gets here, coord does have
                    //the values to be sent to the nexr view controller.
                    let twoViewController = TwoViewController()
                    twoViewController.sendData(data: "\(coord)")
                    self.present(twoViewController, animated: true)
                }
            }
        }
    
        //...    
    }
    
    class TwoViewController: UIViewController {
    
        var myData: String = ""
        //Creating a new instance of `OneViewController` has no meaning.
    
        override func viewDidLoad() {
            super.viewDidLoad()
            //Useless to set the delegate of newly created `OneViewController`.
        }
    
        func sendData(data: String) {
            myData = data
            print ("myData: \(myData)")
        }
    
    }
    

    If you have any reason to have a property oneViewController in TwoViewController, please explain why. Your current code explains nothing.