Reputation: 28094
I have an existing model class which I would like to manage with Parse, ideally by changing its superclass from NSObject to PFObject. But this is a real-world model class, designed without Parse in mind, so it presents a number of challenges.
The challenges are:
Every one of these things seems to require special treatment to be handled correctly in Parse, and Parse’s documentation is brief on these issues.
To give an example, my class is something like this:
// I’d like to change this to be a PFUser subclass.
class User : NSObject { /* an ordinary user object */ }
// And this to be a PFObject subclass
class Tango : NSObject {
var user:User // Presumably, a Parse "Pointer" to a PFUser
var opponent:Participant
var info:NSString?
var watchers:NSArray // an array of Participants
var duration:NSTimeInterval? // (notice this is an optional value type, in accessible from Objc)
// various methods
}
// a custom class which contains a User
class Participant : NSObject
{
var status:String
var user:User // a Pointer to a PFUser?
// etc..
}
So I have a few key questions here:
Pointer
s to User
a subclass of PFUser
?Optional<NSTimeInterval>
? Or is this another case where there’s an extension point to provide inter-conversion with a data type Parse can handle?Tango
, would I be wiser just to implement a method for converting an instance to/from plain old plist types (dictionaries, arrays, strings, numbers), and have a PFObject handle those?I am not interested in maximal query flexibility or maximal performance. I am interested in the quickest thing which can work reliably, and which requires the minimum re-writing of existing code that depends on the existing class hierarchy. I am aware that the User / Tango
relationship could be described as many-to-many, which is what PFRelation
is for, but I have the impression it would require a major redesign to use it.
In other words, I am really hoping I can avoid replacing my entire model layer with a new class hierarchy designed as denormalized tables for for Parse's pleasure. I have existing code which works with the current structure, and I am trying to fit in Parse without breaking anything already there.
So are these key questions the right ones to retrofit this class for Parse? What is the right way to handle them?
Upvotes: 2
Views: 1211
Reputation: 8662
My answer: Don't! It doesn't make sense to make your model classes dependent on a third-party backend provider.
Making model classes subclass Parse classes is a brittle design. If you want to switch from Parse to something else, you'll have to change your model classes again!
I'm looking at using Parse as a backend and I'm not planning to subclass. Instead I'll define a Data Access Layer protocol, with a Parse-based implementation, for getting data from/ sending data to the backend. That layer will handle converting things from PFObjects et cetera to my model objects and vice versa storing data in, and retrieving data from, Parse.
UPDATE: I asked one of the Parse iOS SDK developers about this and he suggested using the Parse REST API for this approach, since creating and destroying PFObjects is memory-intensive. He also pointed out that switching backend providers is pretty rare - which is true in my experience.
I suppose this removes some of the benefit of using Parse, but that's a tradeoff I'm willing to make. It still allows me to avoid writing server code. In your case this design might be less work since it will isolate the changes.
Upvotes: 1
Reputation: 3725
You should definitely check out the subclassing guide. A few things to note that are particularly important for your use case:
User : PFUser
) then you only need to register that subclass. All the constructor methods return instancetype
so you can call them on User and you'll get an actual User back. Similarly, any query for a Parse user class will return results deserialized as your type.PFObject
for your own types, you must also implement +parseClassName
. This maps your class to the name you want to see in the data browser. This name must be consistent across all languages to make sure you're talking to the same data.PFObject
subclassing library was written to only implement @dynamic
properties. If you @static
it or define the method then PFObject leaves it alone. If you have an ivar with the same name, the property isn't saved to Parse, but we will instead create an accessor/mutator pair that respects the PFObject
's internal lock that we take when merging in server data or preparing a save operation.PFObject
can handle properties of any JSON serializable primitive, pointers to other PFObject
subtypes, arrays/dictionaries thereof, and PFRelation
pointers. I haven't played with Swift yet, so I don't know how it's going to interact with optional properties; I assume they're NSNumbers under the covers and PFObject
handles NSNumbers as well as primitives (which are auto-boxed/unboxed).
// Note: +initialize is Objective-C's only non-polymorphic function; every class
// must implement this directly.
+(void) initialize {
[self registerSubclass];
}
Upvotes: 2
Reputation: 905
There is a similar question on Google Groups, although I must say your question is more complex.
We know that in Swift you have to declare you properties as @NSManaged public var
.
Step two would be to figure out if you can setup relationships with the built-in Users (PFUsers).
Please give us your complete solution when you find the answers to all your questions.
See the following link for step 1 : Here
Additional Info:
I have constructed my own PFObject. I have found that when I call saveInBackgroundWithBlock
the block is never excecuted, although the object is actually save sucessfully. My PFObject FYI
public class PatientRemote: PFObject, PFSubclassing {
public override class func load() {
self.registerSubclass()
}
public class func parseClassName() -> String! {
return "Patient"
}
@NSManaged public var firstname : NSString
@NSManaged public var lastname : NSString
@NSManaged public var birth : NSDate
@NSManaged public var idnumber : NSString
@NSManaged public var gender : NSString
@NSManaged public var fileNumber : NSString
@NSManaged public var patientPicture : NSString
@NSManaged public var medicalAid: NSString
@NSManaged public var option: NSString
@NSManaged public var mainMember: NSString
@NSManaged public var membershipNo: NSString
@NSManaged public var dependant: NSString
@NSManaged public var address1: NSString
@NSManaged public var address2: NSString
@NSManaged public var address3: NSString
@NSManaged public var address4: NSString
@NSManaged public var postalCode: NSString
@NSManaged public var workNumber: NSString
@NSManaged public var cellNumber: NSString
@NSManaged public var localId: NSString
}
Upvotes: 1