我有一个名为MediaFile的PFObject子类。为了从调用服务器中获取子类的实例,我已经看到了如何从Parse子类构造查询,如下所示:
PFQuery *query = [MediaFile query];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) { ... }];
但是,我的应用程序中的大多数服务器调用都是自定义云调用,它返回PFObjects。一旦我检索了这些对象,我就想将它们视为MediaFile对象,并在它们上调用MediaFile类中定义的自定义方法。转换不起作用,因为它实际上并不构造MediaFile对象。我为克服这个问题所做的是为我使用[MediaFile object]
取回的每个PFObject构建新的MediaFiles,然后使用我编写的名为loadFromObject:
的方法将所有数据复制到每个PFObject中:
[PFCloud callFunctionInBackground:@"func" withParameters:@{} block:^(id objects, NSError *error) {
for (PFObject *object in objects) {
MediaFile *mf = [[MediaFile object] loadFromObject:object];
[array addObject:mf];
}
}];
在MediaFile.m中:
- (MediaFile *) loadFromObject:(PFObject *)object {
NSArray *keys = [object allKeys];
for (NSString *key in keys) {
id obj = [object objectForKey:key];
[self setObject:obj forKey:key];
}
return self;
}
这样可行,但是有更优雅的方法可以解决这个问题吗?
答案 0 :(得分:1)
您的自定义类是如何定义的? 因为它们的子类化机制依赖于键值编码(KVC)。 这是KVC Programming Guide。或者您可以查看here上的指南。
以下示例应该有效。
在标题中:
@interface CustomObject : PFObject <PFSubclassing>
@property (nonatomic, strong) NSString *propertyName;
在实施中:
#import <Parse/PFObject+Subclass.h>
#pragma mark - columns of Parse table
@dynamic propertyName;
#pragma mark - regiester parse subclass in runtime
+ (void)load {
@autoreleasepool {
[self registerSubclass];
}
}
#pragma mark - parse cloud table name
+ (NSString *)parseClassName
{
return @"CustomObject"; // table name
}
答案 1 :(得分:1)
<强> TL; DR:强>
当您的Cloud代码从网络调用中返回这些对象时,请确保您的子类PFObject
已在Parse注册。
如果您使用the instructions Parse includes in it's documentation guide对PFObject
进行了子类化,则可以在第一次返回自定义子类的网络调用之前进行以下调用:
CustomSubclass.initialize()
添加此代码的好地方是在您的app delegate的application(didFinishLaunchingWithOptions:)
方法中,它可能会在与您的子类相关的任何其他代码之前运行。
带解释的长版本
我的情况与你的情况略有不同,但我认为问题基本相同。我的问题是我通过PFQuery
获取对象,查询回调中返回的对象只是通用的PFObject
。
以下是我的代码:
// Scene is a PFObject subclass
func getLatestScenes(completion: ((scenes: [Scene]) -> Void)?) {
var query = PFQuery(className: SceneClassName)
query.findObjectsInBackgroundWithBlock { (results: [AnyObject]?, error: NSError?) -> Void in
if let scenes = results as? [Scene] {
// This would never run, as the members of `results` were only PFObjects
completion?(scenes: scenes)
} else {
// Code would always skip to the empty result case
completion?(scenes: [])
}
}
}
results
数组的各个成员将在调试器中打印出来,其中的描述清楚地表明它们应该按照预期属于Scene
类,但在检查时它们只是{{ 1}} S上。
PFObject
这里的问题是(lldb) po results![0]
<Scene: 0x7fc743a8f310, objectId: YyxYH9dtBp, localId: (null)> {
creator = "<PFUser: 0x7fc74144b320, objectId: FV3cmDI1PW>";
sceneDataFile = "<PFFile: 0x7fc743a96920>";
}
(lldb) p results![0]
(PFObject) $R6 = 0x00007fc743a8f310 {
NSObject = {
isa = 0x00007fc743a8f310
}
...
// Info on object...
...
}
对象没有在Parse中正确注册为Scene
子类。 PFObject
方法被正确覆盖,如下所示:
initialize
但是在调用查询时没有调用override class func initialize() {
struct Static {
static var onceToken : dispatch_once_t = 0;
}
dispatch_once(&Static.onceToken) {
self.registerSubclass()
}
}
函数。问题是在第一个消息发送到该类之前调用了类的initalize
方法,但在执行查询之前没有消息发送到initialize
。将以下行添加到AppDelegate的Scene
解决了问题
application(didFinishLaunchingWithOptions:)
之后,Parse能够在客户端上推断出对象应该是哪个类,并使用该类构造结果数组。
答案 2 :(得分:0)
毕竟它很简单。对我有用的是将返回的PFObject
简单地分配给PFObject
的Objective-C子类。所以在你的情况下,
[PFCloud callFunctionInBackground:@"func" withParameters:@{} block:^(id objects, NSError *error) {
for (PFObject *object in objects) {
MediaFile *mf = object; // simple as that
[array addObject:mf];
}
}];