Ios 序列化包含核心数据中NSManagedObject引用的多维数组
我有两个实体,Ios 序列化包含核心数据中NSManagedObject引用的多维数组,ios,iphone,objective-c,core-data,nscoding,Ios,Iphone,Objective C,Core Data,Nscoding,我有两个实体,Chain和Step链具有一个属性步骤,该属性可能是步骤实体的多维数组,例如: [ step, step, step, [ step, step ], step ] 每个步骤对象都有一个作为字符串的内容属性 如果我使用的是关系数据库,我只需将该数组存储为JSON,每个步骤都是特定步骤的步骤id 我如何在核心数据中实现类似的功能?我推测我需要使步骤类符合NSCoding协议,但是那会是什么样子呢?如何使其仅在Chain.steps的最终值中存
Chain
和Step
<代码>链具有一个属性步骤
,该属性可能是步骤实体的多维数组,例如:
[
step,
step,
step,
[
step,
step
],
step
]
每个步骤
对象都有一个作为字符串的内容
属性
如果我使用的是关系数据库,我只需将该数组存储为JSON,每个步骤都是特定步骤的步骤id
我如何在核心数据中实现类似的功能?我推测我需要使步骤
类符合NSCoding协议,但是那会是什么样子呢?如何使其仅在Chain.steps的最终值中存储其id
的等价物,即对自身的引用
编辑
下面的一条评论建议我在步骤
和其他步骤
之间包含一对多关系(我们称之为nextStep
)。然后,我将使用此关系在链
中从一个步骤转到下一个步骤,因此链
实体只需要包含序列中的第一个步骤
。这个问题是,<代码>步骤可能属于不止一个<代码>链< /代码>,因此它可能并不总是具有相同的<代码> NEXSTEP> <代码>值。 < P>请考虑使用<代码> CordDATA < /C>关系,因此链将与多个关系到步骤实体,哪一个将具有向后的类型关系到一个到链实体。这个如何?链与步骤实体之间存在一对多关系(例如stepsOfChain>chainOfStep),步骤与自身之间也存在一对多关系(例如stepsOfStep>stepOfStep)。后面的关系打开了在stepsOfChain字段的一个条目中存储多个步骤的可能性
我的大致想法是,您需要创建一个NSData类型的属性,该属性反序列化为NSManagedObjectID或更多数组的一组NSArray,以实现您所说的多维数组结构。
诚然,这是一个快速的想法,必然会有边缘案例和其他问题,使一个工具(CoreData)做一些它不是构建来做的事情
“祝你好运!” 我不鼓励您序列化和反序列化包含核心数据对象的数组。您可以将数组转换为保存步骤的对象ID的URIRepresentation
,但如果从数据库中删除步骤,会发生什么情况?序列化的数组仍然受到旧对象的污染
这是我的建议
我的模型设置如下:
Link
是一个抽象实体
为了便于使用,我定义了以下协议:
@protocol Link <NSObject>
//This is to make chain traversal easy - all links are guaranteed to have "steps".
- (NSOrderedSet*)steps;
@end
最后是遍历:
for(Chain* chain in chains)
{
NSLog(@"<chain %@>", chain.name);
for(id<Link> link in chain.links)
{
NSLog(@"\t<step>");
for(Step* step in link.steps)
{
NSLog(@"\t\t%@", step.content);
}
NSLog(@"\t</step>");
}
NSLog(@"</chain>\n\n");
}
用于(链*链中链)
{
NSLog(@“”,chain.name);
for(chain.links中的id链接)
{
NSLog(@“\t”);
用于(步骤*链接中的步骤)
{
NSLog(@“\t\t%@”,步骤内容);
}
NSLog(@“\t”);
}
NSLog(@“\n\n”);
}
这允许您创建一个可管理的对象图,当任务被删除时,它将自动重建自身
这是一个简单的例子。它只解决了一个层次的问题。你可以在SingleStepLink
或MultiStepLink
和Link
(而不是Step
)之间建立一种无限深度的关系,在这种情况下,叶子与Step
具有最终的关系,我建议你有一个如下的模式。
StepArray是一个Abstract实体
根据您的问题陈述,链可以包含步骤对象的二维数组。一个步骤可以包含在多个链对象中
我的解决方案->
您希望步骤关系同时包含单个步骤对象和步骤对象数组。
我不是像二维数组那样存储,而是将单个存储对象存储为步骤,将步骤数组存储为步骤数组。两者都是对多关系
链对象与步骤对象具有多对多关系。因此,这意味着您可以向其中添加任意多个单独的步骤对象。由于步骤对象可以位于多个链对象中,因此我们习惯于从步骤到链的许多链关系
一个StepArray对象有许多名为steps和Step对象的关系。所以,那些在数组中的Step对象,我希望它们用steps关系存储在StepArray中
任何步骤数组都是唯一的,因此我们必须使用一个名为chain的关系和chain实体。在我看来,一个链可以同时包含步骤和其他链(假设一个链只是步骤的集合)。这样说公平吗
如果是这种情况,那么您可以将共享的抽象实体作为父实体,然后将链定义为与抽象实体具有多对多关系,因此可以是步骤或链(包含步骤)
当然,该模型是否有效可能取决于您需要如何与数据交互。简单回答:
@Leo Natan给出:您可以为链接到链的步骤
的每个步骤
构建一个多维的表示数组
此解决方案很难维护(无自动级联等)。
问题:
使用CoreData framework表示多维数组…
没有简单的实现,因为CoreData是一个对象图持久层,而您需要一个具有严格顺序且可能包含节点重复的数据结构。
此外,您必须定义这种数据结构的用途,以便实现和优化表示以支持特定功能。
我的建议:
自从你
Step* step1 = [Step newObjectInContext:context];
step1.content = @"Wake up";
Step* step2_1 = [Step newObjectInContext:context];
step2_1.content = @"Go to school";
Step* step2_2 = [Step newObjectInContext:context];
step2_2.content = @"Learn new things";
Step* step3 = [Step newObjectInContext:context];
step3.content = @"Go to sleep";
NSOrderedSet* links = [NSOrderedSet orderedSetWithObjects:[Link linkWithStep:step1 inContext:context], [Link linkWithStepsArray:@[step2_1, step2_2] inContext:context], [Link linkWithStep:step3 inContext:context], nil];
[chain setLinks:links];
for(Chain* chain in chains)
{
NSLog(@"<chain %@>", chain.name);
for(id<Link> link in chain.links)
{
NSLog(@"\t<step>");
for(Step* step in link.steps)
{
NSLog(@"\t\t%@", step.content);
}
NSLog(@"\t</step>");
}
NSLog(@"</chain>\n\n");
}
//byte order correction
NSUInteger flipNSUInteger(NSUInteger input) {
uint8_t* buff = (uint8_t*)(&input);
uint8_t tmp;
size_t size = sizeof(input);
for (NSUInteger i = 0; i < size/2; ++i) {
tmp = buff[i];
buff[i] = buff[size-i-1];
buff[size-i-1] = tmp;
}
return input;
}
- (void) setIndexPath:(NSIndexPath*)indexPath
{
NSIndexPath* currentIndexPath = [self indexPath];
if ( currentIndexPath==nil ||
[currentIndexPath compare:indexPath] != NSOrderedSame)
{
[self willChangeValueForKey:@"indexPath"];
if (indexPath) {
NSUInteger* bytes = (NSUInteger*)malloc([indexPath length]*sizeof(NSUInteger));
[indexPath getIndexes:bytes];
for (NSUInteger i = 0; i < indexPath.length; ++i) {
bytes[i] = flipNSUInteger(bytes[i]);
}
self.binaryIndexPath = [NSData dataWithBytesNoCopy:bytes
length:[indexPath length]*sizeof(NSUInteger)];
} else {
self.binaryIndexPath = nil;
}
[self setPrimitiveValue:indexPath forKey:@"indexPath"];
[self didChangeValueForKey:@"indexPath"];
}
}
NSFetchRequest* r = [NSFetchRequest fetchRequestWithEntityName:@"StepPlaceholder"];
r.predicate = [NSPredicate predicateWithFormat:@"chain = %@",self.objectID];
r.relationshipKeyPathsForPrefetching = @[@"step"];
r.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"binaryIndexPath"
ascending:YES]];
static char const* const virtual_last_index_key = "virtual_last_index";
@interface NSArray (lastvirtualindex)
@property (nonatomic,assign) NSUInteger virtualLastIndex;
@end
@implementation NSArray (lastvirtualindex)
- (NSUInteger) virtualLastIndex
{
return [objc_getAssociatedObject(self, virtual_last_index_key) unsignedIntegerValue];
}
- (void) setVirtualLastIndex:(NSUInteger)virtualLastIndex
{
objc_setAssociatedObject(self, virtual_last_index_key, @(virtualLastIndex),OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
+ (NSArray*) buildMultiDimArrayWithSortedPlaceholders:(NSArray*)placeholders
{
NSMutableArray* map = [NSMutableArray new];
for (StepPlaceholder* placeholder in placeholders) {
NSMutableArray* currentMap = map;
NSUInteger i = 0;
NSUInteger length = [placeholder.binaryIndexPath length]/(sizeof(NSUInteger));
const NSUInteger* indexes = [placeholder.binaryIndexPath bytes];
for (;i < length-1; ++i) {
if ([currentMap count] &&
currentMap.virtualLastIndex == indexes[i] &&
[[currentMap lastObject] isKindOfClass:[Step class]])
{
return nil;
} else if ([currentMap count] == 0 || currentMap.virtualLastIndex != indexes[i]) {
[currentMap addObject:[NSMutableArray new]];
}
currentMap.virtualLastIndex = indexes[i];
currentMap = currentMap.lastObject;
}
[currentMap addObject:[placeholder step]];
currentMap.virtualLastIndex = indexes[i];
}
return map;
}