gpt4 book ai didi

ios - 保存 PFObject NSCoding

转载 作者:技术小花猫 更新时间:2023-10-29 11:07:35 25 4
gpt4 key购买 nike

我的问题:saveInBackground 不工作。

它不起作用的原因:我正在使用 NSKeyedArchiving 将存储在 NSArray 中的 PFObjects 保存到文件中。我这样做的方法是通过这个 library 实现 NSCoding .由于某种我不知道的原因,正在添加其他几个字段并将其设置为 NULL。我有一种感觉,这会搞砸对 saveInBackground 的 API 调用。当我在第一组对象上调用 saveInBackground 时(在 NSKeyedArchiving 之前)saveInBackground 工作得很好。但是,当我在第二个对象上调用它时(在 NSKeyedArchiving 之后)它不会保存。这是为什么?

保存

[NSKeyedArchiver archiveRootObject:_myArray toFile:[self returnFilePathForType:@"myArray"]];

检索

_myArray = (NSMutableArray *)[NSKeyedUnarchiver unarchiveObjectWithFile:
[self returnFilePathForType:@"myArray"]];

NSArchiving 之前的对象

2014-04-16 16:34:56.267 myApp[339:60b]
<UserToMessage:bXHfPM8sDs:(null)> {
from = "<PFUser:sdjfa;lfj>";
messageText = "<MessageText:asdffafs>";
read = 0;
to = "<PFUser:asdfadfd>";
}
2014-04-16 16:34:56.841 myApp[339:60b]
<UserToMessage:bXHsdafdfs:(null)> {
from = "<PFUser:eIasdffoF3gi>";
messageText = "<MessageText:asdffafs>";
read = 1;
to = "<PFUser:63sdafdf5>";
}

NSArchiving 后的对象

<UserToMessage:92GGasdffVQLa:(null)> {
ACL = "<null>";
createdAt = "<null>";
from = "<PFUser:eIQsadffF3gi>";
localId = "<null>";
messageText = "<MessageText:EudsaffdHpc>";
objectId = "<null>";
parseClassName = "<null>";
read = 0;
saveDelegate = "<null>";
to = "<PFUser:63spasdfsxNp5>";
updatedAt = "<null>";
}

2014-04-16 16:37:46.527 myApp[352:60b]
<UserToMessage:92GadfQLa:(null)> {
ACL = "<null>";
createdAt = "<null>";
from = "<PFUser:eIQsadffF3gi>";
localId = "<null>";
messageText = "<MessageText:EuTndasHpc>";
objectId = "<null>";
parseClassName = "<null>";
read = 1;
saveDelegate = "<null>";
to = "<PFUser:63spPsadffp5>";
updatedAt = "<null>";
}

使用 Florent 的 PFObject 类别更新:

PFObject+MyPFObject_NSCoding.h

#import <Parse/Parse.h>

@interface PFObject (MyPFObject_NSCoding)

-(void) encodeWithCoder:(NSCoder *) encoder;
-(id) initWithCoder:(NSCoder *) aDecoder;
@end

@interface PFACL (extensions)
-(void) encodeWithCoder:(NSCoder *) encoder;
-(id) initWithCoder:(NSCoder *) aDecoder;
@end


PFObject+MyPFObject_NSCoding.m

#import "PFObject+MyPFObject_NSCoding.h"
@implementation PFObject (MyPFObject_NSCoding)
#pragma mark - NSCoding compliance
#define kPFObjectAllKeys @"___PFObjectAllKeys"
#define kPFObjectClassName @"___PFObjectClassName"
#define kPFObjectObjectId @"___PFObjectId"
#define kPFACLPermissions @"permissionsById"
-(void) encodeWithCoder:(NSCoder *) encoder{

// Encode first className, objectId and All Keys
[encoder encodeObject:[self className] forKey:kPFObjectClassName];
[encoder encodeObject:[self objectId] forKey:kPFObjectObjectId];
[encoder encodeObject:[self allKeys] forKey:kPFObjectAllKeys];
for (NSString * key in [self allKeys]) {
[encoder encodeObject:self[key] forKey:key];
}


}
-(id) initWithCoder:(NSCoder *) aDecoder{

// Decode the className and objectId
NSString * aClassName = [aDecoder decodeObjectForKey:kPFObjectClassName];
NSString * anObjectId = [aDecoder decodeObjectForKey:kPFObjectObjectId];


// Init the object
self = [PFObject objectWithoutDataWithClassName:aClassName objectId:anObjectId];

if (self) {
NSArray * allKeys = [aDecoder decodeObjectForKey:kPFObjectAllKeys];
for (NSString * key in allKeys) {
id obj = [aDecoder decodeObjectForKey:key];
if (obj) {
self[key] = obj;
}

}
}
return self;
}
@end

最佳答案

您获得所有 "<null>" 的原因NSArchiving 之后的条目是因为您使用的 NSCoding 库处理 nil Parse 属性的方式。特别是,在 2 月 18 日的一次提交中,对 nil 的处理发生了一些变化,包括删除了几个检查属性是否为 nil 的测试,以及在解码中添加了以下代码:

    //Deserialize each nil Parse property with NSNull
//This is to prevent an NSInternalConsistencyException when trying to access them in the future
for (NSString* key in [self dynamicProperties]) {
if (![allKeys containsObject:key]) {
self[key] = [NSNull null];
}
}

我建议您使用替代的 NSCoding 库。

@AaronBrager 在 4 月 22 日的回答中建议了一个替代库。

更新:

由于替代库缺少对 PFFile 的支持,下面是为 PFFile 实现 NSCoding 所需的更改的类别实现。只需编译并添加 PFFile+NSCoding.m到你的项目。此实现来自您使用的原始 NSCoding 库。

PFFile+NSCoding.h

//
// PFFile+NSCoding.h
// UpdateZen
//
// Created by Martin Rybak on 2/3/14.
// Copyright (c) 2014 UpdateZen. All rights reserved.
//

#import <Parse/Parse.h>

@interface PFFile (NSCoding)

- (void)encodeWithCoder:(NSCoder*)encoder;
- (id)initWithCoder:(NSCoder*)aDecoder;

@end

PFFile+NSCoding.m

//
// PFFile+NSCoding.m
// UpdateZen
//
// Created by Martin Rybak on 2/3/14.
// Copyright (c) 2014 UpdateZen. All rights reserved.
//

#import "PFFile+NSCoding.h"
#import <objc/runtime.h>

#define kPFFileName @"_name"
#define kPFFileIvars @"ivars"
#define kPFFileData @"data"

@implementation PFFile (NSCoding)

- (void)encodeWithCoder:(NSCoder*)encoder
{
[encoder encodeObject:self.name forKey:kPFFileName];
[encoder encodeObject:[self ivars] forKey:kPFFileIvars];
if (self.isDataAvailable) {
[encoder encodeObject:[self getData] forKey:kPFFileData];
}
}

- (id)initWithCoder:(NSCoder*)aDecoder
{
NSString* name = [aDecoder decodeObjectForKey:kPFFileName];
NSDictionary* ivars = [aDecoder decodeObjectForKey:kPFFileIvars];
NSData* data = [aDecoder decodeObjectForKey:kPFFileData];

self = [PFFile fileWithName:name data:data];
if (self) {
for (NSString* key in [ivars allKeys]) {
[self setValue:ivars[key] forKey:key];
}
}
return self;
}

- (NSDictionary *)ivars
{
NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];
unsigned int outCount;

Ivar* ivars = class_copyIvarList([self class], &outCount);
for (int i = 0; i < outCount; i++){
Ivar ivar = ivars[i];
NSString* ivarNameString = [NSString stringWithUTF8String:ivar_getName(ivar)];
NSValue* value = [self valueForKey:ivarNameString];
if (value) {
[dict setValue:value forKey:ivarNameString];
}
}

free(ivars);
return dict;
}

@end

第二次更新:

我描述的更新解决方案(使用 Florent's PFObject / PFACL encoders 的组合替换 classNameparseClassName 加上 Martin Rybak's PFFile encoder )确实有效 - 在下面的测试工具中(见下面的代码)第二次调用 saveInBackgroundNSKeyedUnarchiver 恢复后调用确实有效.

- (void)viewDidLoad {
[super viewDidLoad];

PFObject *testObject = [PFObject objectWithClassName:@"TestObject"];
testObject[@"foo1"] = @"bar1";
[testObject saveInBackground];

BOOL success = [NSKeyedArchiver archiveRootObject:testObject toFile:[self returnFilePathForType:@"testObject"]];
NSLog(@"Test object after archive (%@): %@", (success ? @"succeeded" : @"failed"), testObject);

testObject = [NSKeyedUnarchiver unarchiveObjectWithFile:[self returnFilePathForType:@"testObject"]];
NSLog(@"Test object after restore: %@", testObject);

// Change the object
testObject[@"foo1"] = @"bar2";
[testObject saveInBackground];
}

- (NSString *)returnFilePathForType:(NSString *)param {
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filePath = [docDir stringByAppendingPathComponent:[param stringByAppendingString:@".dat"]];

return filePath;
}

但是,查看 Parse 服务器,第二次调用 saveInBackground已创建对象的新版本。

即使这超出了原始问题的范围,我也会看看是否有可能鼓励 Parse 服务器重新保存原始对象。同时请投票和/或接受答案,因为它解决了使用 saveInBackground 的问题。在 NSKeyedArchiving 之后.

最终更新:

这个问题原来只是一个时间问题 - 当 NSKeyedArchiver 发生时第一次 saveInBackground 还没有完成 - 因此在归档时 objectId 仍然是 nil,因此在第二次 saveInBackground 时它仍然是一个新对象.使用一个 block (类似于下面)来检测何时保存完成并且可以调用 NSKeyedArchiver 也可以工作

以下版本不会导致保存第二个副本:

- (void)viewDidLoad {
[super viewDidLoad];

__block PFObject *testObject = [PFObject objectWithClassName:@"TestObject"];
testObject[@"foo1"] = @"bar1";
[testObject saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (succeeded) {
BOOL success = [NSKeyedArchiver archiveRootObject:testObject toFile:[self returnFilePathForType:@"testObject"]];
NSLog(@"Test object after archive (%@): %@", (success ? @"succeeded" : @"failed"), testObject);

testObject = [NSKeyedUnarchiver unarchiveObjectWithFile:[self returnFilePathForType:@"testObject"]];
NSLog(@"Test object after restore: %@", testObject);

// Change the object
testObject[@"foo1"] = @"bar2";
[testObject saveInBackground];
}
} ];

}

关于ios - 保存 PFObject NSCoding,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23119739/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com