2

In my view controller, there is an outlet to a MKMapView and the view controller naturally conforms to MKMapViewDelegate to perform MapKit operations.

I'm trying to migrate to the MVVM model before further progress in the project in order to keep it tidy. However, I'm drawing a blank about how to move all the MKMapViewDelegate methods to another file where the MKMapView outlet sits in the view controller.

Thanks.

P.S. I'm coding with Swift

Can
  • 4,516
  • 6
  • 28
  • 50

2 Answers2

2

I had a situation just like that, when I create a GMSMapViewDelegate separate from my view controller.

What I did and you could try:

  • Create a class that extends NSObject and the MKMapViewDelegate. (The delegate needs to conform to NSObjectProtocol)
  • You need to create and setup the mapView in the new class, but let the view controller access it.
  • ATTENTION - remember to maintain a reference to your new class in the view controller. The delegate is a weak variable in the map view.

MapModelView.swift

class MapModelView:NSObject, MKMapViewDelegate {

   let mapView:MKMapView!

   init(screenSize: CGRect) {
        // generate the map view at the size of the screen
        // otherwise it won't be seen
        self.mapView = MKMapView(frame: CGRectMake(0, 0, screenSize.width, screenSize.height)
        super.init()
        self.mapView.delegate = self
    } 
}

ViewController.swift

class ViewController: UIViewController {
    @IBOutlet weak var mapView: MKMapView!

    override func viewDidLoad() {
        // Get the screen size for the map view creation
        let screenSize: CGRect = UIScreen.mainScreen().bounds

        mapKitOperationsDelegate = MapKitOperations(screenSize: screenSize)
        mapView = mapKitOperationsDelegate.getMapView()
        view.addSubview(mapView)
    }

(Added 02/08/2018)

PS

As mentioned by Chanchal Raj "MapView is a UI component, it shouldn't be in ViewModel class". It was my solution at the time but it's not the correct way, conceptualy speaking (using MVVM).

Will Glück
  • 1,242
  • 12
  • 17
  • Although that weak reference seems dangerous and should be handled carefully that actually makes sense. I'll give it a try and report back. Thanks. – Can Nov 20 '15 at 12:58
  • I'm trying to find a better solution, I did not enjoy the NSObject in there. – Will Glück Nov 20 '15 at 14:43
  • Curious about what you'll come up with but shouldn't we subclass NSObject? Isn't that mandatory? – Can Nov 20 '15 at 15:04
  • How should I set the delegate of the map view exactly? – Can Nov 21 '15 at 21:55
  • mapView.delegate = self, inside the delegate initialization. Yeah, I guess that subclass NSObject is mandatory. – Will Glück Nov 22 '15 at 21:01
  • I set the delegate to self inside `MapModelView` class. Inside my view controller, the mapView from `MapModelView`is given to the outlet mapView and somehow my delegate functions are not called; hence no MapKit stuff happening. Any ideas? – Can Nov 22 '15 at 21:11
  • Thats strange. I was having this problem when my mapView was losing the delegate reference, but if you are keeping a strong reference to it in the view controller thats probably not the case. Take a look at my answer, I edited the code, you should be doing something like that. – Will Glück Nov 23 '15 at 01:14
  • 1
    I made some edits. The problem was that the map view created wasn't being displayed since it was 0x0. Therefore I initiated it with the screen size. Now all of the delegate functions are being used and the map view is being rendered as I wanted. Your previous edit led me here actually. Thanks pal. – Can Nov 23 '15 at 09:18
  • 1
    MapView is a UI component, it shouldn't be in ViewModel class – Chanchal Raj Jul 28 '18 at 08:20
1

What I've done in this cases, is to have the ViewController adopt the protocol, because is part of the View layer and have the ViewModel handle the logic from the delegate method.

You could use completion blocks or delegates if it's (in the ViewModel) to handle the logic and return it to the ViewController.

This is how I handle my UITableView delegates.

Here's something that could help you decide: http://roadfiresoftware.com/2015/07/why-not-make-the-viewmodel-the-table-views-data-source/

dmlebron
  • 861
  • 6
  • 16