我已经在我的显示器上敲了好几个星期,在休息一下后绕过我的问题,我发现我再次遇到同样的问题。
首先,我能找到与我的问题最接近的事情: NSCoding / Realm in Google Groups
我试图在我的一些Realm Model对象上使用NSCoding协议,以便将它们变成标准的NSData对象,我可以在我的项目正在使用的几个框架中进行转换。但是,我收到了一些奇怪的错误,我根本无法找到解决方法,而且我只是没有足够的经验来处理。
我使用的是简单的NSKeyedArchiver,特别是archivedDataWithRootObject。编码过程看起来非常顺利,直到我可以将其二进制blob作为NSData传输而没有问题 - 字节为字节,编码的大小是解码器端接收到的。我的模型定义如下:
//
// CSTaskRealmModel.m
// CommSync
//
// Created by Ivan Lugo on 1/27/15.
// Copyright (c) 2015 AppsByDLI. All rights reserved.
//
#import "CSTaskRealmModel.h"
@implementation CSTaskRealmModel
#pragma mark - Realm modeling protocol
+ (NSDictionary *)defaultPropertyValues {
NSDictionary* defaults = nil;
defaults = @{@"taskDescription":@"",
@"taskTitle":@"",
@"taskPriority":[NSNumber numberWithInt:0],
@"UUID":@"",
@"deviceID":@"",
@"concatenatedID":@"",
@"assignedID":@"",
@"tag":@"",
@"completed":@false
};
return defaults;
}
+ (NSArray*)ignoredProperties {
return @[@"TRANSIENT_audioDataURL"];
}
+ (NSString*)primaryKey {
return @"concatenatedID";
}
#pragma mark - NSCoding Compliance
- (id) initWithCoder:(NSCoder *)aDecoder {
if(self = [super init]) {
self.UUID = [aDecoder decodeObjectForKey:kUUID];
self.deviceID = [aDecoder decodeObjectForKey:kDeviceId];
self.concatenatedID = [aDecoder decodeObjectForKey:kConcatenatedID];
self.assignedID = [aDecoder decodeObjectForKey:kAssignedID];
self.tag = [aDecoder decodeObjectForKey:kTag];
self.taskTitle = [aDecoder decodeObjectForKey:kTaskTitle];
self.taskDescription = [aDecoder decodeObjectForKey:kTaskDescription];
NSNumber* num = [aDecoder decodeObjectForKey:kCompleted];
self.completed = [num boolValue];
num = [aDecoder decodeObjectForKey:kTaskPriority];
self.taskPriority = [num integerValue];
NSMutableArray* dataArray = [aDecoder decodeObjectForKey:kRevisionDataArray];
for(CSTaskRevisionRealmModel* rev in dataArray) {
[self.revisions addObject:rev];
}
dataArray = [aDecoder decodeObjectForKey:kMediaDataArray];
for(CSTaskMediaRealmModel* media in dataArray) {
[self.taskMedia addObject:media];
}
dataArray = [aDecoder decodeObjectForKey:kCommentsDataArray];
for (CSCommentRealmModel* comment in dataArray) {
[self.comments addObject:comment];
}
}
return self;
}
- (void) encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:_UUID forKey:kUUID];
[aCoder encodeObject:_deviceID forKey:kDeviceId];
[aCoder encodeObject:_concatenatedID forKey:kConcatenatedID];
[aCoder encodeObject:_assignedID forKey:kAssignedID];
[aCoder encodeObject:_tag forKey:kTag];
[aCoder encodeObject: [NSNumber numberWithBool:_completed] forKey:kCompleted];
[aCoder encodeObject: _taskTitle forKey:kTaskTitle];
[aCoder encodeObject:_taskDescription forKey:kTaskDescription];
[aCoder encodeObject:[NSNumber numberWithInteger:_taskPriority] forKey:kTaskPriority];
NSMutableArray* revArray = [NSMutableArray arrayWithCapacity:_revisions.count];
for (CSTaskRevisionRealmModel* rev in self.revisions) {
[revArray addObject:rev];
}
[aCoder encodeObject:revArray forKey:kRevisionDataArray];
NSMutableArray* mediaArray = [NSMutableArray arrayWithCapacity:_taskMedia.count];
for (CSTaskMediaRealmModel* media in self.taskMedia) {
[mediaArray addObject:media];
}
[aCoder encodeObject:mediaArray forKey:kMediaDataArray];
NSMutableArray* commentsArray = [NSMutableArray arrayWithCapacity:_comments.count];
for (CSCommentRealmModel* comment in self.comments) {
[commentsArray addObject:comment];
}
[aCoder encodeObject:commentsArray forKey:kCommentsDataArray];
}
@end
然而,当对象在解码时,在这些非常无害的线路上......
NSData* taskData = [NSData dataWithContentsOfURL:localURL];
id newTask = [NSKeyedUnarchiver unarchiveObjectWithData:taskData];
// Where 'localURL' is just an on-disk location of the data object a device has received.
我收到此错误;它出现在Realm源代码的RLMAccessor。:
中*** Terminating app due to uncaught exception 'RLMException', reason: 'Object has been deleted or invalidated.'
在我看来,好像在模型的init方法中发生了非常非常奇怪的事情,我无法做出正面或反面。在某些情况下,如果我删除主键(尝试绕过失效),错误将更改为(在同一源文件中):
'Primary key can't be changed after an object is inserted.'
我根本无法弄清楚这里发生了什么!这是踢球者:我的原始实现,在我设法为其添加一些属性之前,完美地工作:
//
// CSTaskRealmModel.m
// CommSync
//
// Created by Ivan Lugo on 1/27/15.
// Copyright (c) 2015 AppsByDLI. All rights reserved.
//
#import "CSTaskRealmModel.h"
@implementation CSTaskRealmModel
#pragma mark - Lifecycle
- (id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super init]) {
self.UUID = [aDecoder decodeObjectForKey:@"UUID"];
self.deviceID = [aDecoder decodeObjectForKey:@"deviceID"];
self.concatenatedID = [aDecoder decodeObjectForKey:@"concatenatedID"];
self.taskTitle = [aDecoder decodeObjectForKey:@"taskTitle"];
self.taskDescription = [aDecoder decodeObjectForKey:@"taskDescripion"];
self.taskPriority = [aDecoder decodeIntForKey:@"taskPriority"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:self.UUID forKey:@"UUID"];
[aCoder encodeObject:self.deviceID forKey:@"deviceID"];
[aCoder encodeObject:self.concatenatedID forKey:@"concatenatedID"];
[aCoder encodeObject:self.taskTitle forKey:@"taskTitle"];
[aCoder encodeObject:self.taskDescription forKey:@"taskDescripion"];
[aCoder encodeInteger:self.taskPriority forKey:@"taskPriority"];
// NOTE!
// This is ALL KINDS OF EXTREMELY INEFFICIENT!
// We should not rearchive and reconvert images we have already worked with
NSMutableArray* tempArrayOfImages = [NSMutableArray arrayWithCapacity:self.TRANSIENT_taskImages.count];
for(UIImage* image in self.TRANSIENT_taskImages) { // for every TRANSIENT UIImage we have on this task
NSData* thisImage = UIImageJPEGRepresentation(image, 0.3); // make a new JPEG data object with some compressed size
[tempArrayOfImages addObject:thisImage]; // add it to our container
}
NSData* archivedImages = [NSKeyedArchiver archivedDataWithRootObject:tempArrayOfImages]; // archive the data ...
[[RLMRealm defaultRealm] beginWriteTransaction];
self.taskImages_NSDataArray_JPEG = archivedImages; // and set the images of this task to the new archive
[[RLMRealm defaultRealm] commitWriteTransaction];
[aCoder encodeObject:self.taskImages_NSDataArray_JPEG forKey:@"taskImages"]; // encode the object and pray
}
+ (NSArray*)ignoredProperties {
return @[@"TRANSIENT_taskImages"];
}
请注意,我能看到的唯一重要区别是原始实现上没有primaryKey对象。我能想到的唯一能做错的事情是:(a)我从根本上对我的NSCoding线做错了,或者我甚至不应该对这些域对象进行NS编码,或者(b)某种其他方式,其他一些我的代码区域正在执行某些来验证Realm对象,然后将它打包并以NSData的形式发送出来。
我无法正确表达(现在是凌晨2点,发布时间......)我对您对此有任何见解或帮助表示感谢。如果您想要更多的代码上下文,我很乐意发布它,或者指向我的git存储库的方向。
答案 0 :(得分:2)
看起来有点休息,需要更加巧妙的调试来破解这个。我欢迎对此答案进行任何更正,或者更深入的信息!
事实证明,访问Realm对象并不 实际上获取领域模型对象本身 - 或者至少不是NSCoding
协议所期望的方式。在调试过程中,我发现未归档的类最终为RLMAccessor_[myClassName]
。在预感中,我决定尝试别的东西。
我不是仅仅抓住我对编码感兴趣的领域对象,而是实例化一个全新的模型,并从感兴趣的模型中为其分配所有关键属性。然后,没有将它添加到领域,通过该行发送编码版本。事实证明,这非常有效。
出于某种原因,我还没有完全理解,那个返回的领域访问器使它从中提取数据的对象无效,这意味着它不能被重用。
我的方法可能不是最有效的,也可能不是Realm的做法,但它似乎符合我的需要:一个可以充当瞬态和持久对象的Realm模型对象。