21

I have an Array with content. as usual it contain 20 objects. I want the same array split into 2 sections in Tableview. I am trying to implement it with NSMake in current array. For example I need get in first tableview section 3 rows and second will contain all the rest (17 rows ).

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

Does anyone can help me with that?

9
  • 4
    NSMakeRange's parameters are (location, length). Perhaps you're thinking it's something else? Commented Oct 25, 2013 at 18:32
  • If you have a hardcoded range, why bother creating the subarray? Just return the hardcoded count for each section and avoid all of the overhead of creating an NSRange and a wasted NSArray. Commented Oct 25, 2013 at 19:06
  • @rmaddy I more or less asked the same question, he said he wants the actual objects. Commented Oct 25, 2013 at 19:08
  • @JoelFischer But he's not using the array except to get the count. That's silly. The count will always be the length value of the NSRange. Commented Oct 25, 2013 at 19:09
  • I know, if you look at the bottom of my answer I said that I wasn't sure what count was used for. He commented saying I don't need to return count of array objects. section 1 should contain objects from 1 to 3 and section 2 should contain from 4 to 20. I'm assuming, based on that, and the fact that he IS using subarrays that what he really wants is the objects. I'm guessing this is used in a tableview rows for various sections. If this is for the number of rows, you're right, he should just just use hardcoded counts. Commented Oct 25, 2013 at 19:11

3 Answers 3

63

NSMakeRange is defined as (startingIndex, length), not (start, end) which it seems like how you are trying to use it.

So if you need the first 3 objects, then the rest it would look like this:

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

Edit: According to your comment, you are actually looking for the count to return in number of rows in section. Since you are using a fixed number of rows, you can just return the actual number within the case statement.

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

You do not actually need to use [subarrayWithRange], nor NSMakeRange. If you do need to at some point reference the actual array, you will get an NSIndexPath object which you can use to get the object from your array. You will need to use the section and row properties.

Edit: NSRange -> NSMakeRange

Sign up to request clarification or add additional context in comments.

14 Comments

Hi Joel, So How I can do what I need? I am using count, because I need return numberOfRowsInSection:
@Anton see my updated answer. This is assuming you're looking to actually return an array.
in second session it always takes rows from 0. I don't need to return count of array objects. section 1 should contain objects from 1 to 3 and section 2 should contain from 4 to 20.
There's no point to any of this. Just return hardcoded counts.
@GabrielePetronella Yeah, I caught that, and since it wasn't part of the original question, and I figured it would make him more confused, I just removed it.
|
5

As others have noted you are using NSRange improperly.

It's definition is

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

so the second parameter of the struct is the length of the range, not the location of last element as you apparently think.


That being said, what you are doing it's much more complicated than it should be.

What's the purpose of producing a subarray of a known length and then returning the length of the subarray itself? With this in mind:

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

should be (using NSRange properly)

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

but it can actually be just

return 6;

or if the range length is a parameter

return length;

Again, there's no need in the world to slice an array and count. The length is known a priori.


So in the context of UITableViewDataSource, you have to

  • return the count for each section in -tableView:numberOfRowsInSection:. Something like

    switch(section) {
        case 0: return 2;
        case 1: return 18;
    }    
    
  • return the actual objects in tableView:cellForRowAtIndexPath:. Something like

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

As an extra tip, I would advice using a different notation for building structs

NSMakeRange(0, 42)

can be written

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

which is much more readable (and less error prone, especially when you are in doubt about the meaning of the parameters).

Even

(NSRange){ 0, 42 }

is acceptable. I think it's better (and shorter) than NSMakeRange, but it loses the benefits or readability.

Comments

1

Ok I have solve my issue

In my Fetcher class I did

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

then

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

then in method cellForRowAtIndexPath:

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

item - it's my NSObject with MVC

So It's working As I wanted :)

Thanks for all trying to help me.

Cheers

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.