I am reading through some code and I came across the following statement and it seems to make absolutely no sense. The line is coded below. It takes the first object of an NSMutableArray and then sends the "count" message. What exactly is this doing?
for (int j = 0; j < [[inputData objectAtIndex:0] count]; j++)
//inputData is just an NSMutableArray
Could someone please explain this to me? I have never come across this before. I thought at first maybe it was like a 2-D array scenario where array[x].length is different from array.length, but inputData is just a single NSMutableArray of like 10 numbers.
If your array(in this case inpuData) has a key-value matching mechanism, this loop will increment its index but since everytime the condition is the same(the count of [inputData objectAtIndex:0] will never change ) this will cause an infinite loop
If you are correct that inputData contains NSNumbers, then what happens is that the first time through, you get an exception because NSNumber does not respond to -count.
The only way that code would do anything else is if [inputData objectAtIndex:0] responds to -count. It can be any object that responds to -count not just an array. Actually, it would also not throw an exception if inputData was nil. The expression would then return 0 (sending objectAtIndex: to nil returns nil and sending count to nil returns 0).
Related
I have an array which is a parsed xml feed which i want to add to another array using the code....
int insertIdx = [blogEntries count];
for (RSSItem *nextItem in feedItems) {
[blogEntries insertObject:nextItem atIndex:insertIdx];
//[blogEntries addObject:nextItem];
insertIdx += 1;
}
For some reason all of the objects in the blogEntries array all have an index of 0, when i slog them all out using...
for (RSSItem *nextItem in blogEntries)
NSLog(#"title - %#, pos - %i", nextItem.title, [blogEntries IndexOfObject:nextItem]);
do you know why the index might not be updating?
Any help would be appreciated
Did you try to use addObject: instead of insertObject:atIndex?
Are you sure that objects are different as:
indexOfObject:
Returns the lowest index whose corresponding array value is equal to a given object.
I was not able to refrain myself On the Topic of adding many item at once into a NSMutableArray, I do prefer to use this method :
- (void)addObjectsFromArray:(NSArray *)otherArray
it remove that useless for loop. (unless you need to do some other work in that loop)
And as of your problem, viperking have a big hint about a possible problem you may be facing. (if that is the case you may need to validate your isEqual: method.
I'm using this line of code to go through an array
for (int i = 0; i < [[GameP objectForKey:#"groundMap"] length]; i += 5) {
Coming from an AS3 background, I presumed "length" would give me the length of an array/object, but I've just discovered "count" which seems to do the same thing, and I can't find any info on using "length" but it seems to work.
Can someone tell me..
What is "length" and how/why is it working in that line?
What's the difference between count and length?
Which is better to use?
Thanks for any advice.
Assuming GameP is a dictionary, the call to objectForKey: returns an object of type id. So you are trying to call the length method on an id. This will compile fine but at runtime it is probably wrong assuming the object for "groundMap" is an array. An array only has a count method, no length method.
You are also accessing an object from the dictionary for every loop iteration. You really should write your code like this:
NSArray *groundMap = [GameP objectForKey:#"groundMap"];
NSUInteger count = groundMap.count;
for (int i = 0; i < count ; i += 5) {
}
This is easier to read and the compiler can do better error checking. It is also much more efficient.
At first you have to know the class of the object at your dictionary GameP.
If that NSArray you have to use count here is no way to use another method.
You can find length method at NSSString class.
NSDictionary has the following method signature:
- (NSArray *)objectsForKeys:(NSArray *)keys notFoundMarker:(id)anObject;
My question(s):
Is nil a reasonable default to use for notFoundMarker?
Is it possible to get the key (for which no value was found) back as the notFoundMarker itself? This is useful if the key and value were are different object types, and lets one know what's still missing.
Can a block be used as the value for notFoundMarker, will it actually run? Or will the block's stack-allocated-address simply be returned?
What are some really bad things to try and use as the value for notFoundMarker?
As pointed out in the comments below, you should use [NSNull null]
Probably not without writing your own wrapper method or some sort of category to do this. That said, if you just want to know what key wasn't found, you can simply look at the array of keys that you passed in, as the indexes will match up.
You can certainly use a block. I don't think it will be run. This should be very easy to test though (simply define a block that logs something out to the console and try it).
This really depends on the context and what you're doing to do with the returned array. There's nothing that's inherently bad to put in an array and return, but I'd question the decision to use anything that doesn't match the types of the objects you're expecting to be returned for keys that are found in the NSDictionary.
EDIT:
In fact you could probably achieve what you want for 2. like this:
NSMutableArray *objects = [myDictionary objectsForKeys:myKeys notfoundMarker:[NSNull null]];
for (int ii = 0; ii < [objects count]; ii++ ) {
if ([objects objectAtIndex:ii] == [NSNull null]) {
[objects insertObject:[myKeys objectAtIndex:ii] atIndex:ii];
}
}
Assume I have NSNumbers 1 - 450. I can choose to add them to an NSMutableArray either starting with 1 and ending with 450, or starting with 450 and ending with 1. My code would be a little simpler if I could start with 1 and end with 450, but when the time finally comes for me to enumerate over the array, I will ultimately need to reverse it. In other words, I need the first object in the enumeration to be 450, and the last one to be 1.
Since my code would be simpler if I do it this way (add starting with 1, then reverse it prior to enumeration), it's my preferred method. However, the Apple documentation for - (NSEnumerator *)reverseObjectEnumerator says:
It is more efficient to use the fast enumeration protocol (see
NSFastEnumeration). Fast enumeration is available on Mac OS X v10.5
and later and iOS 2.0 and later.
So should I avoid the array reversal and simply write slightly more complicated code so that the NSMutableArray gets created in the desired order in the first place?
You can use fast enumeration with an NSEnumerator instance, the documentation about fast enumeration even uses the reverseObjectEnumerator: method as an example:
NSEnumerator *enumerator = [array reverseObjectEnumerator];
for (NSString *element in enumerator) {
//...
}
Besides, your question sounds a lot like premature optimization...
No, you do not need to write the more complicated code to put it in the right order. The reverseObjectEnumerator will work fine, it is only marginally slower. If performance is a big concern, either of the snippets below will work well (the faster of the two being the while loop)
// Assuming 'array' is your NSMutableArray
int i = [array count];
while(i--) {
Object *current = [array objectAtIndex:i];
// Mess around with current
}
That will start you at 450 and end at 0. You can also do this with a for loop, though you need to make sure that you either start with index 449, or you do something like
for(int i = [array count]; i > 0 ; i--) {
Object *curreyt = [array objectAtIndex:i-1];
// Mess around with current
}
I'm sure I'm doing something silly, but this is driving me crazy.
I'm trying to loop through database results, create objects from those results, and add the objects to an NSMutableArray. I've verified via NSLog calls that the data is being correctly read from the database and copied to the object, but the count for the NSMutableArray always returns 0.
Here's the essence of the code:
while ([rs next]) {
Kana *htemp = [Kana alloc];
htemp.content = [rs stringForColumn:#"hiragana"];
[hiragana addObject:htemp];
}
NSLog(#"Hiragana contains %d objects", [hiragana count]);
Kana is derived from NSObject, and hiragana is an instance of NSMutableArray.
I'm sure this is a rookie mistake, and I hope someone can set me straight. TIA! :)
My guess, judging from the code you posted, is that you probably aren't allocating your array properly. When creating objects, you need to initialize them as well. Therefore, this:
Kana *htemp = [Kana alloc];
Should be:
Kata *temp = [[Kana alloc] init];
All objects need to be initialized this way. Thus, if I'm correct and you haven't initialized your array, then your creation needs to go from this:
NSMutableArray *hiragana = [NSMutableArray alloc];
to this:
NSMutableArray *hiragana = [[NSMutableArray alloc] init];
For optimization reasons, you should probably also specify an initial capacity as well if you have any idea how many objects you might hold:
[[NSMutableArray alloc] initWithCapacity:someNumber];
Another common cause (not in your case, as it turns out, but generally) is forgetting to even allocate the array. If you haven't created an array yet, you're sending that count message to nil, so the result will always be 0.
A few things:
What happens if you put an NSLog call inside of the while loop? Verify that loop iterations are actually happening before blaming it on the array.
Where are you creating the array hiragana? If you are doing it incorrectly for some reason and the array is nil, it might cause problems like this.
If you do not have garbage collection on, be sure to do [htemp release] after adding it to the loop. addObject retains and each added item will leak from the loop. Again, this is only relevant if garbage collection is off.
It's most likely either you aren't created the array correctly or rs doesn't contain what you expect it to contain, and so [rs next] isn't getting called ever (if rs is nil, for example, no iterations of this loop would execute and you wouldn't have any sort of error).