views:

51

answers:

5

I'm foolishly saying:

if ([imageCache objectAtIndex:index]) {

Problem is, on my first time through this, I haven't put ANYTHING in my NSMutableArray *imageCache, and this croaks with a range error.

How can I ask an NSMutableArray whether it has anything for a particular index?

+1  A: 
if (index < [imageCache count])
   ...
Vladimir
A: 

[imageCache count] will return the number of items in your array. Take it from there :-)

Andiih
Never mind! I see!
Dan Ray
A: 

Check the number of items in the array first with [imageCache count]. Don't try to ask for anything with an index greater than that result.

+4  A: 

The NSArray cluster class cannot store nil. So I think it is sufficient to simply check the bounds:

NSUInteger index = xyz; 
if (index < [imageCache count]) { 
    id myObject = [imageCache objectAtIndex:index]; 
}
Alex Reynolds
+1 While `NSArray` cannot store `nil`, it *can* store `[NSNull null]`...
Dave DeLong
Okay, the next-but-related question that this revealed... I'm loading these images asynchronously, they're all different sizes. So there's no telling the order they're going to get to me in. It appears that when I try to do `[imageCache insertObject:image atIndex:index]` for an index that doesn't exist, I get a range error too. Do NSArrays have to be contiguous?
Dan Ray
Why not just use the `NSMutableArray` method `-addObject:`? http://developer.apple.com/mac/library/documentation/cocoa/reference/Foundation/Classes/NSMutableArray_Class/Reference/Reference.html#//apple_ref/doc/uid/20000138-BABDEFAA
Alex Reynolds
I've just "solved" this by checking to see if I have [count] as deep as the index I'm trying to put in, and adding @"" until I do. (Also I really want replaceObjectAtIndex:withObject instead of insertObject...). So now it "works" but it's sure ugly.@Alex Reynolds--because I'm trying to keep my cache array in sync with the array of objects calling my asynchronous image fetcher, and I'm not likely to get my fetchers back in the order they were launched.
Dan Ray
If you need a sorted or ordered array, you might first perform the asynchronous fetches and then create a sorted or ordered array on completion of the fetch operations.
Alex Reynolds
Try a dictionary instead...keyed on your "index" value
Andiih
@Alex: the point is to short-circuit the need to fetch based on the contents of my cache. I can see the wisdom of what you're saying, and if I'd been that wise at design time it probably would have been a good approach, but that ship has sailed. ;-)@Andiih: Hmmm. Integer indexes just made me think arrayishly, but there's no reason those couldn't be dictionary keys. Thanks.
Dan Ray
+1  A: 

What find really useful is having a safeObjectAtIndex: method. This will do the check for you and will return nil if the index is out of range.

Just create a new category on NSArray and include the following methods:

- (id)safeObjectAtIndex:(NSUInteger)index;
{
    return ([self arrayContainsIndex:index] ? [self objectAtIndex:index] : nil);
}

- (BOOL)arrayContainsIndex:(NSUInteger)index;
{
    return NSLocationInRange(index, NSMakeRange(0, [self count]));
}
Diederik Hoogenboom
Nice use of categories.
Alex Reynolds
Is `arrayContainsIndex` also something you've created in a NSArray category? The docs mention no such method--and frankly, if such a thing existed, I'd just use that!
Dan Ray
Sorry, forgot about that one. I have updated the answer with the arrayContainsIndex: method.
Diederik Hoogenboom