Displaying the contents of an NSMutableArray in a UITextView - objective-c

I have this array, NSSMutableArray *myarray, which has five objects in it, and I am using a loop like this:
for( className *myObject in myarray)
{
myTextview.text = [NSString stringWithFormat:#"the name is %#", myObject];
}
When I build and run, only the last name shows in my UITextView *myTextview. I logged it, and my loop is working fine -- it's showing all five objects.
The problem seems to be that each time an object is sent to the myTextView, the next object replaces it; is there a way I can hold all of them, so the whole array can be shown?

Each time you pass the loop you are replacing myTextview.text. What you want is to add to the string each time. Try this:
NSMutableString *string = [NSMutableString string];
for( className *myObject in myarray) {
[string appendString:[NSString stringWithFormat:#"the name is %#\n", myObject]];
}
myTextview.text = string;

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:#" "]];
}

Interpreting a data stream in objective c

I am getting a stream from a live feed. It looks something like this as a mutableArray:
"Columbia Heights",
E04,
"Cleveland Park",
A05
The first line is a name and the second is a station code.
I need to turn this into a dictionary that is Plist compliant.
So the result in mind would look like this:
name:
"Columbia Heights",
code:
E04,
name:
"Cleveland Park",
code:
A05
What I've written so far is this:
NSMutableDictionary *stationDict = [NSMutableDictionary dictionaryWithObjectsAndKeys:#"Name",#"name",#"Code",#"code", nil];
int i = 0;
for (i=0; i < counter; i++) {
// get names and codes for each of 3 fave stations
//[stationArray addObject:[mutableFaveArray objectAtIndex:i]];
NSString *tempName = [mutableFaveArray[i] valueForKey:#"name"];
NSString *tempCode = [mutableFaveArray[i] valueForKey:#"code"];
[stationDict setObject:tempName forKey:#"name"];
[stationDict setObject:tempCode forKey:#"code"];
}
I'm no longer getting an error, but I get as output, the same as my input.. I'm also only getting the last record..
"Cleveland Park",
A05
Updated Code:
NSMutableDictionary *stationDict = [NSMutableDictionary dictionaryWithObjectsAndKeys:#"Name",#"name",#"Code",#"code", nil];
int i = 0;
for (i=0; i < mutableFaveArray.count; i++) {
NSString *tempName = [mutableFaveArray[i] valueForKey:#"name"];
NSString *tempCode = [mutableFaveArray[i] valueForKey:#"code"];
[stationDict setObject:tempName forKey:#"name"];
[stationDict setObject:tempCode forKey:#"code"];
[stationArray addObject:stationDict];
}
This results in the last dictionary entry being saved twice..
{
code = A05;
name = "Cleveland Park";
},
{
code = A05;
name = "Cleveland Park";
}
The problem is that you're only creating a single dictionary, stationDict, before the for loop. You then hit the for loop, which changes the values in stationDict, adds stationDict to the stationArray, changes the values in stationDict again, adds that same dictionary to stationArray, and so on. What you end up with is an array that contains the same object repeated mutableFaveArray.count times.
The solution is to either create a new dictionary at the beginning of the body of the for loop, or add a copy of the dictionary to add to the array. So, either this:
for (i=0; i < mutableFaveArray.count; i++) {
stationDict = [NSMutableDictionary dictionary];
//...continue with the rest of your code...
or this:
//...other for loop code precedes this...
[stationArray addObject:[stationDict copy]];
}
Either approach ensures that each thing you add to the array is a dictionary that's distinct from the others you've added. As a refinement, you could probably speed up the code a little by using a non-mutable dictionary. If you have to create a new dictionary each time through the loop, you can create it with the data you want it to contain rather than changing the objects, so you don't necessarily need it to be mutable. Also, you can declare the loop variable inside the for statement, which ensures that it'll go out of scope as soon as the for terminates. Also, you can use Objective-C's notation for dictionaries:
NSMutableArray *stationArray = [NSMutableArray array];
for (int i=0; i < mutableFaveArray.count; i++) {
[stationArray addObject:#{#"name":mutableFaveArray[i][#"name"],
#"code":mutableFaveArray[i][#"code"]}];
}
You can further abbreviate that and maybe speed it up a bit using fast enumeration:
NSMutableArray *stationArray = [NSMutableArray array];
for (NSDictionary *fave in mutableFaveArray) {
[stationArray addObject:#{#"name":fave[#"name"],
#"code":fave[#"code"]}];
}
Or you can let mutableFaveArray do the enumerating for you:
__block NSMutableArray *stationArray = [NSMutableArray array];
[mutableFaveArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop))
{
[stationArray addObject:#{#"name":obj[#"name"],
#"code":obj[#"code"]}];
}];
That last one might be a bit faster, but perhaps a bit harder to read.

for loop parse newline then equal sign and put it in dictionary

NSString *result
result contains:
NC_AllowedWebHosts=
NC_BgeLAN=br1
NC_Doc=/tmp/dhd=
NC_ExPts=1863==
NC_Redirect=1
[...]
binary_custom=/path/to/directory
blocklist=0
blocklist_url=http://list.g.com/?list=
[...]
I am using this function but i have problems parsing list with double == or triple === for example.
NSArray *strings = [result componentsSeparatedByCharactersInSet:
[NSCharacterSet characterSetWithCharactersInString:#"=\r\n"]];
NSMutableArray *keys = [NSMutableArray new];
NSMutableArray *values = [NSMutableArray new];
for (int i = 0; i+1 < strings.count; i+=2) {
[keys addObject:strings[i]];
[values addObject:strings[i+1]];
}
I would like to parse everything based on new line "\r\n" first then everything that is before the first "=" symbol put in a dictionary key, and everything after up to the new line in a dictionary value. This way I can say get me key "NC_ExPts" and value would return "1863==" and so on. Any help would be appreciated.
#Monolo I can read line-by-line but I don't know how to get values on the first appearance of "=" and put it in values and keys
NSArray *lines = [result componentsSeparatedByCharactersInSet:
[NSCharacterSet characterSetWithCharactersInString:#"\r\n\n"]];
for (NSString* line in lines) {
if (line.length) {
NSLog(#"line: %#", line);
}
}
You need to read the original text line-by-line, then divide each line by only the first "="-sign. With the method you are using, you divide lines and key-value pairs in one go, meaning that you lose too much information about the structure of the data. This is why you are having difficulties handling lines with "==" in them in the value part.
NSString's enumerateLinesUsingBlock: will take care of the first part, and finding the first "=" in each of those lines is easily done with rangeOfString:.

Array Issue in Objective C Xcode

I have a problem with my algorithm for calculating a sore. The user enters a word into the UITextField, and if the word matches a string in the array (#"The Word") the int 'score' will be added by 1.
Then the int score is set as a label as the user gets a word right. (DISPLAYING THE SCORE)
THE PROBLEM, a user can just keep on entering the same word over and over again and the score will keep going up by one. IS there a command for knowing if a word has already been entered, so you can only use the word once.
The Code
NSArray *scoreArray1 = [NSArray arrayWithObjects:
#"Word 1", #"Word 2", #"Word 3", nil];
NSString *inputtwo =_EnterNameText.text;
BOOL isItright = NO;
for(NSString *possible in scoreArray1) {
if([inputtwo isEqual:possible] ) {
isItright = YES;
break;
}
}
if(isItright) {
static int myInt = 0;
myInt++;
NSString *score = [NSString stringWithFormat:#"%d", myInt];
[_scorelabel setText:score];
}
UPDATE!!!!!!
NSArray *scoreArray1 = [NSArray arrayWithObjects:
#"Alan Shearer", #"Shearer", #"Andrew Cole", #"Andy Cole", #"Cole", #"Thierry Henry", #"Henry", #"Robbie Fowler", #"Fowler", #"Frank Lampard", #"Lampard", #"Michael Owen", #"Owen", nil];
NSSet *set2 = [NSSet setWithArray:scoreArray1];
NSString *inputtwo =_EnterNameText.text;
BOOL isItright = NO;
for(NSString *possible in set2) {
if([inputtwo isEqual:possible] ) {
isItright = YES;
break;
}
}
if(isItright) {
static int myInt = 0;
myInt++;
NSString *score = [NSString stringWithFormat:#"%d", myInt];
[_scorelabel setText:score];
}
HOWEVER NOW THE APP DOES NOT WORK, IT CRASHES, any suggestions?
Why don't you keep a second Array where you store the given (correct) answers.
Whit this you can just do a contains inside your if....problem solved.
a second option is not to put string in your array but "Answer" Objects, that have a field that you can flag as already used.
You could just create an NSMutableSet and put a copy of the word into there whenever one is entered. Then you just need to check if the word exists in the set before incrementing the score.
I'm suggesting a set because it uses hashed access, so lookups are fast. Also, if you add the same string more than once, the set will still only have one reference to the string.
Actually, if you have an array of "legal" words, the way to go is to simply remove each word as it's called out, until the array gets to be zero entries long.
NSMutableArray* scoreArrayCopy = [NSMutableArray arrayWithArray:scoreArray];
int originalCount = scoreArrayCopy.count;
...
while (scoreArrayCopy.count > 0) {
NSString* guess = <get next guess>;
[scoreArrayCopy removeObject:guess];
score = originalCount - scoreArrayCopy.count;
}
(If you have a lot of words things would be more efficient if you used an NSMutableSet instead of an NSMutableArray, but the logic would be the same.)

How do you enumerate through an array in Obj-C?

I have an array which has several objects (all of different classes) in it. But using enumeration doesn't work on it for some reason.
NSString *arrayString;
NSURL *arrayUrl;
NSProcessInfo *arrayPr;
NSDictionary *arrayDictionary;
NSMutableString *arrayMString;
NSMutableArray *objectArray = [NSMutableArray arrayWithObjects:arrayString,arrayUrl,arrayPr,arrayDictionary,arrayMString,nil];
for( NSString *item in objectArray ){
NSLog(#"Class name is: %#", [item className]);
}
I think it might be something to do with how the objects are been added to the array but i'm new to objective-c and not sure.
you aren't actually populating the array.
NSString *arrayString;
declares a variable, arrayString, of type NSString. it's not initialized (so it deserves to crash when you use the variable -- but may be 0 with some build settings).
so, to assign a variable:
NSString *arrayString = [NSString stringWithFormat:#"sksjdhf %f\n", 3.3];
arrayWithObjects adds objects from the (va list) argument until nil/null/0 is encountered.
you must set up the remainder of your variables/arguments correctly before using them.
this should work as you expect it to:
NSString * str = #"a string";
NSMutableArray *objectArray = [NSMutableArray arrayWithObjects:str, nil];
for (NSObject * item in objectArray) {
NSLog(#"Class name is: %#", [item className]);
}
In the for loop, use an id data type. The id data type is a general purpose data type that can be used to store a reference to any object.
For example:
for ( id item in objectArray ) {
NSLog(#"Class name is: %#", [item className]);
}
Yep, that's how you do it. If you're having trouble, it is not in the enumeration syntax itself.