0

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?

1 Answer 1

1

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.. :)

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your alternative suggestion. I did have an alternative solution in mind, similar, but I'm removing NSManaged from the test2:Test2 property in Test and using getters and setters on it. Then I'm creating a Dictionary which is NSManaged, that the getter and setter works through. Obviously this is a bit of a hack solution and I was hoping to find a solution where objects could be nested. (I assume as you were giving an alternative solution that you either believe nested objects in parse either isn't possible, or you aren't aware of how this could be possible) Thanks anyway for your help

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.