web-dev-qa-db-ja.com

NSRangeを使用してNSArrayのサブアレイを作成する方法は?

コンテンツを含む配列があります。通常どおり、20個のオブジェクトが含まれています。 Tableviewで同じ配列を2つのセクションに分割したい。現在の配列でNSMakeを使用して実装しようとしています。たとえば、最初のテーブルビューセクションで3行取得する必要があり、2番目には残りのすべて(17行)が含まれます。

switch (section) {
        case 0:
            return
            [[array subarrayWithRange:NSMakeRange(3, 8)] count];
            // in this line, it always takes from the first object in array, despite I told hime start from 3 (If I understand right, how to works NSMakeRange)
            break;
        case 1:
            return
            [[array subarrayWithRange:NSMakeRange(9, 19)] count];
            // here my app is crashing with an error 
            //*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSArray subarrayWithRange:]: range {9, 19} extends beyond bounds [0 .. 19]'
        default:
            break;
    }

誰かがそれを手伝ってくれる?

21
Anton

NSMakeRange(startingIndex, length)ではなく(start, end)として定義されています。

したがって、最初の3つのオブジェクトが必要な場合、残りは次のようになります。

switch (section) {
    case 0:
        // This returns objects 0-2 in the array
        return [array subarrayWithRange:NSMakeRange(0, 3)];
    case 1:
        // This returns objects 3-20 in the array
        return [array subarrayWithRange:NSMakeRange(3, 17)];
    default:
        break;
}

編集:コメントによると、実際にはセクションの行数で返されるカウントを探しています。固定数の行を使用しているため、caseステートメント内で実際の数を返すことができます。

switch (section) {
    case 0:
        // This returns the count for objects 0-2 in the array
        return 3;
    case 1:
        // This returns the count for objects 3-20 in the array
        return 17;
    default:
        break;
}

実際には[subarrayWithRange]NSMakeRangeを使用する必要はありません。ある時点で実際の配列を参照する必要がある場合は、配列からオブジェクトを取得するために使用できるNSIndexPathオブジェクトを取得します。セクションと行のプロパティを使用する必要があります。

編集:NSRange-> NSMakeRange

59
Joel Fischer

他の人がNSRangeを不適切に使用していると述べているように。

定義は

typedef struct _NSRange {
      NSUInteger location;
      NSUInteger length;
} NSRange;

したがって、構造体の2番目のパラメーターは範囲の長さであり、見たところの最後の要素の場所ではありません。


そうは言っても、あなたがやっていることは、本来あるべきよりもはるかに複雑です。

既知の長さのサブ配列を作成し、サブ配列自体の長さを返す目的は何ですか?これを考慮して:

return [[array subarrayWithRange:NSMakeRange(3, 8)] count];

(正しくNSRangeを使用)

return [[array subarrayWithRange:NSMakeRange(3, 6)] count];

しかし、実際には

return 6;

または範囲の長さがパラメータの場合

return length;

ここでも、配列をスライスしてカウントする必要はありません。長さは事前にわかっています。


したがって、UITableViewDataSourceのコンテキストでは、

  • 各セクションの数を-tableView:numberOfRowsInSection:に返します。何かのようなもの

    switch(section) {
        case 0: return 2;
        case 1: return 18;
    }    
    
  • 実際のオブジェクトをtableView:cellForRowAtIndexPath:に返します。何かのようなもの

    id object = nil;
    switch (indexPath.section) {
        case 0:
            object = self.objects[indexPath.row];
            break;
        case 1:
            object = self.objects[2 + indexPath.row];
            break;
    }
    ...
    

追加のヒントとして、構造体の構築に別の表記法を使用することをお勧めします

NSMakeRange(0, 42)

書くことができます

(NSRange){ .location = 0, .length = 42 }

これは非常に読みやすくなっています(特に、パラメータの意味に疑問がある場合は、エラーが発生しにくくなります)。

でも

(NSRange){ 0, 42 }

許容範囲です。 NSMakeRangeよりは良い(そして短い)と思いますが、利点や読みやすさが失われます。

5

問題は解決しました

私のFetcherクラスでは

_sectionOne = [news objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 3)]];
_sectionTwo = [news objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(3, 17)]];

その後

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 2;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    switch (section) {
        case 0:
            return [_sectionOne count];
            break;
        case 1:
            return [_sectionTwo count];
            break;
        default:
            break;
    }
    return 0;
}

次に、メソッドcellForRowAtIndexPathで:

 switch (indexPath.section) {
        case 0:
            item = [_sectionOne objectAtIndex:indexPath.row];
            break;
        case 1:
            item = [_sectionTwo objectAtIndex:indexPath.row];
            break;
        default:
            break;
    }

アイテム-MVCを使用したNSObjectです

だからそれは私が望んだように働いています:)

助けてくれてありがとう。

乾杯

1
Anton