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;
}