web-dev-qa-db-fra.com

Comment créer un sous-tableau de NSArray en utilisant NSRange?

J'ai un tableau avec du contenu. comme d'habitude, il contient 20 objets. Je veux que le même tableau soit divisé en 2 sections dans Tableview. J'essaie de l'implémenter avec NSMake dans le tableau actuel. Par exemple, j'ai besoin d'obtenir dans la première section de la table 3 lignes et la seconde contiendra tout le reste (17 lignes).

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

Quelqu'un peut-il m'aider?

21
Anton

NSMakeRange est défini comme (startingIndex, length), ne pas (start, end) dont il semble que vous essayez de l'utiliser.

Donc, si vous avez besoin des 3 premiers objets, le reste ressemblera à ceci:

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

Modifier: selon votre commentaire, vous recherchez en fait le nombre à renvoyer en nombre de lignes dans la section. Puisque vous utilisez un nombre fixe de lignes, vous pouvez simplement renvoyer le nombre réel dans l'instruction 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;
}

Vous n'avez pas réellement besoin d'utiliser [subarrayWithRange], ni NSMakeRange. Si vous devez à un moment donné référencer le tableau réel, vous obtiendrez un objet NSIndexPath que vous pourrez utiliser pour obtenir l'objet de votre tableau. Vous devrez utiliser les propriétés de section et de ligne.

Modifier: NSRange -> NSMakeRange

59
Joel Fischer

Comme d'autres l'ont remarqué, vous utilisez incorrectement NSRange.

Sa définition est

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

donc le deuxième paramètre de la structure est la longueur de la plage, pas l'emplacement du dernier élément comme vous le pensez apparemment.


Cela étant dit, ce que vous faites est beaucoup plus compliqué qu'il ne devrait l'être.

Quel est le but de produire un sous-tableau d'une longueur connue, puis de renvoyer la longueur du sous-tableau lui-même? Avec ça en tête:

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

devrait être (en utilisant NSRange correctement)

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

mais ça peut être juste

return 6;

ou si la longueur de la plage est un paramètre

return length;

Encore une fois, il n'est pas nécessaire dans le monde de découper un tableau et de compter. La longueur est connue a priori.


Donc, dans le contexte de UITableViewDataSource, vous devez

  • renvoie le nombre de chaque section dans -tableView:numberOfRowsInSection:. Quelque chose comme

    switch(section) {
        case 0: return 2;
        case 1: return 18;
    }    
    
  • retourner les objets réels dans tableView:cellForRowAtIndexPath:. Quelque chose comme

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

Comme conseil supplémentaire, je vous conseillerais d'utiliser une notation différente pour construire des structures

NSMakeRange(0, 42)

peut être écrit

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

ce qui est beaucoup plus lisible (et moins sujet aux erreurs, surtout lorsque vous avez un doute sur la signification des paramètres).

Même

(NSRange){ 0, 42 }

est acceptable. Je pense que c'est mieux (et plus court) que NSMakeRange, mais il perd les avantages ou la lisibilité.

5

Ok j'ai résolu mon problème

Dans ma classe Fetcher, je l'ai fait

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

puis

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

puis dans la méthode cellForRowAtIndexPath:

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

article - c'est mon NSObject avec MVC

Donc ça marche comme je voulais :)

Merci d'avoir essayé de m'aider.

À votre santé

1
Anton