Prevent duplicate printout of element in NSMutableArray - objective-c

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 %#.

Related

removing null from arrays in Object-c

I have this snipped of code that results in an array with a whole bunch of "<null>" throughout and I need to figure out how to remove them. Obviously after smashing my head against the keyboard I'm asking for some help.
In my .h I have declared:
NSArray *sortedContacts;
NSArray *rawContacts;
And then in .m:
-(void) buildContacts {
ABAddressBook *addressBook = [ABAddressBook sharedAddressBook];
NSArray *contacts = [addressBook people];
rawContacts=contacts;
NSArray *firstNames = [rawContacts valueForKey:#"First"];
NSArray *lastNames = [rawContacts valueForKey:#"Last"];
NSArray *organization = [rawContacts valueForKey:#"Organization"];
NSMutableArray *fullNames = [NSMutableArray array];
for(int i = 0; i < [firstNames count]; i++)
{
NSString *fullName = [NSString stringWithFormat:#"%# %# %#",
[firstNames objectAtIndex:i],
[lastNames objectAtIndex:i],
[organization objectAtIndex:i]];
[fullNames addObject:fullName];
}
NSMutableArray *fullList = [[NSMutableArray alloc]initWithArray:fullNames];
[fullList removeObjectIdenticalTo: #"<null>"];
sortedContacts = [fullList sortedArrayUsingSelector:#selector(compare:)];
NSLog(#"%#",sortedContacts);
}
I've tried so many things that I just can't see the forest for the trees anymore.
The text <null> is how the singleton instance of NSNull describes itself. That is, it's what -[NSNull description] returns.
In turn, these NSNull objects are getting into your firstNames, lastNames, and organization arrays because that's what Key-Value Coding does when you call -valueForKey: on an array and some of the elements return nil when that message is forwarded on to them with the same key. That is, calling [rawContacts valueForKey:#"First"] causes NSArray to call [element valueForKey:#"First"] for each element in rawContacts and to put the result in the array it builds. But, since an array can't contain nil, if one of those elements returns nil from [element valueForKey:#"First"], an NSNull object is added in its place.
Then, you are formatting the string fullName from the corresponding elements of firstNames, lastNames, and organization. You need to check if any of those elements are NSNull using if ([value isKindOfClass:[NSNull class]]) and handling that. For instance, you might just skip that record. Or you might combine the available fields and leave out any unavailable ones.
In any case, none of the elements of fullList will be #"<null>" because formatting values into #"%# %# %#" can never result in that string. (It might be #"<null> <null> <null>" or something like that, but never just #"<null>".)
A quick look at your code suggests you cannot get any empty strings added to your array, (a) you add elements using:
[fullNames addObject:fullName];
and fullName is created using:
[NSString stringWithFormat:#"%# %# %#" ...
so even if the %#'s get replaced by nothing you'll still have 2 spaces...
Maybe this is why all the things you've tried fail, if you're looking for empty strings you won't find them.
(Addendum: Question now says you're looking for #"<null>", you won't get that either for the same reason - there is at least two spaces in your string.)
The simple answer to removing invalid entries in fullNames is not to add them in the first place. You are adding elements in a loop (for), and conditional logic (e.g. if) inside the loop to determine whether you have something valid to add - however you define "something valid" - and only add an item to fullNames if so.
HTH
I'm not really familiar with the AddressBook framework, however this might be what's causing the confusion:
The values you collect in your arrays firstNames, lastNames and organization can be of type NSString or NSNull. You have to do any null-checking within the for-loop, before the fullName-string is constructed.
Remove this useless line:
[fullList removeObjectIdenticalTo: #"<null>"];
And replace the contents of your for-loop with the following code:
for(int i = 0; i < [firstNames count]; i++)
{
NSString *firstName = [firstNames objectAtIndex:i];
NSString *lastName = [lastNames objectAtIndex:i];
NSString *org = [organization objectAtIndex:i];
NSMutableArray *namesArray = [NSMutableArray array];
if ([firstName isKindOfClass:[NSString class]])
[namesArray addObject:firstName];
if ([lastName isKindOfClass:[NSString class]])
[namesArray addObject:lastName];
if ([org isKindOfClass:[NSString class]])
[namesArray addObject:org];
if (namesArray.count > 0)
[fullNames addObject:[namesArray componentsJoinedByString:#" "]];
}

Objective C code debug issue

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.

Having trouble taking an index of an array and making it an NSString

I get an array from a JSON and I parse it into an NSMutableArray (this part is correct and working). I now want to take that array and print the first object to a Label. Here is my code:
NSDictionary *title = [[dictionary objectForKey:#"title"] objectAtIndex:2];
arrayLabel = [title objectForKey:#"label"];
NSLog(#"arrayLabel = %#", arrayLabel); // Returns correct
//Here is where I need help
string = [arrayLabel objectAtIndex:1]; //I do not get the first label (App crashes)
NSLog(#"string = %#", string);
other things that I have already tried are as follows:
string = [NSString stringWithFormat:#"%#", [arrayImage objectAtIndex:1]];
and
string = [[NSString alloc] initWithFormat:#"%#", [arrayImage objectAtIndex:1]];
Any help is greatly appriciated!
EDIT: The app does not return a single value and crashes.
Your code doesn't match the structure of your JSON. In your comment on the deleted answer, you said you got an exception when sending objectAtIndex: to an NSString. In your case, arrayLabel isn't an array when you think it is.
If your JSON has an object, your code needs to treat it as an NSDictionary. Likewise for arrays and NSArray and strings and NSString.
In addition to whatever else was going on, you repeatedly refer to "first" but use the index 1. In most C-based programming languages (and others, as well) the convention is that indexes into arrays are 0-based. So, use index 0 to get the first element.

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

objective-c empty NSArray error

I'm using JSON to parse data into an NSArray 'courseArray'. I then filter this data using NSPredicate and store it into 'rows'. The problem is, i dont know how to determine if 'rows' is empty or not. For example : If a record exists, rows will contain the appropriate objects, but if the record doesnt exist then the application crashes (also when i use NSLog to see the contents of the array its blank, i believe its supposed to say its nil? if there are no objects). How can i fix this?
if (dict)
{
courseArray = [[dict objectForKey:#"lab"] retain];
NSPredicate* predicate = [NSPredicate predicateWithFormat:#"labNumber== %#",labSelected]; //filter
rows = [[courseArray filteredArrayUsingPredicate:predicate]retain];
}
[jsonreturn release];
self.formattedTextView.opaque = NO;
self.formattedTextView.backgroundColor = [UIColor clearColor];
NSLog(#"array %#",rows);
**NSDictionary *currentSelection = [rows objectAtIndex:0];** (app crashes at this line - [NSArray objectAtIndex:]: index 0 beyond bounds for empty array')
NSString *labNumber = [currentSelection objectForKey:#"labNumber"];
-objectAtIndex: will raise an exception if there is no object at the nominated index. If rows is empty there won't be an object at index 0, hence the exception. As you don't catch the exception, the result is that your app is terminated.
You probably want to compare [rows count] to 0 to check that there's something in it and to react appropriately if not.
Try if([courseArray count] > 0) also another method that can be of help here is
[courseArray containsObject:(id)]