I'm looking at the Ray Wenderlich tutorial http://www.raywenderlich.com/90971/introduction-mapkit-swift-tutorial and he is using there this function:
class func fromJSON(json: [JSONValue]) -> Artwork? {
// 1
var title: String
if let titleOrNil = json[16].string {
title = titleOrNil
} else {
title = ""
}
let locationName = json[12].string
let discipline = json[15].string
// 2
let latitude = (json[18].string! as NSString).doubleValue
let longitude = (json[19].string! as NSString).doubleValue
let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
// 3
return Artwork(title: title, locationName: locationName!, discipline: discipline!, coordinate: coordinate)
}
Since I'm using SwiftyJSON in my project I would like to stay with that, so I thought about rewriting this function based on that.
If I understand correctly, this function takes one json node and creates Artwork
object from it.
So how can I refer to a single json node with SwiftyJSON?
I tried doing:
class func fromJSON(JSON_: (data: dataFromNetworking))->Artwork?{
}
but it causes error use of undeclared type dataFromNetworking
. On the other hand that's exactly how they use it in the documentation https://github.com/SwiftyJSON/SwiftyJSON
Could you help me with rewriting it?
My suggestion: separate the model layer
from the presentation layer
.
First of all you need a way to represent the data. A struct is perfect for this.
struct ArtworkModel {
let title: String
let locationName: String
let discipline: String
let coordinate: CLLocationCoordinate2D
init?(json:JSON) {
guard let
locationName = json[12].string,
discipline = json[15].string,
latitudeString = json[18].string,
latitude = Double(latitudeString),
longitueString = json[19].string,
longitude = Double(longitueString) else { return nil }
self.title = json[16].string ?? ""
self.locationName = locationName
self.discipline = discipline
self.coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
}
}
As you can see ArtworkModel is capable to initialize itself from a json.
Now the Artwork
(conform to MKAnnotation
) becomes much easier.
class Artwork: NSObject, MKAnnotation {
private let artworkModel: ArtworkModel
init(artworkModel: ArtworkModel) {
self.artworkModel = artworkModel
super.init()
}
var title: String? { return artworkModel.title }
var subtitle: String? { return artworkModel.locationName }
var coordinate: CLLocationCoordinate2D { return artworkModel.coordinate }
}
You function now becomes
class func fromJSON(json: JSON) -> Artwork? {
guard let model = ArtworkModel(json: json) else { return nil }
return Artwork(artworkModel: model)
}
To use SwiftyJSON
in this project first you have to change the method to retrieve the data from the property list file.
Note: This replacement is for Swift 2.
Replace the method loadInitialData()
in ViewController
with
func loadInitialData() {
do {
let fileName = NSBundle.mainBundle().pathForResource("PublicArt", ofType: "json")
let data = try NSData(contentsOfFile: fileName!, options: NSDataReadingOptions())
let jsonObject = JSON(data:data)
if let jsonData = jsonObject["data"].array {
for artworkJSON in jsonData {
if let artworkJSONArray = artworkJSON.array, artwork = Artwork.fromJSON(artworkJSONArray) {
artworks.append(artwork)
}
}
}
} catch let error as NSError {
print(error)
}
}
And then just exchange [JSONValue]
in the method
class func fromJSON(json: [JSONValue]) -> Artwork? {
of the Artwork
class with [JSON]
, so it's now
class func fromJSON(json: [JSON]) -> Artwork? {
That's it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With