CoreData,递归结构......我想

时间:2013-06-20 18:17:15

标签: ios uitableview core-data

并感谢您的期待...

我甚至不确定如何说出这个问题,更不用说寻找答案了......老实说,我已经尝试过,所以需要所有的帮助!

这可能非常简单,因为我确信这是一种始终发生的模式:

我的模型(MainLevel *)中有一个与自身有关系的实体。

该实体适用于法律层面,唯一的要求是每项法律至少有一个(最高层)。除此之外,从技术上讲,子级别的数量是无限的(但实际上通常约为5,最多可能不超过8-10)。正如所料,每个子级别只有一个父级(MainLevel.parentLevel),任何父级都可以有多个(或零)子级(NSSet * childLevels)。

我想要做的是将此关系的所有结构放入UITableView或collectionView。

我有一个递归函数如下:

- (NSDictionary *)getStructureOfLawForLevel:(MainLevel *)level
{
    NSMutableDictionary *mutableDict = [[NSMutableDictionary alloc]initWithCapacity:50];
    MainLevel *currentLevel = level;
    [mutableDict setObject:currentLevel.shortName forKey:@"name"];
    if (level.childLevels) {
        NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"order" ascending:YES];
        NSArray *sortdescriptors = @[sortDescriptor];
        NSArray *children = [currentLevel.childLevels sortedArrayUsingDescriptors:sortdescriptors];
        for (MainLevel *childLevel in children)
        {
            NSDictionary *dict = [self getStructureOfLawForLevel:childLevel];
            [mutableDict setObject:dict forKey:@"sublevels"];
        }
    }
    return [mutableDict copy];
}

然后在viewWillAppear:我有这个:

self.structure = [self getStructureOfLawForLevel:self.selectedLevel]

有了这个,我希望我在正确的方面......(由于我现在正在排序的另一个问题未经测试)。

我仍然无法弄清楚如何配置UITableViewUICollectionView。我的意思是我确信我可以通过添加一个或两个计数器并以这种方式获得行数和节数来实现。它看似简单,过于复杂,我确信必须有一个更明显的方法,我只是没有看到......

数据的唯一标准是它必须按实体实例的.order属性排序,并且不是唯一的。我的意思是,例如,每个childLevel都可以有一个订单号为1的childLevel。它是父级别的订单。

很抱歉,如果这被问了一千次。我试图寻找一个答案,但似乎没有什么可以影响我正在使用的搜索词。

我没有对这些数据做任何事情,除了屏幕,没有编辑,添加,删除......不确定这是否相关。

为了清晰起见而编辑

我不打算做一个向下钻取类型表视图。我想在一个视图中查看整个结构的快照,然后我可能需要向下钻取(使用与模型中其他实体的关系)。

为我的解决方案编辑

这是我最终做的......

- (NSArray *)getStructureAsArrayForLevel:(MainLevel *)child
{
    NSMutableArray *thisChildAndChildren = [[NSMutableArray alloc]initWithCapacity:2];
    [thisChildAndChildren addObject:child];
    if (child.childLevels)
    {
        // children exist
        // sort the children into order
        NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"order" ascending:YES];
        NSArray *sortdescriptors = @[sortDescriptor];
        NSArray *children = [child.childLevels sortedArrayUsingDescriptors:sortdescriptors];
        // get an array for each child via recursion
        for (MainLevel *child in children)
        {
            [thisChildAndChildren addObject:[self getStructureAsArrayForLevel:child]];
        }
    }
    return [thisChildAndChildren copy];
}

然后我使用类似的递归函数将数组转换为NSAttributedString并在textView中显示。

我真的不喜欢递归。我不知道为什么,但我觉得很难让SOOOOOOO了解逻辑,当它完成时它看起来很明显......去看看吧!

感谢大家的建议,帮助等...

5 个答案:

答案 0 :(得分:2)

如果您可以使用第三方控制器,请查看TLIndexPathTools。它处理树结构。例如,尝试运行Outline示例项目。

你的视图控制器看起来像这样(对它来说不多):

#import "TLTableViewController.h"
@interface TableViewController : TLTableViewController
@end

#import "TableViewController.h"
#import "TLIndexPathTreeItem.h"
@implementation TableViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    MainLevel *topLevel = nil;//get the top level object here
    TLIndexPathTreeItem *topItem = [self treeItemForLevel:topLevel depth:0];
    self.indexPathController.dataModel = [[TLTreeDataModel alloc] initWithTreeItems:@[topItem] collapsedNodeIdentifiers:nil];
}

- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
    // customize cell configuration here
    TLIndexPathTreeItem *item = [self.dataModel itemAtIndexPath:indexPath];
    MainLevel *level = item.data;
    cell.textLabel.text = [level description];
}

- (TLIndexPathTreeItem *)treeItemForLevel:(MainLevel *)level depth:(NSInteger)depth
{
    NSMutableArray *childItems = [NSMutableArray arrayWithCapacity:50];    
    NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"order" ascending:YES];
    NSArray *sortdescriptors = @[sortDescriptor];
    NSArray *children = [level.childLevels sortedArrayUsingDescriptors:sortdescriptors];
    for (MainLevel *child in children) {
        TLIndexPathTreeItem *childItem = [self treeItemForLevel:child depth:depth + 1];
        [childItems addObject:childItem];
    }
    //set identifier to some unique identifier, if one exists. Otherwise, the item itself
    //will be used as the identifier
    id identifier = nil;
    //set cell identifier based on depth. This can be set to something unique for each
    //depth, or set to a constant value. If nil, the value "Cell" is assumed.
    NSString *cellIdentifier = [NSString stringWithFormat:@"Cell%d", depth];
    //pass "level" to the data argument. Or pass any other data, e.g. include the depth @[@(depth), level]
    TLIndexPathTreeItem *item = [[TLIndexPathTreeItem alloc] initWithIdentifier:identifier sectionName:nil cellIdentifier:cellIdentifier data:level andChildItems:children];
    return item;
}

@end

如果您想要可折叠级别,则可以继承TLTreeTableViewController而不是TLTableViewController。如果您需要更多帮助,请告诉我。

答案 1 :(得分:1)

修改 对不起,我错过了那个想要一次显示所有内容的部分。基本上,我认为最简单的方法是基本上有一个递归结构来获取每个对象的描述。这可能是一个字符串,甚至是一个UIView,然后你可以把它放在你的tableviewcell里。

现在让我们坚持使用字典。每个字典表示都可以包含有关其自身及其子代的信息。模板可以是:

<LevelInfoDictionary>
    <NSObject>someObjectThatRepresentsInfoAboutThisLevel
    <NSArray>arrayOfInfoDictionariesThatRepresentChildren
</LevelInfoDictionary>

然后实现递归方法:

- (NSDictionary *)getLevelInfo
{
    NSMutableArray *childInfo = [NSMutableArray array];
    for(ClassName *child in self.children)
    {
         [childInfo addObject:[child getLevelInfo]];
    }
    return [NSDictionary dictionaryWithObjectsAndKeys:
                         <descriptionOfThisLevel>, @"CurrentLevel",
                         childInfo, @"children>, nil];

}

结束编辑 基本上,正如其他一些人所说,你应该创建一个显示所有顶级对象的tableview。从那里,在您选择一个对象之后,您应该被推送到一个新的tableview,它使用与谓词不同的获取请求,如:

 NSPredicate *predicate = [NSPredicate predicateWithFormat:@"parent = %@",
      selectedParentObject];

然后,您可以使用排序描述符对正在使用的NSFetchRequest进行排序。

或者,您可以通过使用父对象上的属性来获取子项,并将其存储在按排序描述符排序的数组中。

我要提到的另一件事是,目前排序描述符没有完成任何事情。您可能没有注意到这一点,因为您应该更改设计的其他部分,但由于NSDictionary没有订单(它是一个哈希表),因此在将对象放入字典之前对对象进行排序不会产生任何效果。

答案 2 :(得分:0)

从TableView或CollectionView的ViewController开始,您应该首先显示所有顶级对象(无父级)。从那里,当用户选择父对象成为当前级别的对象时,ViewController应刷新其数据源以显示该级别的所有子元素。然后,您可以通过后退按钮遍历到父级。

如果您需要更多详细信息,请与我们联系。

答案 3 :(得分:0)

你的循环没有意义,因为你想要一个孩子结构的词典列表,但你实际上每次都要覆盖它。你可能想要这样的东西:

NSMutableArray *subLevels = [NSMutableArray array];

for (MainLevel *childLevel in children)
{
    [subLevels addObject:[self getStructureOfLawForLevel:childLevel]];
}

[mutableDict setObject:subLevels forKey:@"sublevels"];

我想您希望在表视图中显示每个级别,并钻取到每个后续级别的另一个表视图。这应该是简单的,基于字典,它给你一个显示的名称和一个可选的数组,定义是否可以钻孔和传递给下一个视图控制器的数据。

答案 4 :(得分:0)

如果它帮助了其他人,这就是我最终做的......

- (NSArray *)getStructureAsArrayForLevel:(MainLevel *)child
{
    NSMutableArray *thisChildAndChildren = [[NSMutableArray alloc]initWithCapacity:2];
    [thisChildAndChildren addObject:child];
    if (child.childLevels)
    {
        // children exist
        // sort the children into order
        NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"order" ascending:YES];
        NSArray *sortdescriptors = @[sortDescriptor];
        NSArray *children = [child.childLevels sortedArrayUsingDescriptors:sortdescriptors];
        // get an array for each child via recursion
        for (MainLevel *child in children)
        {
            [thisChildAndChildren addObject:[self getStructureAsArrayForLevel:child]];
        }
    }
    return [thisChildAndChildren copy];
}

然后我使用类似的递归函数将数组转换为NSAttributedString并在textView中显示。

我真的不喜欢递归。我不知道为什么,但我觉得很难让SOOOOOOO了解逻辑,当它完成时它看起来很明显......去看看吧!

感谢大家的建议,帮助等...

修改

这不完全正确,因为第一层的结构与后面的结构略有不同。在某些时候我需要更改它以将顶级作为目录并使用第一级作为目录的键,然后将完整的数组添加为该键的对象。但它有效...我的大脑疼痛......我可以忍受它直到我改变它。