How to create a subarray of NSArray using NSRange?
Asked Answered
D

3

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?

Debra answered 25/10, 2013 at 18:29 Comment(9)
NSMakeRange's parameters are (location, length). Perhaps you're thinking it's something else?Browbeat
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.Neutralism
@Neutralism I more or less asked the same question, he said he wants the actual objects.Throaty
@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.Neutralism
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.Throaty
@Neutralism I need count these object per each section in method tableView:numberOfRowsInSection:Debra
@Debra Right. Since you need a count you should return a count. Since you are hardcoding the length parameter in NSMakeRange, why not just return that length directly? There is no point to creating a subarray just to return its count when you are hardcoding the length of the subarray. The hardcoded length and the resulting subarray count will always be equal.Neutralism
@Neutralism maybe will be better to split this array with 2 arrays?Debra
this question is gone. it either needs MAJOR rewriting or closing.Aeneus
T
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

Throaty answered 25/10, 2013 at 18:31 Comment(14)
Hi Joel, So How I can do what I need? I am using count, because I need return numberOfRowsInSection:Debra
@Debra see my updated answer. This is assuming you're looking to actually return an array.Throaty
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.Debra
@Debra That should be easy enough to do, in that case, you should be able to easily modify my answer. Just make another case for 2, add another return statement and modify the NSMakeRanges in the style of (location, length) as above, and you'll be set!Throaty
There's no point to any of this. Just return hardcoded counts.Neutralism
@JoelFischer in this line return [array subarrayWithRange:NSMakeRange(3, 17)]; it will show my array always from the first object. I have tried the same with NSIndexSet. Getting the same :(Debra
This answers provide some good piece of information about NSRange, but I believe it misses the main problem of the OP. He clearly stated in the comments that he needs to return an NSInteger in numberOfRowsInSection: but the answer now returns an array. Also, as @Neutralism rightfully pointed out, the whole thing is useless, as I explain in my answer.Vastitude
The first comment to this answer.Vastitude
@GabrielePetronella The first comment was edited, or I'm an idiot. One of the two.Throaty
@JoelFischer yes it was edited. It's not your fault, the OP is clearly very confused about the subject and that's why the unclear question. I was too quick in casting a downvote, if you edit the answer I'll be able (and happy) to retract it.Vastitude
@GabrielePetronella Edited my answer aboveThroaty
the question is more than 'confusing'Aeneus
@JoelFischer great! The only thing which is possibly incorrect, even though is a sketchy implementation, is array[indexPath.row]. Since he wants to use the same array for every section, you would actually need some offset according to the section. +1 thoughVastitude
@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.Throaty
V
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.

Vastitude answered 25/10, 2013 at 19:42 Comment(0)
D
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

Debra answered 27/10, 2013 at 20:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.