Reputation: 2995
I am attempting to store data in the local data store using parse.com(1.7.3) in Swift iOS. Following the parse.com docs here, I am able to subclass PFObject to store a simple object. However I am hoping to compose a custom object inside this object and am finding difficulties in doing this.
I have stripped this problem back to its most basic and include my code below. Basically I am storing a PFObject subclass called 'Test', which will store a String(testString), and a custom object called Test2. Test2 in turn will also store a String(testString). I assume that Test2 also needs to subclass PFObject.
Test - testString(String)
- test2(Test2)
- testString(String)
AppDelegate.swift
(Registering subclass in AppDelegate instead of Initialise method - see here for more details.)
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
Test.registerSubclass()
Test2.registerSubclass()
Parse.enableLocalDatastore()
Parse.setApplicationId("...", clientKey: "...")
}
Test2.swift
class Test2:PFObject, PFSubclassing {
@NSManaged var testString:String
static func parseClassName() -> String {
return "Test2"
}
}
Test.swift
class Test:PFObject, PFSubclassing {
@NSManaged var testString:String
@NSManaged var test2:Test2
static func parseClassName() -> String {
return "Test"
}
}
ViewController.swift
override func viewDidLoad() {
saveTest() //toggle between save and load, don't do both!
//loadTest()
}
func saveTest() {
var test2 = Test2()
test2.testString = "I am Test 2"
var test = Test()
test.testString = "I am Test"
test.test2 = test2
test.pinInBackground()
}
func loadTest() {
let query = PFQuery(className:Test.parseClassName())
query.fromLocalDatastore()
query.findObjectsInBackgroundWithBlock({
(objects:[AnyObject]?, error: NSError?) in
if let error = error {
println("THERE WAS AN ERROR")
// There was an error
} else {
if let objects = objects as? [PFObject] {
for object in objects {
//We have an object!
println("We have a PFObject, now to cast as Test")
if let object = object as? Test {
println(object)
}
}
}
}
})
}
So the println in loadTest outputs the following in the console:
<Test: 0x7ff2da75e810, objectId: new, localId: local_15a085d00030543f> {
test2 = "<Test2: 0x7ff2db90fe50, objectId: new>";
testString = "I am Test";
}
If I try to access the test2 property or a property of test2, the app hangs. I also am not able to 'fetch' the Test object. Curiously If I load any Test2 objects stored locally(identical to the loadTest method above with any mention of Test replaced with Test2), I do find the Test2 object:
<Test2: 0x7f94b1f1e850, objectId: new, localId: (null)> {
testString = "I am Test 2";
}
So in pinning the test object, test2 is being pinned too. However the test2 object is not connecting to the test object for some reason.
I'm starting to get lost, and can't seem to find relevant(or accurate) documentation or sample projects which would probably clear all this up in a second... What is the best approach(if any) to compose a custom object inside a PFObject subclass?
Upvotes: 0
Views: 1349
Reputation: 676
Here's an idea which can help you in this case. Your Test class is a subclass of PFObject. And you have a custom object inside Test class, named Test2.
In your Test2.swift file, create a method that would return an NSDictionary object containing all properties of its object. Somewhat similar to this :
class func objDetail() -> NSDictionary {
return [
"key1": self.property1,
"key2": self.property2,
// ...
] as NSDictionary
}
And you could use this dictionary to store your object details as an object in your Test object. Now, parse supports dictionary and you've converted it in dictionary. It would save the object.
Now add another method in your swift file to create object based on dictionary values.
convenience init(_ dictionary: Dictionary<String, AnyObject>) {
self.init()
title = dictionary["title"] as? NSString
shortDescription = dictionary["shortDescription"] as? NSString
newsDescription = dictionary["newsDescription"] as? NSString
link = dictionary["link"] as? NSURL
}
For retrieving object, in your loadTest method's query.findObjectsInBackgroundWithBlock call this object's init method and create object with values of dictionary you get from parse.
Hope, my idea helps you.. :)
Upvotes: 1