With the help of some great tutorials and users here, I've had success implementing SwiftyJSON in my app and getting a basic WatchKit app built alongside. My last hurdle to pass is getting my whole set of parsed JSON data to be passed to WatchKit, as to allow me to choose from a cell in a TableView and pull up more specific detail on a piece of criteria.
I'm parsing JSON data in my Minion.swift file, like so;
import UIKit
class Minion {
var name: String?
var age: String?
var height: String?
var weight: String?
class func fetchMinionData() -> [Minion] {
let dataURL = NSURL(string: "http://myurl/json/")
var dataError: NSError?
let data = NSData(contentsOfURL: dataURL!, options: NSDataReadingOptions.DataReadingMappedIfSafe, error: &dataError)
let minionJSON = JSONValue(data)
var minions = [Minion]()
for minionDictionary in minionJSON {
minions.append(Minion(minionDetails: minionDictionary))
}
return minions
}
init(minionDetails: JSONValue) {
name = minionDetails["san"].string
age = minionDetails["age"].string
height = minionDetails["height"].string
weight = minionDetails["free"].string
}
}
For my iOS app, this is working well to populate my UITableView and subsequent Detail View. I have my ViewController.Swift like so;
import UIKit
class ViewController: UITableViewController {
let minions: [Minion]
required init(coder aDecoder: NSCoder!) {
minions = Minion.fetchMinionData()
super.init(coder: aDecoder)
}
override func viewDidLoad() {
super.viewDidLoad()
let defaults = NSUserDefaults(suiteName: "group.com.mygroup.data")
let key = "dashboardData"
defaults?.setObject(minions, forKey: key)
defaults?.synchronize()
}
// MARK: Table view data source
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
}
I've truncated much of the code as I don't believe it's relevant to WatchKit. In the WatchKit extension, I have my InterfaceController.swift like so;
import WatchKit
class InterfaceController: WKInterfaceController {
@IBOutlet weak var minionTable: WKInterfaceTable!
let defaults = NSUserDefaults(suiteName: "group.com.mygroup.data")
var dashboardData: String? {
defaults?.synchronize()
return defaults?.stringForKey("dashboardData")
}
let minions = ???
When I run the iOS app, it throws me the error "Property list invalid for format: 200 (property lists cannot contain objects of type 'CFType')" because I am passing the whole set of JSON data as "minions." If I set my NSUserDefaults key to "minions[0].name" it will pass the single string, but passing the whole set of data so the WatchKit table can allow me to choose a row seems to be evading me.
In advance, as always, I am most grateful.
Your Minion
class need to implement the NSCoding
. Then in your view controller you need to transfer your Minion
object to NSData
object.
class Minion: NSObject, NSCoding {
.....
init(coder aDecoder: NSCoder!) {
aCoder.encodeObject(name, forKey: "name")
aCoder.encodeObject(age, forKey: "age")
aCoder.encodeObject(height, forKey: "height")
aCoder.encodeObject(weight, forKey: "weight")
}
func encodeWithCoder(aCoder: NSCoder) {
name = aDecoder.decodeObjectForKey("name") as String
age = aDecoder.decodeObjectForKey("age") as String
height = aDecoder.decodeObjectForKey("height") as String
weight = aDecoder.decodeObjectForKey("weight") as String
}
}
In your ViewController class:
NSKeyedArchiver.setClassName("Minion", forClass: Minion.self)
defaults?.setObject(NSKeyedArchiver.archivedDataWithRootObject(minions), forKey: "minions")
If you want to retrieve the data from NSUserDefaults
:
if let data = defaults?.objectForKey("minions") as? NSData {
NSKeyedUnarchiver.setClass(Minion.self, forClassName: "Minion")
let minions = NSKeyedUnarchiver.unarchiveObjectWithData(data) as! [Minion]
}