connecting strings - iphone

This is my code for connecting different NSNumbers from an array to one string. But for some reason I get a weird result in the watch area. The result of the NSLog is fine. Maybe you can help?
for (int i = 0; i < [ViewController sharedInstance].safeZonesUserList.count; i++) {
int userIndex = [[[ViewController sharedInstance].safeZonesUserList objectAtIndex:i] intValue];
NSString *arrayValue = [NSString stringWithFormat:#"%d",userIndex];
usersList = [usersList stringByAppendingString:arrayValue];
if (i < ([ViewController sharedInstance].safeZonesUserList.count - 1)) {
usersList = [usersList stringByAppendingString:#","];
}
}
My array holds 1 and 2, but the result I get in the watch area is: "1,2;\x8c\a#\x01\x03206"
Thanks,

You can replace your example with one line of code:
NSString* usersListAsString = [[ViewController sharedInstance].safeZonesUserList componentsJoinedByString:#","] ;
componentsJoinedByString gets the descriptions of every item in your NSArray, replacing the first 2 lines of code within your loop. Then it combines the descriptions into one NSString with your specified string (",") in-between them, replacing your example's lines 3 - 5.

Related

Performance issue creating Section Index Titles for UITableView

I'm displaying an array of contacts ( [[ContactStore sharedStore]allContacts] ) in a tableview and have divided the list into alphabetic sections. I have used the following code to return an array of the first letters of the contacts, and a dictionary of the number of entries per letter.
//create an array of the first letters of the names in the sharedStore
nameIndex = [[NSMutableArray alloc] init];
//create a dictionary to save the number of names for each first letter
nameIndexCount = [[NSMutableDictionary alloc]init];
for (int i=0; i<[[[ContactStore sharedStore]allContacts]count]; i++){
//Get the first letter and the name of each person
Contact *p = [[[ContactStore sharedStore]allContacts]objectAtIndex:i];
NSString *lastName = [p lastName];
NSString *alphabet = [lastName substringToIndex:1];
//If that letter is absent from the dictionary then add it and set its value as 1
if ([nameIndexCount objectForKey:alphabet] == nil) {
[nameIndex addObject:alphabet];
[nameIndexCount setValue:#"1" forKey:alphabet];
//If its already present add one to its value
} else {
NSString *newValue = [NSString stringWithFormat:#"%d", ([[nameIndexCount valueForKey:alphabet] intValue] + 1)];
[nameIndexCount setValue:newValue forKey:alphabet];
}
}
This works, however it is very slow when the array is large, I'm sure there's a better way to do this but I'm quite new to this so am not sure how. Are there any suggestions for a better way to do this?
Although Bio Cho has a good point, you might see an increase in performance by calling
[[ContactStore sharedStore]allContacts]
only once. For example:
nameIndex = [[NSMutableArray alloc] init];
nameIndexCount = [[NSMutableDictionary alloc] init];
/*
Create our own copy of the contacts only once and reuse it
*/
NSArray* allContacts = [[ContactStore sharedStore] allContacts];
for (int i=0; i<[allContacts count]; i++){
//Get the first letter and the name of each person
Contact *p = allContacts[i];
NSString *lastName = [p lastName];
NSString *alphabet = [lastName substringToIndex:1];
//If that letter is absent from the dictionary then add it and set its value as 1
if ([nameIndexCount objectForKey:alphabet] == nil) {
[nameIndex addObject:alphabet];
[nameIndexCount setValue:#"1" forKey:alphabet];
//If its already present add one to its value
} else {
NSString *newValue = [NSString stringWithFormat:#"%d", ([[nameIndexCount
valueForKey:alphabet] intValue] + 1)];
[nameIndexCount setValue:newValue forKey:alphabet];
}
}
Though I can't say for sure, I'd guess that repeatedly accessing your shared store is what's killing you. Maybe only accessing it once will give you what you need.
Consider storing your contacts in Core Data and using an NSFetchedResultsController.
The NSFetchedResultsController will only load a subset of the rows which are visible on the table view, thus preventing your user from having to wait for all the contacts to be sorted.
NSFetchedResultsController will also sort your contacts by an attribute (ie. first or last name), and you can set your section titles to be the first letter of the field you're sorting by.
Take a look at this question and this tutorial.

Adding items to NSMutableArray not working

I am trying to create an array of numbers that I will use later to determin the size of my tableviewcells.
However I am having some issues with the array, After my while statment it comes back as being NULL, yet when I log the values I am getting from my array of objects they are correct... and the if statement works perfectly.
This is my code
int count = 0;
// Cell heights
int smallCell = 69;
int largeCell = 120;
NSNumber *currentHeight = [[NSNumber alloc] init]; // allows int to be stored into NSArray
while (count < seriesSearchArray.count) {
myObj = (SeriesSearchResultItem*)[dataArrayOfObjects objectAtIndex:count];
if (![myObj.seriesNote isEqualToString:#""]) {
NSLog(#"%#", myObj.seriesNote);
currentHeight = [NSNumber numberWithInt:largeCell];
NSLog(#"%#", currentHeight); // correct value shown
[heightArray addObject:currentHeight];
}
else {
currentHeight = [NSNumber numberWithInt:smallCell];
NSLog(#"%#", currentHeight); // correct value shown
[heightArray addObject:currentHeight];
}
NSLog(#"%#", heightArray); // NULL Shown
count ++;
}
So thats if, I am trying to get the value from each of the objects in my array which works, the if statment works perfectly but then when I try to add them to my new array it always comes back as NULL.
Moving comment to answer
You need something like
heightArray = [NSMutableArray arrayWithCapacity:seriesSearchArray.count]

Regex pattern and/or NSRegularExpression a bit too slow searching over very large file, can it be optimized?

In an iOS framework, I am searching through this 3.2 MB file for pronunciations: https://cmusphinx.svn.sourceforge.net/svnroot/cmusphinx/trunk/pocketsphinx/model/lm/en_US/cmu07a.dic
I am using NSRegularExpression to search for an arbitrary set of words that are given as an NSArray. The search is done through the contents of the large file as an NSString. I need to match any word that appears bracketed by a newline and a tab character, and then grab the whole line, for example if I have the word "monday" in my NSArray I want to match this line within the dictionary file:
monday M AH N D IY
This line starts with a newline, the string "monday" is followed by a tab character, and then the pronunciation follows. The entire line needs to be matched by the regex for its ultimate output. I also need to find alternate pronunciations of the words which are listed as follows:
monday(2) M AH N D EY
The alternative pronunciations always begin with (2) and can go as high as (5). So I also search for iterations of the word followed by parentheses containing a single number bracketed by a newline and a tab character.
I have a 100% working NSRegularExpression method as follows:
NSArray *array = [NSArray arrayWithObjects:#"friday",#"monday",#"saturday",#"sunday", #"thursday",#"tuesday",#"wednesday",nil]; // This array could contain any arbitrary words but they will always be in alphabetical order by the time they get here.
// Use this string to build up the pattern.
NSMutableString *mutablePatternString = [[NSMutableString alloc]initWithString:#"^("];
int firstRound = 0;
for(NSString *word in array) {
if(firstRound == 0) { // this is the first round
firstRound++;
} else { // After the first iteration we need an OR operator first.
[mutablePatternString appendString:[NSString stringWithFormat:#"|"]];
}
[mutablePatternString appendString:[NSString stringWithFormat:#"(%#(\\(.\\)|))",word]];
}
[mutablePatternString appendString:#")\\t.*$"];
// This results in this regex pattern:
// ^((change(\(.\)|))|(friday(\(.\)|))|(monday(\(.\)|))|(saturday(\(.\)|))|(sunday(\(.\)|))|(thursday(\(.\)|))|(tuesday(\(.\)|))|(wednesday(\(.\)|)))\t.*$
NSRegularExpression * regularExpression = [NSRegularExpression regularExpressionWithPattern:mutablePatternString
options:NSRegularExpressionAnchorsMatchLines
error:nil];
int rangeLocation = 0;
int rangeLength = [string length];
NSMutableArray * matches = [NSMutableArray array];
[regularExpression enumerateMatchesInString:string
options:0
range:NSMakeRange(rangeLocation, rangeLength)
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop){
[matches addObject:[string substringWithRange:result.range]];
}];
[mutablePatternString release];
// matches array is returned to the caller.
My issue is that given the big text file, it isn't really fast enough on the iPhone. 8 words take 1.3 seconds on an iPhone 4, which is too long for the application. Given the following known factors:
• The 3.2 MB text file has the words to match listed in alphabetical order
• The array of arbitrary words to look up are always in alphabetical order when they get to this method
• Alternate pronunciations start with (2) in parens after the word, not (1)
• If there is no (2) there won't be a (3), (4) or more
• The presence of one alternative pronunciation is rare, occurring maybe 1 time in 8 on average. Further alternate pronunciations are even rarer.
Can this method be optimized, either by improving the regex or some aspect of the Objective-C? I'm assuming that NSRegularExpression is already optimized enough that it isn't going to be worthwhile trying to do it with a different Objective-C library or in C, but if I'm wrong here let me know. Otherwise, very grateful for any suggestions on improving the performance. I am hoping to make this generalized to any pronunciation file so I'm trying to stay away from solutions like calculating the alphabetical ranges ahead of time to do more constrained searches.
****EDIT****
Here are the timings on the iPhone 4 for all of the search-related answers given by August 16th 2012:
dasblinkenlight's create NSDictionary approach https://stackoverflow.com/a/11958852/119717: 5.259676 seconds
Ωmega's fastest regex at https://stackoverflow.com/a/11957535/119717: 0.609593 seconds
dasblinkenlight's multiple NSRegularExpression approach at https://stackoverflow.com/a/11969602/119717: 1.255130 seconds
my first hybrid approach at https://stackoverflow.com/a/11970549/119717: 0.372215 seconds
my second hybrid approach at https://stackoverflow.com/a/11970549/119717: 0.337549 seconds
The best time so far is the second version of my answer. I can't mark any of the answers best, since all of the search-related answers informed the approach that I took in my version so they are all very helpful and mine is just based on the others. I learned a lot and my method ended up a quarter of the original time so this was enormously helpful, thank you dasblinkenlight and Ωmega for talking it through with me.
Since you are putting the entire file into memory anyway, you might as well represent it as a structure that is easy to search:
Create a mutable NSDictionary words, with NSString keys and NSMutableArray values
Read the file into memory
Go through the string representing the file line-by-line
For each line, separate out the word part by searching for a '(' or a '\t' character
Get a sub-string for the word (from zero to the index of the '(' or '\t' minus one); this is your key.
Check if the words contains your key; if it does not, add new NSMutableArray
Add line to the NSMutableArray that you found/created at the specific key
Once your are finished, throw away the original string representing the file.
With this structure in hand, you should be able to do your searches in time that no regex engine would be able to match, because you replaced a full-text scan, which is linear, with a hash look-up, which is constant-time.
** EDIT: ** I checked the relative speed of this solution vs. regex, it is about 60 times faster on a simulator. This is not at all surprising, because the odds are stacked heavily against the regex-based solution.
Reading the file:
NSBundle *bdl = [NSBundle bundleWithIdentifier:#"com.poof-poof.TestAnim"];
NSString *path = [NSString stringWithFormat:#"%#/words_pron.dic", [bdl bundlePath]];
data = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
NSMutableDictionary *tmp = [NSMutableDictionary dictionary];
NSUInteger pos = 0;
NSMutableCharacterSet *terminator = [NSMutableCharacterSet characterSetWithCharactersInString:#"\t("];
while (pos != data.length) {
NSRange remaining = NSMakeRange(pos, data.length-pos);
NSRange next = [data
rangeOfCharacterFromSet:[NSCharacterSet newlineCharacterSet]
options:NSLiteralSearch
range:remaining
];
if (next.location != NSNotFound) {
next.length = next.location - pos;
next.location = pos;
} else {
next = remaining;
}
pos += (next.length+1);
NSString *line = [data substringWithRange:next];
NSRange keyRange = [line rangeOfCharacterFromSet:terminator];
keyRange.length = keyRange.location;
keyRange.location = 0;
NSString *key = [line substringWithRange:keyRange];
NSMutableArray *array = [tmp objectForKey:key];
if (!array) {
array = [NSMutableArray array];
[tmp setObject:array forKey:key];
}
[array addObject:line];
}
dict = tmp; // dict is your NSMutableDictionary ivar
Searching:
NSArray *keys = [NSArray arrayWithObjects:#"sunday", #"monday", #"tuesday", #"wednesday", #"thursday", #"friday", #"saturday", nil];
NSMutableArray *all = [NSMutableArray array];
NSLog(#"Starting...");
for (NSString *key in keys) {
for (NSString *s in [dict objectForKey:key]) {
[all addObject:s];
}
}
NSLog(#"Done! %u", all.count);
Try this one:
^(?:change|monday|tuesday|wednesday|thursday|friday|saturday|sunday)(?:\([2-5]\))?\t.*$
and also this one (using positive lookahead with list of possible first letters):
^(?=[cmtwfs])(?:change|monday|tuesday|wednesday|thursday|friday|saturday|sunday)(?:\([2-5]\))?\t.*$
and at the end, a version with some optimization:
^(?=[cmtwfs])(?:change|monday|t(?:uesday|hursday)|wednesday|friday|s(?:aturday|unday))(?:\([2-5]\))?\t.*$
Here is my hybrid approach of dasblinkenlight's and Ωmega's answers, which I thought I should add as an answer as well at this point. It uses dasblinkenlight's method of doing a forward search through the string and then performs the full regex on a small range in the event of a hit, so it exploits the fact that the dictionary and words to look up are both in alphabetical order and benefits from the optimized regex. Wish I had two best answer checks to give out! This gives the correct results and takes about half of the time of the pure regex approach on the Simulator (I have to test on the device later to see what the time comparison is on the iPhone 4 which is the reference device):
NSMutableArray *mutableArrayOfWordsToMatch = [[NSMutableArray alloc] initWithArray:array];
NSMutableArray *mutableArrayOfUnfoundWords = [[NSMutableArray alloc] init]; // I also need to know the unfound words.
NSUInteger pos = 0;
NSMutableString *mutablePatternString = [[NSMutableString alloc]initWithString:#"^(?:"];
int firstRound = 0;
for(NSString *word in array) {
if(firstRound == 0) { // this is the first round
firstRound++;
} else { // this is all later rounds
[mutablePatternString appendString:[NSString stringWithFormat:#"|"]];
}
[mutablePatternString appendString:[NSString stringWithFormat:#"%#",word]];
}
[mutablePatternString appendString:#")(?:\\([2-5]\\))?\t.*$"];
// This creates a string that reads "^(?:change|friday|model|monday|quidnunc|saturday|sunday|thursday|tuesday|wednesday)(?:\([2-5]\))?\t.*$"
// We don't want to instantiate the NSRegularExpression in the loop so let's use a pattern that matches everything we're interested in.
NSRegularExpression * regularExpression = [NSRegularExpression regularExpressionWithPattern:mutablePatternString
options:NSRegularExpressionAnchorsMatchLines
error:nil];
NSMutableArray * matches = [NSMutableArray array];
while (pos != data.length) {
if([mutableArrayOfWordsToMatch count] <= 0) { // If we're at the top of the loop without any more words, stop.
break;
}
NSRange remaining = NSMakeRange(pos, data.length-pos);
NSRange next = [data
rangeOfString:[NSString stringWithFormat:#"\n%#\t",[mutableArrayOfWordsToMatch objectAtIndex:0]]
options:NSLiteralSearch
range:remaining
]; // Just search for the first pronunciation.
if (next.location != NSNotFound) {
// If we find the first pronunciation, run the whole regex on a range of {position, 500} only.
int rangeLocation = next.location;
int searchPadding = 500;
int rangeLength = searchPadding;
if(data.length - next.location < searchPadding) { // Only use 500 if there is 500 more length in the data.
rangeLength = data.length - next.location;
}
[regularExpression enumerateMatchesInString:data
options:0
range:NSMakeRange(rangeLocation, rangeLength)
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop){
[matches addObject:[data substringWithRange:result.range]];
}]; // Grab all the hits at once.
next.length = next.location - pos;
next.location = pos;
[mutableArrayOfWordsToMatch removeObjectAtIndex:0]; // Remove the word.
pos += (next.length+1);
} else { // No hits.
[mutableArrayOfUnfoundWords addObject:[mutableArrayOfWordsToMatch objectAtIndex:0]]; // Add to unfound words.
[mutableArrayOfWordsToMatch removeObjectAtIndex:0]; // Remove from the word list.
}
}
[mutablePatternString release];
[mutableArrayOfUnfoundWords release];
[mutableArrayOfWordsToMatch release];
// return matches to caller
EDIT: here is another version which uses no regex and shaves a little bit more time off of the method:
NSMutableArray *mutableArrayOfWordsToMatch = [[NSMutableArray alloc] initWithArray:array];
NSMutableArray *mutableArrayOfUnfoundWords = [[NSMutableArray alloc] init]; // I also need to know the unfound words.
NSUInteger pos = 0;
NSMutableArray * matches = [NSMutableArray array];
while (pos != data.length) {
if([mutableArrayOfWordsToMatch count] <= 0) { // If we're at the top of the loop without any more words, stop.
break;
}
NSRange remaining = NSMakeRange(pos, data.length-pos);
NSRange next = [data
rangeOfString:[NSString stringWithFormat:#"\n%#\t",[mutableArrayOfWordsToMatch objectAtIndex:0]]
options:NSLiteralSearch
range:remaining
]; // Just search for the first pronunciation.
if (next.location != NSNotFound) {
NSRange lineRange = [data lineRangeForRange:NSMakeRange(next.location+1, next.length)];
[matches addObject:[data substringWithRange:NSMakeRange(lineRange.location, lineRange.length-1)]]; // Grab the whole line of the hit.
int rangeLocation = next.location;
int rangeLength = 750;
if(data.length - next.location < rangeLength) { // Only use the searchPadding if there is that much room left in the string.
rangeLength = data.length - next.location;
}
rangeLength = rangeLength/5;
int newlocation = rangeLocation;
for(int i = 2;i < 6; i++) { // We really only need to do this from 2-5.
NSRange morematches = [data
rangeOfString:[NSString stringWithFormat:#"\n%#(%d",[mutableArrayOfWordsToMatch objectAtIndex:0],i]
options:NSLiteralSearch
range:NSMakeRange(newlocation, rangeLength)
];
if(morematches.location != NSNotFound) {
NSRange moreMatchesLineRange = [data lineRangeForRange:NSMakeRange(morematches.location+1, morematches.length)]; // Plus one because I don't actually want the line break at the beginning.
[matches addObject:[data substringWithRange:NSMakeRange(moreMatchesLineRange.location, moreMatchesLineRange.length-1)]]; // Minus one because I don't actually want the line break at the end.
newlocation = morematches.location;
} else {
break;
}
}
next.length = next.location - pos;
next.location = pos;
[mutableArrayOfWordsToMatch removeObjectAtIndex:0]; // Remove the word.
pos += (next.length+1);
} else { // No hits.
[mutableArrayOfUnfoundWords addObject:[mutableArrayOfWordsToMatch objectAtIndex:0]]; // Add to unfound words.
[mutableArrayOfWordsToMatch removeObjectAtIndex:0]; // Remove from the word list.
}
}
[mutableArrayOfUnfoundWords release];
[mutableArrayOfWordsToMatch release];
Looking at the dictionary file you provided, I'd say that a reasonable strategy could be reading in the data and putting it into any sort of persistent data store.
Read through the file and create objects for each unique word, with n strings of pronunciations (where n is the number of unique pronunciations). The dictionary is already in alphabetical order, so if you parsed it in the order that you're reading it you'd end up with an alphabetical list.
Then you can do a binary search on the data - even with a HUGE number of objects a binary search will find what you're looking for very quickly (assuming alphabetical order).
You could probably even keep the whole thing in memory if you need lightning-fast performance.

Filtering an NSArray from JSON?

I'm trying to implement a searchable tableview in my app, where when someone can search a location and get results. It looks something like this:
I'm getting my source from genomes.com which gives more then just cities, it also has parks, buildings, counties, etc. I want to just show locations which are cities.
The data is a JSON file which is parsed by JSONKit. The whole file comes in (maximum 20 objects) and then the searchable table view shows it. I'm not sure if I should parse the JSON file differently, or if I should make the table view show only the results needed. (Performance in this case is not an issue.). The JSON file gets converted to an NSArray.
Here is part of the array:
{
adminCode1 = MA;
adminCode2 = 027;
adminName1 = Massachusetts;
adminName2 = "Worcester County";
adminName3 = "";
adminName4 = "";
adminName5 = "";
continentCode = NA;
countryCode = US;
countryName = "United States";
elevation = 178;
fcl = A;
fclName = "country, state, region,...";
fcode = ADMD;
fcodeName = "administrative division";
geonameId = 4929431;
lat = "42.2000939";
lng = "-71.8495163";
name = "Town of Auburn";
population = 0;
score = "53.40083694458008";
timezone = {
dstOffset = "-4";
gmtOffset = "-5";
timeZoneId = "America/New_York";
};
toponymName = "Town of Auburn";
},
What I want to do is if the "fcl" (seen in the array) is equal to P, then I want it to show that in the table view. If the "fcl" is some other character, then I don't want it to be seen in the table view. I'm pretty sure that an if statement can do that, but I don't know how to get it so that it filters part of it.
Any help would be appreciated! Thanks
EDIT: As of now, this is the code to search:
- (void)delayedSearch:(NSString*)searchString
{
[self.geoNamesSearch cancel];
[self.geoNamesSearch search:searchString
maxRows:20
startRow:0
language:nil];
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
self.searchDisplayController.searchBar.prompt = NSLocalizedStringFromTable(#"ILGEONAMES_SEARCHING", #"ILGeoNames", #"");
[self.searchResults removeAllObjects];
// Delay the search 1 second to minimize outstanding requests
[NSObject cancelPreviousPerformRequestsWithTarget:self];
[self performSelector:#selector(delayedSearch:) withObject:searchString afterDelay:0];
return YES;
}
Your question is basically, how do you filter your array from a search bar string? If so, you can detect when the text changes via UISearchBarDelegate and then go through your array copying those objects that contain the string you are looking for, i.e.
This is the delegate method you want: searchBar:textDidChange:.
[filterArray removeAllObjects];
for(int i = 0; i < [normalArray count]; i++){
NSRange textRange;
textRange =[[[[normalArray objectAtIndex:i] objectForKey:#"name"] lowercaseString] rangeOfString:[searchBarString lowercaseString]];
//I wasn't sure which objectForKey: string you were looking for, just replace the one you want to filter.
if(textRange.location != NSNotFound)
{
[filterArray addObject:[normalArray objectAtIndex:i]];
}
}
filterTableView = YES;
[tableView reloadData];
Note the filterTableView bool value, this is so your tableView knows either to load normally or the filtered version you just made. You implement this in:
tableView:numberOfRowsInSection: //For number of rows.
tableView:cellForRowAtIndexPath: //For the content of the cells.
Hope this is what you were looking for.
NSMutableArray* filtered = [[NSMutableArray alloc] autorelease];
for (int i=0;i<[data count];i++)
{
NSDictionary* item=[data objectAtIndex:i];
if (#"P" == [item objectForKey:#"fcl"] )
{
[filtered addObject:item];
}
}
So every time the search field changes, you will compute a new array, and then reload your tableview. The number of rows will be the numbers of rows in your filtered array.
To compute the new array, you can do this (assuming an array of dictionaries):
NSString *searchString; // from the search field
NSMutableArray *array = [NSMutableArray arrayWithCapacity:[origArray count]];
for(NSDictionary *dict in origArray) {
NSString *val = [dict objectForKey:#"fcl"];
if([val length] >= searchString) {
NSString subString = [val substringToIndex:[searchString length]];
if([subString isEqualToString:val]) [array addObject:dict];
}
}
Each cell then will get its values from the new array.
Just put your json in a NSDictionary and simply do something like :
if ([[yourJson objectForKey:#"fcl"] stringValue] == #"A")
//doSomething

Why doesn't this for loop execute?

I have a picker view controller to select a chemical source and possibly a concentration. If the source doesn't have concentrations, it just presents a single picker. It gets populated by an NSDictionary with source type names as keys and a custom model object I made called Chemical that has four properties, two NSString, one float and one BOOL.
When I trigger this with dictionary that has 2 components, I want to extract the four values from the Chemical that is represented. Note that I populate the picker with values from the first two properties, but not the float or BOOL. I run through the array for the key that's selected in the first component and check the string from the second component against the chemConcentration property from each of the Chemicals in the key/value array. When the chemConcentration matches, I know I have the right Chemical and I can get its properties to send back.
Whew!
The problem is that even though I know I get to the for loop, it seems to get skipped. The NSLog right before it prints, but the one inside doesn't. sourceConstant and sourceIsLiquid stay 0.0 and NO
- (IBAction)selectedSourceButton {
NSLog(#"selectedSourceButton pressed");
NSInteger sourceRow = [picker selectedRowInComponent:kSourceComponent];
NSString *selectedSource = [self.sources objectAtIndex:sourceRow];
NSArray *selectedChemicalGroup = [dictionaryOfSources objectForKey:selectedSource];
NSInteger concentrationRow = [picker selectedRowInComponent:kConcentrationComponent];
NSString *selectedConcentration = [[NSString alloc] init];
float selectedConstant = 0.0;
BOOL selectedIsLiquid = NO;
if (numberOfComponents == 2) {
NSLog(#"numberOfComponents = 2 if/then chosen"); // <-- This prints.
selectedConcentration = [self.concentrations objectAtIndex:concentrationRow];
NSLog(#"begin selectedConcentration for loop. Number of loops = %d", [selectedChemicalGroup count]); // <-- And so does this.
for (int i; i<[selectedChemicalGroup count]; i++) { // <-- But this doesn't seem to fire!
NSLog(#"selectedConcentration = %#, from selectedChemicalGroup = %#", selectedConcentration, [[selectedChemicalGroup objectAtIndex:i] chemConcentration]); // <-- Because this doesn't print.
if ([selectedConcentration isEqualToString:[[selectedChemicalGroup objectAtIndex:i] chemConcentration]]) {
selectedConstant = [[selectedChemicalGroup objectAtIndex:i] chemConstant];
selectedIsLiquid = [[selectedChemicalGroup objectAtIndex:i] chemIsLiquid];
}
}
}
else {
selectedConcentration = #"";
selectedConstant = [[selectedChemicalGroup objectAtIndex:0] chemConstant];
selectedIsLiquid = [[selectedChemicalGroup objectAtIndex:0] chemIsLiquid];
}
NSLog(#"selectedSourceButton source to return = %#, concentration = %#, sourceConstant = %1.7f, isLiquid = %d", selectedSource, selectedConcentration, selectedConstant, selectedIsLiquid);
if ([self.delegate respondsToSelector:#selector (sourcePickerViewController:didSelectSource:andConcentration:andConstant:andIsLiquid:)]) {
[self.delegate sourcePickerViewController:self didSelectSource:selectedSource andConcentration:selectedConcentration andConstant:selectedConstant andIsLiquid:selectedIsLiquid];
}
}
You need to initialize your variable i: for (int i = 0; ...
But there's a better way to do this, using "fast enumeration":
for (MyChemicalGroupClass *group in selectedChemicalGroup) {
if ([selectedConcentration isEqualToString:[group chemConcentration]]) {
...
}
}
Initialize loop count i
for (int i = 0; i<[selectedChemicalGroup count]; i++)
Do the following and you will understand why:
int i;
NSLog(#"%d", i);