Objective C code debug issue - objective-c

I am trying to compile and run a simple objective c code BUT I am doing it on Windows.I am using the GNU Step and it is extremely hard for me to debug it and understand what is going on runtime.I am a .NET developer and I always use the Debugger in Visual Studio to follow the data flow and stuf but here ...... it is realy annoying.I don't have a Mac Book so I don't have the XCode too.
Can anybody tell me what is the problem in that peace of code?It is quite simple and it would be great if someone who has a Mac could debug it for me and tell me what is wrong.
The idea of the code is that it reads out a text file line by line and then on every 3 lines of code it makes an Object of NSMutableArray and adds it to another NSMutableArray.Here it is:
The read_line function:
int read_line(FILE *in, char *buffer, size_t max)
{
return fgets(buffer, max, in) == buffer;
}
The content of the text file:
Sophie Ellis-Bextor
71222
5.01
Inna Morales
61223
6.00
Kortez Domingues
41231
3.25
The code in the main:
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
FILE *in;
if((in = fopen("C:...\\Input.txt", "rt")) != NULL)
{
char line[256];
NSMutableArray* resultArray = [[NSMutableArray alloc] init];
while(read_line(in, line, sizeof line))
{
NSString *currentLine = [[NSString alloc] initWithUTF8String:line];
[resultArray addObject:currentLine];
}
NSMutableArray*resultObjectsArray =[[NSMutableArray alloc] init];
NSMutableArray*tmpArray =[[NSMutableArray alloc] init];
for(int i=0 ; i <[resultArray count];i++)
{
if(i%4 == 3)
{
[resultObjectsArray addObject:tmpArray];
[tmpArray removeAllObjects];
NSLog(#"Here we add a new object");
}
else
{
[tmpArray addObject:[resultArray objectAtIndex:i]];
NSLog(#"%#",[resultArray objectAtIndex:i]);
}
}
fclose(in);
NSLog(#"First object in the result Array: %#",[[resultObjectsArray objectAtIndex:0] objectAtIndex:0]);
}
[pool drain];
All that I can see is that on the
NSLog(#"First object in the result Array: %#",[[resultObjectsArray objectAtIndex:0] objectAtIndex:0]);
line I get the next error:
Uncaught Exception NSRangeException, reason:Index 0 is out of range 0 (in 'objectAtIndex:')

I'm assuming you accidentally left off a (blank) line at the end of your input file, since the exception you mention doesn't happen with the file literally as given. I've edited your question to reflect this. Then, assuming the file is fixed in that way:
The immediate cause of the exception is that tmpArray is empty when the final NSLog is called. The reason for that is that you reuse the same tmpArray object each time through the preceding loop; you add tmpArray to resultObjectsArray, and then clear out tmpArray and start adding additional members to it. The reason this is a problem is that array elements are added by reference, not copied; you need to either copy tmpArray each time or make a brand new temporary object.
So, when you reach the final NSLog, the first element in resultObjectsArray is the same object as tmpArray; you've just called [tmpArray removeAllObjects] in the if(i%4 == 3) conditional, so it's empty; thus the second objectAtIndex:0 raises an exception.
Now, as to why the original version of the input file (the one without the blank line at the end) does not trigger the same exception (but also doesn't function correctly): your for loop goes through line by line, and adds each line to tmpArray, until it reaches a line whose index is evenly divisible by 4, at which point it clears tmpArray so it can start adding more to it the next time. The original version of the input file you gave had 11 lines, so tmpArray wasn't cleared at the end; thus tmpArray, as well as the identical objects serving as elements of resultObjectsArray, contained the last three lines read. Since it wasn't empty, objectAtIndex:0 didn't raise an except. But at the same time, the logic was wrong, since the NSLog is supposed to be returning the first element in the array, but as it happens all the elements are references to that same tmpArray object, which contains only the last stanza of lines.

Related

Issue adding strings to a NSMutableArray using addObject

I've searched other questions and can't seem to find a similar problem. Either I am something completely wrong or I am blind. But here goes the code:
#autoreleasepool {
NSMutableString *sense = [[NSMutableString alloc] init];
NSMutableArray *senses = [[NSMutableArray alloc] init];
....... other code which initializes rL and count/length .......
for (index=0;index<count;index++) {
for (j=0;j<length;j++) {
c = [rL characterAtIndex:j];
switch (c) {
case '.':
[senses addObject:sense];
[sense setString:#""];
break;
default:
[sense appendFormat:#"%c",c];
break;
}
}
}
}
When I do this, and iterate, in debug mode, I see that all objects in senses are same as whatever the last value of sense was.
what am I doing wrong?
"sense" is always the same object. It is a mutable string, so the contents can change, but it is always the same object. So senses will contain that single object, multiple times. You could instead use
[senses addObject:[sense copy]];
The immediate solution could be to change:
[senses addObject:sense];
to:
[senses addObject:[NSString stringWithString:sense]];
This will add unique instances instead of adding the same mutable string over and over.
But it appears you are splitting a string up using the "." characters as a delimiter.
There's an easier way:
NSArray *senses = [rl componentsSeparatedByString:#"."];
That's it - one line.

Prevent duplicate printout of element in NSMutableArray

I am using a singleton class to transfer a NSMutableArray across views.
The issue I am having is my array is getting displayed multiple times.
Right now I am working with three UITextFields. Each is getting added to the array and outputted in a specific format. Here is what my output looks like:
A / B
C
A / B
C
A / B
C
All I need shown is:
A / B
C
Here is my code if someone can help me find what is missing or needs to be reworked:
To display the text:
UILabel * myLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 300, 200)];
[myLabel setFont:[UIFont fontWithName:#"Helvetica" size:10.0]];
myLabel.numberOfLines = 0;
NSMutableString * string = [NSMutableString string];
Education * myEducation = [Education sharedEducation];
for (Education * output in myEducation.educationOutputArray)
{
[string appendString:[NSString stringWithFormat:#"%# / %# \n%#\n", [myEducation.educationOutputArray objectAtIndex:0], [myEducation.educationOutputArray objectAtIndex:1], [myEducation.educationOutputArray objectAtIndex:2], nil]];
}
myLabel.text = string;
[self.view addSubview:myLabel];
Here is where I am saving the text:
-(void)saveButtonTapped:(id)sender
{
[_educationArray addObject:_aTextField.text];
[_educationArray addObject:_bTextField.text];
[_educationArray addObject:_cTextField.text];
Education * myEducation = [Education sharedEducation];
myEducation.educationOutputArray = _educationArray;
[self.navigationController popViewControllerAnimated:YES];
}
EDIT *
When a user is entering text into the text fields they can also add a new set of text using the same three text fields.
If I removed the for loop only the first is displayed. How can I get all of the text to display?
EDIT TWO *
I tried this:
[string appendString:[NSString stringWithFormat:#"%# / %# \n%#\n", [output major], [output university], [output timeAtSchool]]];
Results in this error:
2012-12-29 17:03:07.928 EasyTable[14501:c07] -[__NSCFString major]: unrecognized selector sent to instance 0x7176850
2012-12-29 17:03:07.941 EasyTable[14501:c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString major]: unrecognized selector sent to instance 0x7176850'
*** First throw call stack:
(0x1c99012 0x10d6e7e 0x1d244bd 0x1c88bbc 0x1c8894e 0x6162 0xff817 0xff882 0xffb2a 0x116ef5 0x116fdb 0x117286 0x117381 0x117eab 0x1184a3 0x118098 0x2c10 0x10ea705 0x21920 0x218b8 0xe2671 0xe2bcf 0xe1d38 0x2e5213 0x1c61afe 0x1c61a3d 0x1c3f7c2 0x1c3ef44 0x1c3ee1b 0x1bf37e3 0x1bf3668 0x1e65c 0x240d 0x2335 0x1)
libc++abi.dylib: terminate called throwing an exception
You add three elements at a time to the array, and later you want to process them three at a time.
It would probably be better to create a container class that holds the three elements, and add instances of the container class to the array.
But if you really want to do it this way, you can't use a for/in loop. You have to use an index variable:
NSArray *array = myEducation.educationOutputArray;
for (NSUInteger i = 0, count = array.count; i < count; i += 3) {
[string appendFormat:#"%# / %#\n%#\n", array[i], array[i+1], array[i+2]];
}
you don't have duplicates in the array: the problem is in the for loop
for (Education * output in myEducation.educationOutputArray)
{
[string appendString:[NSString stringWithFormat:#"%# / %# \n%#\n", [myEducation.educationOutputArray objectAtIndex:0], [myEducation.educationOutputArray objectAtIndex:1], [myEducation.educationOutputArray objectAtIndex:2], nil]];
}
here you are looping through the array 3 times (because there are 3 objects in the array) and then printing each object each time. I think you should just do the appendString: line wihtout the for loop
Your for loop is really odd; You loop through each object in the array but then you hardcoded the indexes inside the for loop. I'm not sure what's going on there but it's certainly the source of the odd output. That pointer to an Education object is what you should access. Each time through the loop, use the value of output.
If you're also having uniqueness issues, consider using an NSSet instead of an NSMutableArray. If you care about order, use NSOrderedSet. Set collection types do not allow duplicated values.
Also one more point: If you know you're only going to ever access the values at index 0, 1, and 2, there's really no point to having an NSArray. Just store each value separately and access it directly. At the very least there's no reason for the for loop.
Edit:
You're crashing because you think your array has Education objects in it but it really has plain strings:
-[__NSCFString major]: unrecognized selector sent to instance 0x7176850
Notice that it's saying that you tried to call the method major on an __NSCFString (a private subclass of NSString that apple uses internally). This is a good indicator that your array doesn't contain what you think it does. Make sure you're loading your data into your array correctly by constructing Education objects with the three pieces of data.
You also suggested that you tried
[string appendString:[NSString stringWithFormat:#"%# / %# \n%#\n", output]];
Basically what stringWithFormat: does is take that format string and use it like a template and then it takes as many arguments as you need to fill up the placeholders in the template. %# is a placeholder for an object's description so stringWithFormat: is going to expect three parameters after the format string to fill each %#.

copy and autorelease in enumeration

I am trying to change the contents of an array while enumeration. To avoid the warning ,"the array was mutated while being enumerated" i made a copy of the array and done the autorelease like this-
int iKeyArrayCount=0;
for(NSString *keyEntity in [[keyArray copy]autorelease])
{
[keyArray replaceObjectAtIndex:iKeyArrayCount withObject:[keyEntity stringByReplacingOccurrencesOfString:#"\"" withString:kMPVTBlankString]];
[keyArray replaceObjectAtIndex:iKeyArrayCount withObject:[keyEntity stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
iKeyArrayCount++;
}
My confusion is regarding the enumeration over that copy of keyArray. While enumeration is it like , a copy of keyArray is formed each time the for loop executes? Or only one copy of that keyArray is formed during the whole process of enumeration.
In that code snippet [[keyArray copy] autorelease] is executed once only, and the result is used at the object being iterated.
In other words, "only one copy of that keyArray is formed during the whole process of enumeration" is correct.
It doesn't make sense to copy the whole array for this. You could also just use a regular for-loop instead of the enumeration:
for (NSInteger i = 0; i < [keyArray count]; i++)
{
NSString *keyEntity = [keyArray objectAtIndex:i];
NSString *newKeyEntity = [keyEntity stringByReplacingOccurrencesOfString:#"\\" withString:#" "];
newKeyEntity = [newKeyEntity stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
[keyArray replaceObjectAtIndex:i withObject:newKeyEntity];
}
Things may get dirty if you start adding/deleting objects in the loop, but as long as you just replace them this is just fine.
As you may have already noticed that stringByReplacingOccurrencesOfString:withString: is useless in your example, since you replace it in the next line once again.

Objective-C: taking index of object in array

I'm new in Obj C programming, so i will start from beginning
I have an array with some NSNumber and NSString elements, i want to replace NSString elems to NSNumber elems. I decide to make this with for in construction get to new NSMutableArray all elements value and to NSMutableIndexSet their indexes, but when i made this i faced with trouble, here it is, i show you my code and log.
NSArray *oneMoreStack = [program copy];
NSLog(#" stack=%#",oneMoreStack);
NSLog(#" show me index ind=%#",[oneMoreStack indexOfObject:#"x"]);
NSMutableIndexSet *myVarIndexesSet;
NSMutableArray *myVarsArray;
for (id myVarConst in oneMoreStack) {
if([myVarConst isKindOfClass:[NSString class]])
{
if([myVarConst isEqualToString:#"x"]){
[myVarsArray addObject:myVarConst];
NSLog(#"obj x=%#",myVarConst);
[myVarIndexesSet addIndex:[oneMoreStack indexOfObject:myVarConst]];
NSLog(#"ind x=%#",[oneMoreStack indexOfObject:myVarConst]);
}
}
When i run it log show me this:
Calculator[6306:f803] stack=(
x,
2,
"+"
)
Calculator[6306:f803] show me index ind=(null)
Calculator[6306:f803] obj x=x
Calculator[6306:f803] ind x=(null)
then crash [NSMutableArray replaceObjectsAtIndexes:withObjects:]: index set cannot be nil
So, my question is why does [oneMoreStack indexOfObject:myVarConst] return null? How can i fix it? Thanks.
I don't mention this code before because think problem is in getting indexes.
after previous part of code goes this part:
[stack replaceObjectsAtIndexes:[myVarIndexesSet copy] withObjects:[myVarsArray copy]];
after that crash with error report i mention previously. Thanks.
[oneMoreStack indexOfObject:myVarConst] returns an NSUInteger, a primitive type, not an object.
In your NSLog, you are using %#, which says "Hey, take this object I'm passing as an argument, call -description on it, and print it out". Luckily, the NSUInteger you are passing in happens to be 0, NSLog thinks that it is a null object, and you aren't crashing. If the call to -indexOfObject: returns non-0, you will likely crash.
Try this instead:
// For iOS
NSLog(#" show me index ind=%u", [oneMoreStack indexOfObject:#"x"]);
or
// For 64-bit and 32-bit Mac OS X
NSLog(#" show me index ind=%lu", (unsigned long)[oneMoreStack indexOfObject:#"x"]);
You can learn more about string formats at:
Formatting String Objects

Recursively creating an object and copying specific objects from an array in said object

So, I'm struggling a bit with my programming project.
I have a object that stores player information, name, wins, losses.
I proceed to use that object in another object (a bracket) that sets the values of the player information, after each loop it copies the player object to a NSMutable in the bracket class.
Within the bracket class I have a method to print out the information, which was easy enough to figure out.
Now, to generate what will happen for the next bracket, I set up a method that will return a bracket when it's finished copying who won or lost.
I've done this all within the same bracket method so I could access the data as easily as possible. How do I simply just make a copy of the player object and add it to the new bracket?
I'm finding that I'm just getting garbage values or nothing at all when I try to print out the Bracket I've just generated. Here's my function that I'm having trouble with.
-(Bracket *) NextRound//Configures the next round
{
int i, y, *selection; //counter and selection
int comp;
y = 1;
i = 0;//so the counter won't get messed up
Bracket *roundx = [Bracket new]; //creates the bracket that will be sent back with the winners.
NSLog(#"Did %#(1) or %#(2) win (1 or 2)?: ",[[playerarray objectAtIndex:i] name], [[playerarray objectAtIndex:y] name]);
scanf("%d",&selection);
comp = selection++;
if (comp == 1)
{
NSLog(#"Player %d %# selected to win", i, [[playerarray objectAtIndex:i] name]);
[[self.playerarray objectAtIndex:i] setNext];//bool value for win or not
[roundx.playerarray addObject: [self.playerarray objectAtIndex:i]];
[roundx Print];//Too see if it has anything, usually it does not.
}
else
{
i++;
NSLog(#"Player %d %# selected to win", i, [[playerarray objectAtIndex:i] name]);
[[self.playerarray objectAtIndex:i] setNext];
[roundx.playerarray addObject: [self.playerarray objectAtIndex:i]];
[roundx Print];
}
return(roundx);
}
So, I thought that would just work. It compiles just fine (I get a few warnings, but it's about the integers and such that I use for logic mostly).
Thank You!
My comments:
The definition of selection is incorrect. You have defined it as a pointer to an int, but you are using it as if it were an int everywhere in your code. Note that selection++ increments selection by sizeof(int) not 1.
You shouldn't really be using -new to initialise objects but -alloc and then -init. (This is the modern convention).
The most likely cause of your problem is that playerarray is not initialised.