objects in array no index position - objective-c

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.

Related

Changing NSMutableArray size in objective-c

I was looking around and couldn't find anything, and I'm starting to think it's not possible with objective-c.
I have a NSMutableArray *myMutableArray and the size varies depending on what csv file is loaded. Since I do not set a size of myMutableArray I can't do:
if (c == 5){
myMutableArray[q] = [[NSNumber numberWithFloat:myOtherArray] stringValue];
q = q + 1;
c = 0;
}
Else {
c = c + 1;
}
Since myMutableArray is technically of size nil I guess I can't add objects to it.
In cases, q can be between 1500 and 2500.
My question is, how do I make `myMutableArray' change size on every loop.
If this isn't possible, I guess I will have to make myMutableArray very large - but I need the values in myMutableArray for a graph. If I do myMutableArray = [[NSMutableArray alloc] initWithCapacity:5000]; and don't use the 5000 memory locations, will these locations be nil, or 0? (sorry if the technical words are wrong, by memory locations I mean the memory given to myMutableArray)
Thank you, if there is anything else I can add to this please feel free to let me know.
EDIT: What I'm trying to achieve is adding data to the array, and with that data create a graph
You can't have a sporadically populated array. Creating an array with capacity 5000 is just a hint as to how much data you might be going to store into the array. Consider using an array of dictionaries where the dictionary contains the q value (presumably one coordinate) and the associated value. You can then sort the array based on the q values if you need to (for plotting). Then you can just add the dictionaries to the array as usual (addObject:).
The NSMutableArray class declares the programmatic interface to objects that manage a modifiable array of objects. This class adds insertion and deletion operations to the basic array-handling behavior inherited from NSArray.
If you
arrayWithCapacity:
Creates and returns an NSMutableArray object with enough allocated memory to initially hold a given number of objects.
Mutable arrays expand as needed. When declaring them, we can init them like this:
+ (instancetype)arrayWithCapacity:(NSUInteger)numItems
Here numItems simply establishes the object’s initial capacity.
Later to add more data, i.e. to expand mutable array, use this
addObject:
What it does is, it inserts a given object at the end of the mutable array.
- (void)addObject:(id)anObject
It's important to note that:
The object to add to the end of the array's content. This value must not be nil. It raises an NSInvalidArgumentException if anObject is nil.

Confusion over length being used with NSArray in obj-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.

change element value nsmutablearray

hi i have an array which holds 200 objects or so. Each of these objects is another array with 6 fields of mixed types ( ints, strings and bools).
2 questions...
can i search the array to find the objects that have a certain element i.e say all objects that have element "A" = TRUE.
How do i update a single element from one of the objects? DO i have to find that object (from the parent array hence why i asked the first question) , remove it then add a new object with the updated field? seems a bit overkill but is this what i need to do? is there anyway just to update that single element ?
Yes you can search for that, and yes you must if you're going to change a value. You can use indexOfObjectPassingTest to find the object. in your posted example, you would use it like this (assuming that your objects are each dictionaries with one of the fields being "A"):
NSUInteger indx =[myArray indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
return [[obj valueForKey:#"A"] isEqualToNumber:[NSNumber numberWithBool:TRUE]];
}];
indx will be the index of the object that passes that test in your array.

Distinct Object using NSPredicate

I have an NSArray of custom objects. Consider that the custom objects have a PageNumber property. I would like to filter my NSArray with a condition like "customObject.PageNumber is distinct".
I know I can loop through the array and eliminate object with duplicate pageNumbers. But is there any easy way to do it? I have tried,
[myarray valueForKeyPath:#"distinctUnionOfObjects.pageNumber"];
It is giving me the unique page numbers (like 7, 8, 9). But I want the custom object itself rather than just page numbers. Can any predicate help me?
I have created a simple library, called Linq to ObjectiveC, which is a collection of methods that makes this kind of problem much easier to solve. In your case you need the Linq-to-ObjectiveC distinct method:
NSArray* itemsWithUniquePageNumbers = [items distinct:^id(id item) {
return [item pageNumber];
}];
This returns an array of objects, each one with a unique page number.
Yes, that is possible with the help of NSPredicate
customObject=[(NSArray*)[myArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"self.PageNumber==%d",pageNumber]] lastObject];
//pageNumber is an integer
The filtered array is an NSArray of your custom objects which is the result of filtering using the predicate. Since your page number is unique, it will return only an array of one object. We get that by passing lastObject message to it.
Refer:
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Predicates/predicates.html#//apple_ref/doc/uid/TP40001798-SW1

Implementing an NSOutlineView to edit the contents of a plist file

I'm writing a game using cocos2d-iphone and our stages are defined in .plist files. However, the files are growing large - so I've developed an editor that adds some structure to the process and breaks most of the plist down into fixed fields. However, some elements still require plist editor type functionality, so I have implemented an NSOutlineView on the panels that show 'other parameters'. I am attempting to duplicate the functionality from XCode's 'Property List Editor'.
I've implemented the following system; http://www.stupendous.net/archives/2009/01/11/nsoutlineview-example/
This is very close to what I need, but there is a problem that I've spent most of today attempting to solve. Values for the key column are calculated 'backwards' from the selected item by finding the parent dictionary and using;
return [[parentObject allKeysForObject:item] objectAtIndex:0];
However, when there are multiple items with the same value within a given dictionary in the tree, this statement always returns the first item that has that value (it appears to compare the strings using isEqualToString: or hash values). This leads to the key column showing 'item1, item1, item1' instead of item1, item2, item3 (where items 1-3 all have value ''). I next tried;
-(NSString*)keyFromDictionary:(NSDictionary*)dict forItem:(id)item
{
for( uint i = 0; i < [[dict allKeys] count]; i++ ) {
id object = [dict objectForKey:[[dict allKeys] objectAtIndex:i]];
if ( &object == &item ) {
return [[dict allKeys] objectAtIndex:i];
}
}
return nil;
}
But this always returns nil. I was hoping that somebody with a bit more experience with NSOutlineView might be able to provide a better solution. While this problem only appears once in the linked example, I've had to use this a number of times when deleting items from dictionaries for instance. Any help would be greatly appreciated.
return [[parentObject allKeysForObject:item] objectAtIndex:0];
However, when there are multiple items with the same value within a given dictionary in the tree, this statement always returns the first item that has that value …
Well, yeah. That's what you told it to do: “Get me all the keys for this value; get me the first item in the array; return that”.
… this statement always returns the first item that has that value (it appears to compare the strings using isEqualToString: or hash values).
It's not that statement that's doing it; it's how dictionaries work: Each key can only be in the dictionary once and can only have exactly one object as its value, and this is enforced using the hash of the key and by sending the keys isEqual: messages (not the NSString-specific isEqualToString:—keys are not required to be strings*).
The values, on the other hand, are not uniquified. Any number of keys can have the same value. That's why going from values to keys—and especially to a key—is so problematic.
*Not in NSDictionary, anyway. When you attempt to generate the plist output, it will barf if the dictionary contains any non-string keys.
I next tried;
-(NSString*)keyFromDictionary:(NSDictionary*)dict forItem:(id)item
{
for( uint i = 0; i < [[dict allKeys] count]; i++ ) {
id object = [dict objectForKey:[[dict allKeys] objectAtIndex:i]];
if ( &object == &item ) {
return [[dict allKeys] objectAtIndex:i];
}
}
return nil;
}
But this always returns nil.
That's the least of that code's problems.
First, when iterating on an NSArray, you generally should not use indexes unless you absolutely need to. It's much cleaner to use fast enumeration.
Second, when you do need indexes into an NSArray, the correct type is NSUInteger. Don't mix and match types when you can help it.
Third, I don't know what you meant to do with the address-of operator there, but what you actually did was take the address of those two variables. Thus, you compared whether the local variable object is the same variable as the argument variable item. Since they're not the same variable, that test always returns false, which is why you never return an object—the only other exit point returns nil, so that's what always happens.
The problem with this code and the earlier one-liner is that you're attempting to go from a value to a single key, which is contrary to how dictionaries work: Only the keys are unique; any number of keys can have the same value.
You need to use something else as the items. Using the keys as the items would be one way; making a model object to represent each row would be another.
If you go the model-object route, don't forget to prevent multiple rows in the same virtual dictionary from having the same key. An NSMutableSet plus implementing hash and isEqual: would help with that.
You probably should also make the same change to your handling of arrays.
To clarify, I eventually resolved this problem by creating proxy objects for each of the collections in the plist file (so, for every NSMutableArray or NSMutableDictionary). This meant that I essentially mirrored the Plist structure and included references back to the original objects at each level. This allowed me to store the array index for each object or the dictionary key, so when saving items back from the outline view to the Plist structures, I used the 'key' or 'index' properties on the proxy object.