Reputation: 5852
I have copied the Parse Swift example for Subclassing:
class Armor : PFObject, PFSubclassing {
override class func load() {
self.registerSubclass()
}
class func parseClassName() -> String! {
return "Armor"
}
}
I get the following errors:
/Parse/Armor.swift:11:1: error: type 'Armor' does not conform to protocol 'PFSubclassing'
class Armor : PFObject, PFSubclassing {
^
__ObjC.PFSubclassing:15:28: note: protocol requires function 'object()' with type '() -> Self!'
@objc(object) class func object() -> Self!
^
__ObjC.PFSubclassing:23:52: note: protocol requires function 'objectWithoutDataWithObjectId' with type '(String!) -> Self!'
@objc(objectWithoutDataWithObjectId:) class func objectWithoutDataWithObjectId(objectId: String!) -> Self!
^
__ObjC.PFSubclassing:30:27: note: protocol requires function 'query()' with type '() -> PFQuery!'
@objc(query) class func query() -> PFQuery!
^
__ObjC.PFSubclassing:35:38: note: protocol requires function 'registerSubclass()' with type '() -> Void'
@objc(registerSubclass) class func registerSubclass()
^
/Parse/Armor.swift:14:9: error: 'Armor.Type' does not have a member named 'registerSubclass'
self.registerSubclass()
^ ~~~~~~~~~~~~~~~~
I saw this answer: https://stackoverflow.com/a/24899411/843151 and tried that solution with no luck, I get the same errors.
Any suggestions of why this is happening? Thanks in advance.
Upvotes: 3
Views: 3119
Reputation: 6993
I got deadlocks / hangs using override class func initialize
- even though that's recommended in the parse documentation.
Thinking about it, it's not a good idea to do threading in the init methods of classes - you never know when or in what context these might get called.
This worked for me - for all my custom subclasses, before I call the parse init methods, I explicitly register them as subclasses.
This way the order in which things get called is well defined. Also, it works for me ;)
MyPFObjectSubclass.registerSubclass()
MyPFObjectSubclass2.registerSubclass()
MyPFObjectSubclass3.registerSubclass()
// etc...
let configuration = ParseClientConfiguration {
$0.applicationId = "fooBar"
$0.server = "http://localhost:1337/parse"
}
Parse.initializeWithConfiguration(configuration)
Upvotes: 0
Reputation: 8739
It appears that PFSubclassing does not currently work correctly in Swift as is, as of v1.7.2, released April 27, 2015.
I was able to get it working by implementing custom getters and setters for properties as a temporary workaround--which somewhat defeats the purpose, but at least this approach will result in only minor refactoring once PFSubclassing is made ready for Swift.
It is not necessary to add #import <Parse/PFObject+Subclass.h>
to the bridging header. But, as indicated in the PFSubclassing Protocol Reference, "Warning: This method must be called before [Parse setApplicationId:clientKey:]
," you should register all PFObject custom subclasses before calling Parse.setApplicationId(_:, clientKey:)
.
Here's an example for a custom PFObject subclass called PFChatLOCMessage:
// In ProjectName-Bridging-Header.h
#import <Parse/Parse.h>
// In AppDelegate.swift
@UIApplicationMain
final class AppDelegate: UIResponder, UIApplicationDelegate {
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
configureParse()
return true
}
func configureParse() {
registerParseSubclasses()
Parse.setApplicationId("...", clientKey: "...")
}
func registerParseSubclasses() {
PFChatLOCMessage.registerSubclass()
}
}
// In PFChatLOCMessage.swift
private let PFChatLOCMessageClassName = "PFChatLOCMessage"
private let userKey = "user"
class PFChatLOCMessage: PFObject {
var user: PFUser! {
get { return self[userKey] as! PFUser }
set { self[userKey] = newValue }
}
override init() {
super.init()
}
override init(user: PFUser) {
super.init()
self.user = user
}
}
extension PFChatLOCMessage: PFSubclassing {
class func parseClassName() -> String {
return PFChatLOCMessageClassName
}
}
Upvotes: 0
Reputation: 3628
Parse recommends initialize() instead of load()
class Armor : PFObject, PFSubclassing {
override class func initialize() {
var onceToken : dispatch_once_t = 0;
dispatch_once(&onceToken) {
self.registerSubclass()
}
}
static func parseClassName() -> String! {
return "Armor"
}
}
Upvotes: 2
Reputation: 3287
With xCode 6.1.1 I was able to get this working without the bridging header. Just:
import Parse
at the top of the module. For the class declaration I did need to use @NSManaged for the variable types to get them to link to the Parse class variables successfully. Like this:
class PSCategory : PFObject, PFSubclassing {
override class func load() {
self.registerSubclass()
}
class func parseClassName() -> String! {
return "Category"
}
@NSManaged var Name: String
}
Then in my query all the names are dynamically linked:
var query = PSCategory.query() // PFQuery(className: "Category")
query.cachePolicy = kPFCachePolicyCacheElseNetwork // kPFCachePolicyNetworkElseCache
query.maxCacheAge = 60 * 60 * 24 // One day, in seconds.
query.findObjectsInBackgroundWithBlock {
(categories: [AnyObject]!, error: NSError!) -> Void in
if error == nil {
for abstractCategory in categories {
let category = abstractCategory as PSCategory
NSLog("Category Name: %@", category.Name)
}
} else {
NSLog("Unable to retrieve categories from local cache or network")
}
}
Upvotes: 3
Reputation: 5852
I needed to import the parse PFObject+Subclass.h in my Objective-C bridging header
#import <Parse/PFObject+Subclass.h>
Upvotes: 12