MapKit Tutorial: Getting Started

Thx. It works now. Had a problem with returning values. But took care of it.
and BTW, your tutorial is awesome. Learned so much from this.
Thx again.

Audrey:

Thanks for clear and useful tutorial. I would like to adapt it to an app showing World War I monuments in New Jersey but am unsure as to how to format the data and images (Iā€™m new at this.) Any suggestions?

do you mean, the data isnā€™t already in a database, like my Honolulu Art?

if you store the data in the app itself, you donā€™t need to work with JSON; use the file manager or a property list: Saving Data video course

do you want to make an iOS app version of this page?

it seems they only provide addresses, so youā€™d need to use geocoding to get the latitude and longitude: MapKit video course part 4

for images, you could link to theirs, but if they move them, youā€™ll need to update your app; also, you probably need their permission before you make your app publicly available.

is it an option to contact them directly, and ask for their data?

Hi, thanks a lot for the tutorial , is very clary and easy.

I want to ask a question .

I need to open the same JSON file from WEB URL , for example :ā€œHTTP://localhost/xxxx.JSONā€ , not in build path.

How I can do ?

Thank you very much for your answer.

If the delegate works like a table view delegate, why should you split up the creation of an MKPinAnnotationView.

This works too:

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {

    if let artwork = annotation as? Artwork {
        var artworkView = mapView.dequeueReusableAnnotationViewWithIdentifier("ArtworkView")
        artworkView.annotation = artwork
        artworkView.canShowCallout = true
        return artworkView
    }
    
    return nil
}

Ok, never mind.

If I donā€™t create the MKAnnotationView first and just dequeue it all the time, I wonā€™t get the callout button.

hi Paolo: if your file is really local, you can use Data(contentsOf:); but if the file is on a remote server, you should use URLSession. You can start with NSURLSession Tutorial - Iā€™ve written an update for this, which should appear next month or so. Or look at our URLSession video course.

Data(contentsOf:) blocks the main thread, so you shouldnā€™t use it to get data from remote servers.

hi Sam: thanks for posting! Iā€™m glad you figured it out :smile:

i have try but is not simple, can you help me ?

var networks = Artwork
func loadInitialData() {
// 1

var url: URL!
url = URL(string: "https://10.6.68.141/node.json")

// let fileName = Bundle.main.path(forResource: ā€œnodeā€, ofType: ā€œjsonā€);

    do {
        
    
    data = try URL(contentsOf: url)

// data = try Data(contentsOf: URL(fileURLWithPath: fileName!), options: NSData.ReadingOptions(rawValue: 0))

} catch _ {
data = nil
}




// 2
var jsonObject: Any? = nil
if let data = data {
  do {
   jsonObject = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions(rawValue: 0))
  } catch _ {
    jsonObject = nil
  }
}

Hi, delete last post , I found the solution and it work.

Thank very much for your support.

Hi , sorry but in local work but I donā€™t find a solution with URLSession for remote JSON link .
Here the code that working with local link . Can you help me ? very thanks

var networks = Artwork
func loadInitialData() {
// 1

var url: URL!
url = URL(string: "http://10.6.82.163/node.json")

var data: Data!

do {
        
data = try? Data(contentsOf: url)
   
    

} catch _ {
print("Error: (data: contentsOf: url)")
data = nil
}

// 2
var jsonObject: Any? = nil
if let data = data {
  do {
   jsonObject = try JSONSerialization.jsonObject(with: data)
  } catch _ {
    jsonObject = nil
  }


// 3
if let jsonObject = jsonObject as? [String: Any],
// 4
let jsonData = JSONValue.fromObject(jsonObject)?["data"]?.array {
  for artworkJSON in jsonData {
    if let artworkJSON = artworkJSON.array,
    // 5
    let artwork = Artwork.fromJSON(artworkJSON) {
      self.networks.append(artwork)
    }
  }
}

}

}
}

Look at the sample project of NSURLSession Tutorial: func searchBarSearchButtonClicked and the func updateSearchResults that it calls.

You might also need to look at our JSON tutorial, because your JSON data will probably be different from PublicArt.json

Hi @audrey Where can I find the Xcode 8 version of this project? I donā€™t want to use Xcode 9 yet and am trying to follow the tutorial but am stuck at MKMarkerAnnotationView since that is not in Xcode 8.

Please advise. Thank you!

Hi Ernie: hereā€™s a copy of the tutorial and projects from before this last update to Xcode 9 beta:

MapKitTutorial_Xcode8.zip (1.6 MB)

Hi Audrey - would you have any examples where MKMapviewdelegate methods are held in a separate swift file / class, so that map views in different view controllers can call the same methods? Or is this a stupid idea? best regards AC.

hi AC: the delegate methods are usually implemented in an extension of the view controller. I suppose you could create a delegate class ā€” a singleton? ā€” that all the view controllers access.

but I take it, it is not common to do so? The background to my question is this, If you have one app, multiple viewcontrollers with a mapview on each (for different purposes) I would need one ā€˜draw the map pinā€™-method for each mapview, right? Lazy as I am, I thought (with my limited experience) I could consolidate this into using one such method for all map views. But I have abandoned it for now :slight_smile: Thanks for your tutorial, I consult it many times. /AC

actually, it could work, to create a mapViewService class ā€¦ setting up the map view doesnā€™t often interact with the host view controllerā€™s outlets? making the view controller the mapViewā€™s delegate is more convenient if the delegate methods have to get/set values of view controller properties. Otherwise, a separate class could work well, and reduce code duplication.

Hello! Can you help me please. I add phone number in subtitles in annotation. How I can make when user tap on phone number starting call. Or when user tap on URL link safari open.

sorry Nikita, this is beyond my expertise.

see if this helps:

you can create a UITextView for view.detailCalloutAccessoryView instead of a UILabel, then try Paul Hudsonā€™s example.

the url for a phone number is ā€œtel://ā€ + the number, and you call UIApplication.shared.open