Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting the right type when subclassing PFUser

I am trying to subclass PFUser in Parse on iOS. I can create a subclass, using the following code:

// MyUser.h
#import <Parse/PFUser.h>
#import <Parse/PFObject+Subclass.h>
#import <Parse/PFFile.h>

@interface MyUser : PFUser<PFSubclassing>

@property PFFile *avatar;
...etc...

@end

// MyUser.m
#import "MyUser.h"

@implementation MyUser

@dynamic avatar;
...etc...

@end

When I call [MyUser currentUser], the object I get back is of type PFUser, but is not of type MyUser. Casting it to MyUser* does not help, it just throws the error "unrecognized selector sent to instance 0xce9c0c0" when I try to use any of the custom properties, e.g. user.avatar that is defined in MyUser.

How can I get the cached currentUser object of my custom type?

like image 398
tghw Avatar asked Mar 05 '14 16:03

tghw


2 Answers

The key turned out to be the ordering of registering subclasses and setting the application ID.

[Parse setApplicationId:@"FOO" clientKey:@"BAR"];
[MyUser registerSubclass];

Causes the problem to occur. However, if you set the application ID after registering subclasses, it works as expected.

[MyUser registerSubclass];
[Parse setApplicationId:@"FOO" clientKey:@"BAR"];
like image 67
tghw Avatar answered Sep 25 '22 18:09

tghw


When you create a new class in Parse, you control the name of that class. For example let's say you create a new class named "Armor."

When you create a subclass in Objective-C you're assigning the created Objective-C class to the Parse class. The code below is the implementation file for this Armor subclass. As you can see the Objective-C class name is "Armor" and the Parse class name is also "Armor."

#import "Armor.h"
#import <Parse/PFObject+Subclass.h>

@implementation Armor 
@dynamic displayName;
@dynamic rupees;
@dynamic fireproof;
+ (NSString *)parseClassName {
  return @"Armor";
}
@end

In this case, both the Objective-C class name and the Parse class name are the same. However, this doesn't have to be the case. If I were to change the name of my Objective-C class to "BrandonsAwesomeClass" this could still be assigned to the Parse "Armor" class. If I were to create a new instance of BrandonsAwesomeClass it would still return the Parse class type of "Armor"

#import "BrandonsAwesomeClass.h"
#import <Parse/PFObject+Subclass.h>

@implementation BrandonsAwesomeClass 
@dynamic displayName;
@dynamic rupees;
@dynamic fireproof;
+ (NSString *)parseClassName {
  return @"Armor";
}
@end

In your case the Parse User class is always named "_User" You can't change this name and it doesn't matter what the name of your Objective-C subclass is, it will always return PFUser as the class.

This won't really have much effect on your code or your project, because you can still add custom properties to the Parse "_User" class through the website and add the @dynamic properties to your Objective-C subclass.

As long as you set up your subclass correctly [MyUser currentUser].avatar is the same as accessing [[PFUser currentUser] objectForKey:@"avatar"]

I've linked to the Parse blog post explaining subclasses for reference.

http://blog.parse.com/2013/03/22/stay-classy-objective-c-introducing-native-subclasses-for-parse-objects/

like image 21
Brandon Schlenker Avatar answered Sep 23 '22 18:09

Brandon Schlenker