1

新しいTLIndexPathTools ライブラリを使用して、動的な iOS テーブル ビューを作成しています。具体的には、TLIndexPathTreeItem クラスを使用して、階層的なドロップダウン テーブル構造を構築します。

「アウトライン」の例から、葉ノードから親ノードまで、階層全体を静的に生成する必要があるようです。

//setup item heirarchy for data model
TLIndexPathTreeItem *item111 = [self itemWithId:ITEM_1_1_1 level:2 children:nil];
TLIndexPathTreeItem *item112 = [self itemWithId:ITEM_1_1_2 level:2 children:nil];
TLIndexPathTreeItem *item11 = [self itemWithId:ITEM_1_1  level:1 children:@[item111, item112]];
TLIndexPathTreeItem *item121 = [self itemWithId:ITEM_1_2_1 level:2 children:nil];
TLIndexPathTreeItem *item12 = [self itemWithId:ITEM_1_2 level:1 children:@[item121]];
TLIndexPathTreeItem *item1 = [self itemWithId:ITEM_1 level:0 children:@[item11, item12]];
TLIndexPathTreeItem *item211 = [self itemWithId:ITEM_2_1_1 level:2 children:nil];
TLIndexPathTreeItem *item221 = [self itemWithId:ITEM_2_2_1 level:3 children:nil];
TLIndexPathTreeItem *item212 = [self itemWithId:ITEM_2_1_2 level:2 children:@[item221]];
TLIndexPathTreeItem *item21 = [self itemWithId:ITEM_2_1 level:1 children:@[item211, item212]];
TLIndexPathTreeItem *item2 = [self itemWithId:ITEM_2 level:0 children:@[item21]];

ただし、約 1,000 行のデータがあり、各リーフまで 2 ~ 4 レベルです。タップされたときに各ドロップダウンを動的に設定する方法はありますか? それ以外の場合は、ツリー構造全体をメモリにロードするために巨大な再帰データベース呼び出しとその他のハッカーが必要であり、例に示すようにリーフから親に静的に設定します。

4

1 に答える 1

2

子ノードの遅延読み込みのサポートを追加し、Outline サンプル プロジェクトを更新して、同期読み込みと非同期読み込みの両方を示しました。

最初に注意すべきことは、 を持つノードはchildItems == nilリーフとして扱われるため、View Controller はそれらを展開したり折りたたんだりしようとしないということです。したがって、ノードを遅延ロードする場合は、子アイテムを空の配列に設定する必要があります。

同期ロード用に次のwillChangeNodeデリゲート メソッドが追加されました。

- (TLIndexPathTreeItem *)controller:(TLTreeTableViewController *)controller willChangeNode:(TLIndexPathTreeItem *)treeItem collapsed:(BOOL)collapsed; 

子を含む新しいアイテムを返すだけで、既存のアイテムが置き換えられます。新しいアイテムを作成する最も簡単な方法は、次の便利なメソッドを使用することです。

TLIndexPathTreeItem *newTreeItem = [treeItem copyWithChildren:newChildren];

didChangeNode非同期ロードの場合、デリゲート メソッドでフェッチを開始し、

[self setNewVersionOfItem:newTreeItem];

フェッチの完了ハンドラーのメイン スレッド (selfTLTreeTableViewController):

編集サーバーからデータを取得する場合など、非同期の遅延読み込みについて詳しく説明するには、次のようにします。

- (void)controller:(TLTreeTableViewController *)controller didChangeNode:(TLIndexPathTreeItem *)treeItem collapsed:(BOOL)collapsed
{
    //the logic here checks that the node is being opened. Note that this will cause the
    //node to refresh every time it's expanded. If we only want to load children once,
    //we need to keep track of which nodes have been loaded (or maybe just check
    //that there are no child items yet: [treeItem.childItmes count] == 0).
    if (collapsed == NO) {

        //the next steps is to initiate a data fetch. So the hypothetical method
        //`fetchChildDataFromServerForItem` would execute the appropriate fetch for
        //the given item (to identify the item, one would typically look at the
        //`treeItem.identifier` property or maybe some information that has been placed
        //in `treeItem.data`.
        [self fetchChildDataFromServerForItem:treeItem completion:^(BOOL success, NSArray *result){

            //The fetch method would presumably have a completion block, where the result
            //data would be inserted into the tree.

            if (success && [result count] > 0) {

                //we build up an array of child items by looping over the result set. for arguments
                //sake, assume the result items are dictionaries (e.g. JSON data). They could just
                //as well be Core Data objects, strings, etc.
                NSMutableArray *childItems = [NSMutableArray arrayWithCapacity:result.count];
                for (NSDictionary *data in result) {
                    //TLIndexPathTools relies on items being identifiable, so we need to determine
                    //an appropriate identifier for our data. It could be the data object itself if it
                    //has a suitable `isEqual` method, such as with `NSString`. For a Core Data object,
                    //we would use the `objectID`. But for our dictionary items, we'll assume the
                    //dictionary contains a `recordId`.
                    NSString *identifier = [data valueForKey:@"recordId"];
                    //now we wrap our data in a tree item and add it to the array
                    TLIndexPathTreeItem *childItem = [[TLIndexPathTreeItem alloc] initWithIdentifier:identifier sectionName:nil cellIdentifier:@"CellIdForThisLevel" data:data andChildItems:nil];
                    [childItems addObject:childItem];
                }
                //now we generate a new new node by copying the existing node, but providing a new set of children
                TLIndexPathTreeItem *newTreeItem = [treeItem copyWithChildren:childItems];
                //and finally ask the view controller to set our new tree item, which will cause the new
                //child items to appear in the table.
                [self setNewVersionOfItem:newTreeItem];

            } else {

                //perhaps if the fetch fails to return any items, we set the child items to nil
                //to indicate to the controller that this is a leaf node.
                TLIndexPathTreeItem *newTreeItem = [treeItem copyWithChildren:nil];
                [self setNewVersionOfItem:newTreeItem];

            }
        }];
    }
}
于 2013-07-19T03:33:58.107 に答える