0

并感谢您的关注...

我什至不知道如何表达这个问题,更不用说寻找答案了......老实说,我已经尝试过了,所以需要所有帮助!

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

我的模型 (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]

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

我仍然无法弄清楚如何从中配置 aUITableView或 a UICollectionView。我的意思是我确信我可以通过添加一个或两个计数器并以这种方式获取行数和节数来做到这一点。它只是看起来方式,方式过于复杂,我确信一定有一个更明显的方法,我只是没有看到......

数据的唯一标准是它必须按.order实体实例的属性排序,并且不是唯一的。我的意思是,例如,每个 childLevel 可以有一个 order 编号为 1 的 childLevel。它是那个 parent level 中的 order。

对不起,如果这已经被问了一千次。我试图寻找答案,但似乎没有找到我正在使用的搜索词。

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

为清楚起见编辑...

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

编辑我的解决方案

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

- (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 中。

我真的不喜欢递归。我不知道为什么,但我发现我很难理解逻辑,当它完成时,它似乎很明显......去想一想!

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

4

5 回答 5

2

如果您可以使用第 3 方控制器,请查看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如果您需要更多帮助,请告诉我。

于 2013-06-20T19:08:13.247 回答
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 使用不同的 fetch 请求和谓词,例如:

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

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

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

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

于 2013-06-20T18:42:46.570 回答
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 中。

我真的不喜欢递归。我不知道为什么,但我发现我很难理解逻辑,当它完成时,它似乎很明显......去想一想!

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

编辑

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

于 2013-06-21T14:07:15.870 回答
0

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

如果您需要更多详细信息,请告诉我。

于 2013-06-20T18:23:35.607 回答
0

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

NSMutableArray *subLevels = [NSMutableArray array];

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

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

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

于 2013-06-20T18:24:54.687 回答