how to chain methods in objective-c - objective-c

I'm trying to implement a parsing method to turn an XML document into a multi-dimensional array, however it relies on needing to removal objects from an array just after adding that array to the multi-dimensional array, like so:
while (k<blockRowArray.count){ //loops through all rows one by one
NSLog(#"current k is %i", k);
GDataXMLDocument *currentRow = (GDataXMLDocument *) [blockRowArray objectAtIndex:k];
NSArray *arrayOfBlocks = [currentRow nodesForXPath:#"b" error:nil];
j = 0;
while (j <arrayOfBlocks.count) {
NSLog(#"current j is %i",j);
GDataXMLElement *blockElement = (GDataXMLElement *) [arrayOfBlocks objectAtIndex:j];
NSNumber* blockValue = [NSNumber numberWithInt:[[blockElement stringValue] intValue]];
[individualRowOfBlocks addObject:blockValue];
j++;
}
k++;
NSLog (#"Current row of blocks array is %#",individualRowOfBlocks);
[rowBlocks addObject:individualRowOfBlocks];
[individualRowOfBlocks removeAllObjects];
}
However [individualRowOfBlocks removeAllObjects] is clearly running at the same time or before [rowBlocks addObject:individualRowOfBlocks] as I end up with a multi-dimensional array with a set of empty arrays in it, so what I need to do is make sure that [individualRowOfBlocks removeAllObjects] runs after [individualRowOfBlocks removeAllObjects] any methods of doing this?

However [individualRowOfBlocks removeAllObjects] is clearly running at
the same time or before [rowBlocks addObject:individualRowOfBlocks] as
I end up with a multi-dimensional array with a set of empty arrays in
it, so what I need to do is make sure that [individualRowOfBlocks
removeAllObjects] runs after [individualRowOfBlocks removeAllObjects]
any methods of doing this?
Unless there are threads (or queues) involved, Objective-C methods are always going to be executed in the order written in the code unless the methods being called explicitly do stuff in threads/queues in their implementation (which is exceptionally unlikely in that code).
Every time you call [rowBlocks addObject:individualRowOfBlocks];, you are adding a new reference to the same individualRowOfBlocks array. If you subsequently change the contents of individualRowOfBlocks, every slot in rowBlocks will effectively reflect that change because every slot points to the same instance of the array.
It sounds like instead of removeAllObjects, you should create a new instance of NSMutableArray on each pass through the loop, assigning it to individualRowOfBlocks.

Related

DFS algorithm implementation at Objective C

I am trying to implement the Objective C realization of this algorithm. Here the implementation of it:
#implementation DFSAlgorithm
-(void)dfs:(Graph*)g andStartingPosition:(int)s{
[self performDFS:g andPosition:s];
}
-(void)markedArrayInit:(int)capacity{
//0 is for unmarked vertices
//1 is form marked ones
self.marked=[[NSMutableArray alloc]initWithCapacity:capacity];
for(int i=0;i<[self.marked count];i++)
[self.marked replaceObjectAtIndex:i withObject:[NSNumber numberWithInt:0]];
}
-(void)performDFS:(Graph *)g andPosition:(int)v{
[self markedArrayInit:(int)[g numberOfVertices]];
[self.marked replaceObjectAtIndex:v withObject:[NSNumber numberWithInt:1]];
for (NSNumber *vertex in [g.vertices objectAtIndex:v]){
if(1==[self isMarked:v atGraph:g]){
NSLog(#"%d",(int)vertex);
[self performDFS:g andPosition:(int)vertex];
}
}
}
-(int)isMarked:(int)v atGraph:(Graph *)g{
return [self.marked objectAtIndex:v];
}
#end
However, I don't understand why the following error occurs:
[__NSArrayM replaceObjectAtIndex:withObject:]: index 0 beyond bounds for empty array'
How can I correctly initialize the marked array?
Thank you.
An NSMutableArray is created empty, the capacity value you pass is just a hint to the implementation about how large you expect the array to become.
Therefore replaceObjectAtIndex:withObject: does not work for you, as the array is empty you have no objects to replace.
Instead just use addObject: capacity times.
In your markedArrayInit method you create empty mutable array and reserve memory for it to hold at least capasity number of items. But you do not actually add anything to it (for loop in that method does not actually do anything at all). To fix your problem you can add enough number of items in for loop:
for (int i=0;i< initWithCapacity:capacity;i++)
[self.marked addObject: #0];
}
Edit:
Your implementation has several other problems:
you initialize marked array on each call to performDFS:andPosition:, and call that method recursively. You should move initialization to dfs:andStartingPosition: method
In isMarked:atGraph: method you return object from array, not the numeric value it holds - so it will never be 1, you might want to replace it with the following implementation (Note that method name implies we return some boolean value, not an integer that we'll need to interpret later):
-(BOOL)isMarked:(int)v atGraph:(Graph *)g {
return [self.marked[v] intValue] == 1;
}
...
if([self isMarked:v atGraph:g]){
...
}
There're better data structures to store indices of marked nodes, e.g. NSSet or NSIndexSet
You try to replace not existing object inside array. In markedArrayInit use addObject: method from NSMutableArray. [self.marked count] is always 0 in for cycle.

NCSFDictionary, Mutating method sent to immutable object

I have just started to jump into the realm of Objective-C and am slowly getting it all. I have been working on unarchiving a file that was a NSMutableArray and then initializing in my model with that array. The array is filled with various NSMutableDicationary's. From what I have seen it will add those dictionaries as non-mutable, so I went ahead and copied the regular and put them in a mutable and remove the old one. This solution seems to work for every instance except the very first.
I am at a loss as to why it would work for all but the first.
Here is how I am initializing it all
-(id) initWithList:(NSMutableArray *)savedList
{
self = [super init];
if (self)
{
int size=0;
serverList=[[NSMutableArray alloc] initWithArray:savedList copyItems:YES];
size=[serverList count];
for(int i=0;i<size;i++)
{
loginList=[NSMutableDictionary dictionaryWithDictionary:[serverList objectAtIndex:i]];
[serverList addObject:loginList];
[serverList removeObjectAtIndex:i];
}
}
return self;
}
Here is the code that is throwing the error, The value is being read off of a checkbox in a tableview and passed here to change the value.
-(void)setMount:(int)row value:(NSNumber*)boolAsNumber
{
[[serverList objectAtIndex:row] setObject:boolAsNumber forKey:#"mountshare"];
}
Here is the error that it shows when I try and change the first element
2010-12-01 13:38:54.445 Network Share[35992:a0f] *** -[NSCFDictionary setObject:forKey:]: mutating method sent to immutable object
Thanks for your help. If there is a better way please let me know.
This loop code is wrong:
size=[serverList count];
for(int i=0;i<size;i++)
{
loginList=[NSMutableDictionary dictionaryWithDictionary:[serverList objectAtIndex:i]];
[serverList addObject:loginList];
[serverList removeObjectAtIndex:i];
}
When you remove an object, the array is renumbered. After you've processed the 1st object at index 0, the original 2nd object is becoming the 1st object at index 0, but i is now set to index 1, which is where the original 3rd object is! This means you're only processing alternate items from the original array, and the 2nd, 4th, etc items never get swapped, and that's why you get the errors you're seeing.
One way to solve this would be to replace the "i" in the objectAtIndex: and removeObjectAtIndex: calls with "0", so you're always taking items off the front of the array.
The alternate solution would be to create a separate newServerList array and insert your new objects into that. At the end of the loop, release the old serverList and set the variable to point to newServerList.
Your indexes are messed up. As soon as you remove the object at index 0, the next one will take it's place and you will never replace that, because you then carry on with index 1.
{immutable0, immutable1}
i = 0:
addObject:
{immutable0, immutable1, mutable0}
removeObjectAtIndex:
{immutable1, mutable0}
i = 1:
addObject:
{immutable0, mutable0, mutable02}
removeObjectAtIndex:
{immutable0, mutable02}
--> still got the immutable there. Remember to never remove objects from a mutable array you are looping through at the same time.
You could condense the code a bit:
NSMutableArray *serverList = [NSMutableArray arrayWithCapacity:[savedList count]];
for (NSDictionary *dictionary in savedList)
{
mutable = [dictionary mutableCopy];
[serverList addObject:mutable];
[mutable release];
}
Unrelated to your problem: the argument is obviously wrong (NSMutableArray), if you expect an immutable array there; and if you create your serverList that way, there is no need for a deep copy (copyItems:YES).

My NSMutableArray doesn't work

sorry for my stupid question (beginner)
I got the demo program Accelerometergraph the apple site and would like to use
NSMutableArray in the values of acceleration x.
but my NSMutableArray contains only one object, there being several passage
NSMutableArray routine and should contain the same number of objects that the counter
show, how code below
if(!isPaused)
{
array = [[NSMutableArray alloc] init];
[filter addAcceleration:acceleration];
[unfiltered addX:acceleration.x y:acceleration.y z:acceleration.z];
NSNumber *number = [[NSNumber alloc] initWithDouble:acceleration.x];
[array addObject:number];
++a;
if (a == 30) // only check the # objs of mutablearray
{
sleep(2);
}
[filtered addX:filter.x y:filter.y z:filter.z];
}
It looks like you're missing a loop of some kind. The code you list above:
Makes sure something isn't paused.
Creates a new (empty) mutable array.
Adds a value to the new array.
And does some other work.
My guess is that this whole if{} block sits inside some kind of loop. You need to alloc and init the mutable array outside of the loop instead.
You create a new array each time the if block is entered, so the addObject: will only add the object to the most recently created array.
Furthermore, you are leaking the array and number objects. Each time you allocate an object, you are responsible for releasing it. Make sure you're familiar with the guidelines set out in the memory management programming guide.

NSArray : release its objects, but keep a pointer to it

I declare an NSArray in my code then building the array from another array. I process my NSArray and when I'm finished, I would like to release the objects, but I'm reusing this pointer to NSAarray again later to do the same process (creating the array from another array, process then releasing).. So I need to keep the pointer.
What should I do ?
Here is roughly what I want to do, the buildArray is creating and returning an autoreleased NSArray :
NSArray *myArray;
for (int i = 0, i < 10, i++){
myArray = [NSArray arrayWithArray:[self buildArray]];
// Here I process myArray
...
myArray = nil; // is my guess
}
I need to keep a pointer to my NSArray, in order to reuse later in the loop, but what is happening to the objects created with [self buildArray]? What is the best to do in order not to keep unused object and arrays ?
Or maybe the best solution is simply to removeAllObject of the array..?
Thank you!
You can't reuse an NSArray since it's immutable. You can use an NSMutableArray (which supports -removeAllObjects) though.
If are you need is to keep the pointer, but doesn't need it constant within the loops, you could just use
loop {
NSArray* myArray = [self buildArray];
...
// myArray = nil; // optional.
}
Don't do it like that. Instead, do:
for (int i = 0, i < 10, i++){
NSArray *myArray = [self buildArray]; //buildArray should return an autoreleased object
//Process array
//myArray goes out of scope and is autoreleased later, releasing all of its objects
}

Change the values within NSArray by dereferencing?

I've come across a problem related to pointers within arrays in objective-c.
What I'm trying to do is take the pointers within an NSArray, pass them to a method, and then assign the returned value back to the original pointer(the pointer which belongs to the array).
Based on what I know from C and C++, by dereferencing the pointers within the array, I should be able to change the values they point to... Here is the code I'm using, but it is not working (the value phone points to never changes based on the NSLog output).
NSArray *phoneNumbers = [phoneEmailDict objectForKey:#"phone"];
for (NSString* phone in phoneNumbers) {
(*phone) = (*[self removeNonNumbers:phone]);
NSLog(#"phone:%#", phone);
}
And here is the method signature I am passing the NSString* to:
- (NSString*) removeNonNumbers: (NSString*) string;
As you can see, I am iterating through each NSString* within phoneNumbers with the variable phone. I pass the phone to removeNonNumbers:, which returns the modified NSString*. I Then dereference the pointer returned from removeNonNumber and assign the value to phone.
As you can tell, I probably do not understand Objective-C objects that well. I'm pretty sure this would work in C++ or C, but I can't see why it doesn't work here! Thanks in advance for your help!
Yeah, that's not going to work. You'll need an NSMutableArray:
NSMutableArray * phoneNumbers = [[phoneEmailDict objectForKey:#"phone"] mutableCopy];
for (NSUInteger i = 0; i < [phoneNumber count]; ++i) {
NSString * phone = [phoneNumbers objectAtIndex:i];
phone = [self removeNonNumbers:phone];
[phoneNumbers replaceObjectAtIndex:i withObject:phone];
}
[phoneEmailDict setObject:phoneNumbers forKey:#"phone"];
[phoneNumbers release];
You can't dereference Objective-C object variables. They are always pointers, but you should treat them as though they're atomic values. You need to mutate the array itself to contain the new objects you're generating.
NSArray is not a C/C++ style array. It's an Objective-C object. You need to use the instance methods of the NSArray class to perform operations on it.
In Objective-C you never "dereference" an object pointer to set its value.
Also, you're using what is called Fast Enumeration, which does not allow mutation.
You can also use enumerateObjectsUsingBlock:.
NSArray *array = [NSArray array];
__block NSMutableArray *mutableCopyArray = [array mutableCopy];
[mutableCopyArray enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
[mutableCopyArray replaceObjectAtIndex:idx withObject:[object modifiedObject]];
}];
Checkout How do I iterate over an NSArray?
While this may work to some degree, I haven't tested it, I'd file this under 'bad idea' and not touch. NSArray, and many other cocoa objects, a fairly complex and can have a variety of implementations under the hood as part of the class cluster design pattern.
So when it comes down to it you really won't know what you're dealing internally. NSArray is actually designed to be immutable so in place editing is even doubly a bad idea.
Objects that are designed to let you mess around with the internals expose those through api methods like NSMutableData's mutableBytes.
You're better off constructing a new NS(Mutable)Array with the processed values.