Confusion over length being used with NSArray in obj-c - objective-c

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.

Related

objects in array no index position

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.

Why do I get the error "Array initializer must be an initializer list" when I'm trying to return this array in a function?

I am coming from Java, and I'm very new to Objective C. Anyway, I have this static method which is designed to make a copy of an array (if there's a better way to accomplish this, please let me know, but I'm asking this question more-so to find out why I got this error and how to avoid such an error in the future.) I ran into some problems with it, but just when I thought I had them all sorted out, I got this error that looked like
Here is the method in the interface:
+ (float[]) copyArray: (float[]) array withLength: (int) length;
And here is the method in the implementation:
+ (float[]) copyArray: (float[]) array withLength: (int) length
{
float copiedArray[length];
for (int i = 0; i < length; i++)
{
copiedArray[i] = array[i];
}
return copiedArray;
}
If all you really want is to copy the first n elements from one C array into another already existing array, probably the best way is to simply use memcpy:
memcpy(targetArray, sourceArray, sizeof(sourceArray[0]) * numElements);
The sizeof(sourceArray[0]) calculates the byte-size of the type in your array (in your case, it's equivalent to sizeof(float).
method/function cannot return C array. you should do this
+ (void) copyArrayFrom:(float *)array to:(float *)toArray withLength: (unsigned) length
{
for (int i = 0; i < length; i++)
{
toArray [i] = array[i];
}
}
C arrays are way more tricky than Java arrays. One of the biggest issues is that in a lot of instances, you don't know how large a C array is unless you have saved this information in a different variable, for example. The C FAQ "Arrays and Pointers" lists a lot of traps and they apply to Objective-C as well. You might want to see question 6.5 in particular.
As #lwxted already suggested, try to avoid C arrays unless you really know what you're doing and you have determined that you need them. C arrays are faster than NSArray but unless you have determined that your array really is a performance bottleneck by measuring with a profiler you will most likely not notice any difference.
And I strongly recommend avoiding a C array of Objective-C objects (id objects[]) unless you really, really know very well what you are doing (memory management issues).
In Objective-C, unless for particular needs, a better way to handle this usually is to use the NSArray as opposed to C arrays.
[NSArray arrayWithArray: array];
will copy an array.
Besides, in this case, if you insist on using C arrays, the use of implicitly typed length float[] is advised against. A better way is to use pointers to manipulate arrays.
Also, the stack-allocated array would be invalid after leaving the function, since it's local only in the scope of the copyArray function. You should dynamically allocate memory, if you wish the array to be valid outside the scope.
While I agree with all the points #DarkDust makes, if you're working with a C API such as OpenGL, there may be situations where using NSArray and NSNumber vs. C arrays of type float will have performance impacts. As always, try to use the simpler approach first, and carefully measure performance before deciding to optimize.
In any case, to answer the original question, here's how to correctly return a copy of a C array:
+ (float *)copyOfCArray:(float *)array withLength:(int)length
{
float *copyOfArray = malloc(length * sizeof(float));
for (int i = 0; i < length; i++) {
copyOfArray[i] = array[i];
}
return copyOfArray;
}
Also, there's arguably no need to make the above a method at all. Instead, consider writing it as a C function:
float *CopyArray(float *array, int length)
{
// Implementation would be the same...
}

NSMutableArray Count

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).

Can a block be used as a value for notFoundMarker in iOS?

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

Objective-C for Dummies: How do I get a value out of NSDictionary?

so I'm having the most difficult of time pulling values out of an NSDictionary. Right now I just have a dictionary that is populated from a JSON call and it only contains a key named 'Success' with a value of 0 or 1.
How do I do a conditional on that value to check if its 0 or 1? I've tried a bunch of things, but I'm not getting anywhere. Here's my current code:
[[jsonDictionary objectForKey:#"Success"] isEqualToNumber:1]
I'm getting passing argument 1 of 'isEqualToNumber:' makes pointer from integer without a cast' as a warning, and the app crashes when it hits that line anyway.
And a subquestion, what's the difference between objectForKey and valueForKey? Which one should I use by default?
Anyway, this noob in Objective-C would truly appreciate some help on this. Thanks in advance!
Since dictionaries contain Objective-C objects, an entry containing a number is an NSNumber instance. NSNumber provides a convenience method, -intValue, for extracting its underlying int value:
if ([[jsonDictionary objectForKey:#"Success"] intValue] == 1) { … }
Note that NSNumber has other convenience methods for extracting its underlying value as other C data types.
In most cases, you should use -objectForKey: instead of -valueForKey:. The former is the canonical method to obtain an entry in the dictionary and is declared in NSDictionary. The latter is declared in NSObject and is used in Key-Value Coding contexts, where the key must be a valid KVC key, and there’s additional processing — for instance, if you’re using -valueForKey: in a dictionary with a key that starts with #, that character is stripped from the key and [super valueForKey:key] is called.
The number 1 is not an object pointer. Use an NSNumber instance instead if you want to use a number in an NSDictionary.
[[jsonDictionary objectForKey:#"Success"]
isEqualToNumber:[NSNumber numberWithInteger:1]]
[[jsonDictionary objectForKey:#"Success"] isEqualToNumber: [NSNumber numberWithInt:1]]
Number and Value Programming Topics: Using Numbers
NSNumber: What is the point ?
You can get the value of dictionary in different ways like checking
the value first.
Solution 1: Using simple if statement.
int value = 0;
if ([[jsonDictionary objectForKey:#"Success"]intValue]==1){
value = [[jsonDictionary objectForKey:#"Success"]intValue];
}
Solution 2: Using ternary operator
value = ([[jsonDictionary objectForKey:#"Success"]intValue]==1) ? 1:0;