Subclassing PFObject in Swift

2019-01-14 07:19发布

The Parse documentation for adding properties and methods on PFObject subclasses conveniently skips the Swift syntax in their sample code listing just the Objective-C syntax:

https://parse.com/docs/ios_guide#subclasses-properties/iOS

// Armor.h
@interface Armor : PFObject<PFSubclassing>
+ (NSString *)parseClassName;
@property (retain) NSString *displayName;
@end

// Armor.m
@dynamic displayName;

Has anyone figured out a work around for Swift's lack of dynamic synthesizers in order to implement properties and methods with PFSubclassing? I want to be able to do something like:

class Armor : PFObject, PFSubclassing {
    class func parseClassName() -> String! {
        return "Armor"
    }
}

var armor = Armor()
armor.displayName = "Iron Clad"

5条回答
聊天终结者
2楼-- · 2019-01-14 07:39

I ran into the same issue, though I should note that your class definition should look more like this:

class Armor : PFObject, PFSubclassing {
    var displayName: String

    class func parseClassName() -> String! {
        return "Armor"
    }
}

var armor = Armor()
armor.displayName = "Iron Clad"

I tried a few different things without success. It doesn't look like the Parse SDK supports this yet, keep in mind that the current release of the Parse iOS SDK predates the swift announcement. Sounds like they're working on better swift support for an upcoming release though.

Instead, you can still create PFObject subclasses (as you did) and access data with .getObjectForKey("displayName"), or write your own class methods to access this data. The biggest missing piece is really just some convenience methods that the SDK usually creates for you.

查看更多
小情绪 Triste *
3楼-- · 2019-01-14 07:53

I had this same problem. Had to add @NSManaged to the properties I wanted saved:

class Armor : PFObject, PFSubclassing {
    @NSManaged var displayName: String

    class func parseClassName() -> String! {
        return "Armor"
    }
}

var armor = Armor.object()
armor.displayName = "Iron Clad"

Hopefully this is resolved in the next update.

查看更多
家丑人穷心不美
4楼-- · 2019-01-14 08:00

Prototypic is correct. As of right now it won't work with the dynamic attribute, but the code sample doesn't include the registerSubclass Parse recommends, so the code should include it like this:

class Armor : PFObject, PFSubclassing {
    @NSManaged var displayName: String

    override class func load() {
        self.registerSubclass()
    }
    class func parseClassName() -> String! {
        return "Armor"
    }
}

var armor = Armor.object()
armor.displayName = "Iron Clad"

(Note that "override" is required but missing from the Parse documentation.)

查看更多
倾城 Initia
5楼-- · 2019-01-14 08:04

Swift 1.2

First: Create a swift file and define the subclass. Don't forget to import Parse! (for example Armor)

import Foundation
import Parse


class Armor: PFObject, PFSubclassing {

    // MARK: - PFSubclassing

    override class func initialize() {
        struct Static {
            static var onceToken: dispatch_once_t = 0;
        }
        dispatch_once(&Static.onceToken) {
            self.registerSubclass()
        }
    }

    class func parseClassName() -> String {
        return "Armor"
    }


    // MARK: - Parse Core Properties

    @NSManaged var displayName: String?

}

Note: You can define your properties as optionals. Every "undefined" value inside the Parse Core Manager will be translated to "nil".

Second: Register all subclasses, inside your AppDelegate.swift.

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    // Override point for customization after application launch.

    // MARK: - Parse Setup
    Parse.setApplicationId("YOUR_ID", clientKey: "YOUR_KEY")

    // MARK: - Parse Register Subclasses
    Armor.registerSubclass()

    return true
}
查看更多
Rolldiameter
6楼-- · 2019-01-14 08:05

The solution is to use computed properties instead of stored properties:

class Armor : PFObject, PFSubclassing {

    var displayName: String? {
        get {
            return self["displayName"] as? String
        }
        set {
            self["displayName"] = newValue
        }
    }


    class func parseClassName() -> String {
        return "Armor"
    }
}
查看更多
登录 后发表回答