Objective-C - unidentified Error in for Loop - iphone

the following code attempts to search for a String given by a cell.textlabel.text in a CSV-File
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//create singleton instance
Globals *myGlobals = [Globals sharedGlobals];
//get searchstring form cell
NSString *stringToFind = [self.tableView cellForRowAtIndexPath:indexPath].textLabel.text;
//get Path of csv and write data in string:allLines
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"ITILcsv" ofType:#"txt"];
if(filePath){
NSString *wholeCSV = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
NSArray *allLines = [wholeCSV componentsSeparatedByString:#"\n"];
//declaration
NSArray *currentArray = nil;
NSString *currentSearchString = nil;
//look for searchstring in 4th line of csv, if found write whole line to a singleton-variable
for (int i=0 ; i < [allLines count]; i++){
currentArray = [[allLines objectAtIndex:i] componentsSeparatedByString:#";"];
currentSearchString = [currentArray objectAtIndex:3];
if ([stringToFind isEqualToString:currentSearchString]){
[myGlobals setCurrentLine:currentArray];
}
}
}
Working quite a bit with csv-files in my current project I'm pretty sure this should work, but somehow the app always crashes when the function is called.
Through a whole bunch of testing I'm pretty sure that the problem is in the following lines:
currentArray = [[allLines objectAtIndex:i] componentsSeparatedByString:#";"];
currentSearchString = [currentArray objectAtIndex:3];
The program works with these two lines commented out, but doesnt implement the desired function ;)
I have no clue what the problem might be?
The Error is a SIGABRT in "main".
Thanks in advance everybody.

Might crash when your currentArray has elements less than 3 and you are referring index 3. So in that case your finding for an index which is out of reach.
So better approach would be
for (int i=0 ; i < [allLines count]; i++)
{
currentArray = [[allLines objectAtIndex:i] componentsSeparatedByString:#";"];
// check and then pick
if ([currentArray count] > 3)
{
currentSearchString = [currentArray objectAtIndex:3];
if ([stringToFind isEqualToString:currentSearchString])
{
[myGlobals setCurrentLine:currentArray];
}
}
}

Related

NSMutableArray Not Retaining Objects Outside Method [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
In my -viewDidLoad method, I initialize many NSMutableDictionaries, and add them to an initialized NSMutableArray declared via #property in the class header file. The relevant code is shown below. In short, I'm webscraping information from an HTML webpage.
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
_regionalDicts = [[NSMutableArray alloc] init];
for (int i = 0; i < [strings count]; i++) {
NSString *str = [strings objectAtIndex:i];
//Property parser:
if ([str rangeOfString:#"<td>"].location != NSNotFound) {
NSString *parsedTD1 = [str stringByReplacingOccurrencesOfString:#"<td>" withString:#""];
NSString *parsedTD2 = [parsedTD1 stringByReplacingOccurrencesOfString:#"</td>" withString:#""];
NSString *parsedTD3 = [parsedTD2 stringByReplacingOccurrencesOfString:#" " withString:#"\n"];
NSString *final = [parsedTD3 stringByReplacingOccurrencesOfString:#"\t" withString:#""];
//NSLog(#"Final string: %#", final);
if ([final isEqualToString:#""]) {
continue;
}
if (gotEventType == NO) {
gotEventType = YES;
[dict setObject:final forKey:#"type"];
continue;
}
if (gotRegional == YES && gotLocation == NO) {
gotLocation = YES;
[dict setObject:final forKey:#"location"];
continue;
}
if (gotLocation == YES && gotCity == NO) {
gotCity = YES;
NSString *cityToReturn = [final stringByReplacingOccurrencesOfString:#"\n" withString:#""];
[dict setObject:cityToReturn forKey:#"city"];
continue;
}
if (gotRegional == YES && gotEventType == YES && gotCity == YES && gotLocation == YES && gotURL == YES) {
gotRegional = NO;
gotEventType = NO;
gotCity = NO;
gotLocation = NO;
gotURL = NO;
NSLog(#"Regional: %#", [dict objectForKey:#"regional"]);
NSLog(#"Type: %#", [dict objectForKey:#"type"]);
NSLog(#"City: %#", [dict objectForKey:#"city"]);
//Testing to see if anything is nil
NSLog(#"Location: %#\n", [dict objectForKey:#"location"]);
if (!_regionalDicts) {
NSLog(#"Dict is nil");
}
[_regionalDicts addObject:dict];
NSLog(#"Objects in array: %u", [_regionalDicts count]);
NSMutableDictionary *tempDict = [_regionalDicts objectAtIndex:[_regionalDicts count]-1];
NSLog(#"Regional in array: %#", [tempDict objectForKey:#"regional"]);
[dict removeAllObjects];
continue;
}
It's clear that the generated dictionaries are generated and retained within the _regionalDicts mutable array, which is declared in the header file like this:
#property (strong, nonatomic) IBOutlet NSMutableArray *regionalDicts;
However, when I attempt to pass in information to table view cells in in the same class, the dictionaries' contents are null. There are as many objects within the array as dictionaries I am expecting, but they do not contain any content.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if (_regionalDicts) {
NSMutableDictionary *dict = [_regionalDicts objectAtIndex:0];
NSLog(#"Setting label %#", [dict objectForKey:#"city"]);
[cell.textLabel setText:[dict objectForKey:#"regional"]];
}
return cell;
}
Returns:
2013-04-01 19:58:50.250 MatchScrape[53570:207] Setting label (null)
I can only imagine that a memory management issue is to blame. Why would the contents of a class array be nullified when accessed outside the scope of the method they are added in, but allow the array to retain the same count?
You seem to believe that adding the dictionary to the array doesn't actually add the dictionary to the array, but instead adds a copy of the dictionary. You're probably thinking of how it might work in a language like C++ — but that isn't how it works here. Remember, Objective-C objects are always accessed by reference: you never directly store the object itself in a variable or array — you're just shuffling around a pointer to the actual object, which usually lives on the heap.
So when you add _dict to the array, the one in the array is the very same object referenced by _dict. Anything you do to that dictionary — no matter what reference you use — will be reflected everywhere else that dictionary is referenced, because it's the same dictionary. You haven't made a copy of it. Thus, when you do [_dict removeAllObjects], that removes all the objects from the dictionary and you end up with an array that contains the same empty dictionary a bunch of times.

keysSortedByValueUsingSelector crashes but sortedArrayUsingSelector runs fine

I found a workaround myself, but still trying to understand the problem.
I created a Autocomplete text field with the use of uitableview which is hidden until textfield is edited. The UI part works fine. It's the searching for the results part that's the problem. I declared a local NSMutableDictionary to store my results because I wanted the results to be sorted by the key's values.
if I call keysSortedByValueUsingSelector on the dictionary directly, it crashes. However if I get the keys by [dict allKeys] first, then call sortedArrayUsingSelector, it works fine:
// This commented out line will crash
// NSArray *sortedKeysArray = [dict keysSortedByValueUsingSelector:#selector(compare:)];
// The next two lines runs fine.
NSArray *keyArray = [dict allKeys];
NSArray *sortedKeysArray = [keyArray sortedArrayUsingSelector:#selector(compare:)];
Here is the complete source code for the search method:
- (void)searchAutocompleteEntriesWithSubstring:(NSString *)substring
{
// Put anything that starts with this substring into the autocompleteUrls array
// The items in this array is what will show up in the table view
[autocomplete_symbol_array removeAllObjects];
rRSIAppDelegate *appDelegate = (rRSIAppDelegate *)([[UIApplication sharedApplication] delegate]);
NSString *input_str = [substring uppercaseString];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
int i = 0;
for(SymbolInfo *symbol_info in appDelegate.m_symbol_info_array)
{
i++;
NSString *info_str = [[[symbol_info.m_symbol uppercaseString] stringByAppendingString:#"|"] stringByAppendingString:[symbol_info.m_company_name uppercaseString]];
NSUInteger pos = [info_str rangeOfString:input_str].location;
if (pos != NSNotFound)
{
int tmp = pos * 10000 + i;
NSNumber *map_key = [[NSNumber alloc] initWithInt:tmp];
[dict setObject:symbol_info forKey:map_key];
}
}
// This commented out line will crash
// NSArray *sortedKeysArray = [dict keysSortedByValueUsingSelector:#selector(compare:)];
// The next two lines runs fine.
NSArray *keyArray = [dict allKeys];
NSArray *sortedKeysArray = [keyArray sortedArrayUsingSelector:#selector(compare:)];
for (NSNumber *key in sortedKeysArray)
{
SymbolInfo *symbol_info = [dict objectForKey:key];
[autocomplete_symbol_array addObject:symbol_info];
}
// NSLog(#"everything added: %d", [autocomplete_symbol_array count]);
[autocompleteTableView reloadData];
}
The NSMutableDictionary's method is:
- (void)setObject:(id)anObject forKey:(id < NSCopying >)aKey;
This means that the key should implement the NSCopying protocol.

Populating UITableView cells

Ok so I have wrote some code in this function:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(#"tableviwcell is getting called");
properties = [NSUserDefaults standardUserDefaults];
NSDictionary *events_dict = [properties objectForKey:#"events_dict"];
NSDictionary *events = [events_dict objectForKey:#"event"];
am_participants = [events objectForKey:#"amParticipants"];
pm_participants = [events objectForKey:#"pmParticipants"];
UITableViewCell *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:#"currentCell"];
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"currentCell"];
}
int sizeofam = [am_participants count];
int sizeofpm = [pm_participants count];
NSMutableArray *participants =[[NSMutableArray alloc] init];
NSLog(#"size of am: %i", sizeofam);
if(sizeofam > 0 && sizeofpm > 0){
for(int i = 0; i < sizeofam; i++){
NSDictionary *ampart_dict = [am_participants objectAtIndex:i];
NSString *ampart_email = [ampart_dict objectForKey:#"email"];
NSString *ampart_email_extra = [#"am" stringByAppendingString:ampart_email];
[participants addObject:ampart_dict];
}
for(int i = 0; i < sizeofpm; i++){
NSDictionary *pmpart_dict = [pm_participants objectAtIndex:i];
NSString *pmpart_email = [pmpart_dict objectForKey:#"email"];
NSString *pmpart_email_extra = [#"pm" stringByAppendingString:pmpart_email];
[participants addObject:pmpart_dict];
NSLog(#"%#", participants);
}
int sizeofparticipants = [participants count];
for(int i = 0; i < sizeofparticipants; i++){
NSString *participanti = [[participants objectAtIndex:i] objectForKey:#"email"];
for(int j = 0; j < sizeofparticipants; j++){
NSString *participantj = [[participants objectAtIndex:j] objectForKey:#"email"];
if([participanti isEqualToString:participantj]){
NSLog(#"Participant j: %#", participantj);
[participants removeObjectAtIndex:j];
sizeofparticipants = [participants count];
}
}
}
Basically I need to merge together the two arrays am_participants and pm_participants in to one array of participants. Each object in the array is a dictionary full of various values such as name, email etc. I then have to remove any duplicate values from the list (for example if someone is in the am list and pm list. I am doing that by removing values if their email address is the same in either list.
After this I need to display the new array of participants called 'participants' in one list by populating the cells with the list of participants.
I have set the number of cells to 30.
However The cells get populated with different names randomly when scrolling down the list as thought the array positions are being moved around aswell as duplicate values appearing.
Can someone explain what I am doing wrong?
Thanks!
the cell assignment code is not mentioned above but i assume that you are assigning values from participants as your cell's content as explained. The problem is you are creating your array inside cellForRowAtIndexPath:. This method gets called every time a new cell is to be displayed, thus, you are recreating your participants for every row. You need to move the code you have above to viewDidLoad or viewDidAppear.

Xml parsing in Iphone and adding values to NSMutableArray

I am new to xml parsing. I have the following xml
<myMainList>
<mySubList>
<edited>true</edited>
<mySharedNumber>W59QYBZKJ4</mySharedNumber>
</mySubList>
<mySubList>
<edited>false</edited>
<mySharedNumber>TOW4KLP9WD</mySharedNumber>
</mySubList>
<mySubList>
<edited>true</edited>
<mySharedNumber>XH8JDIZA64</mySharedNumber>
</mySubList>
<mySubList>
<edited>false</edited>
<mySharedNumber>V2YOHSNODT</mySharedNumber>
</mySubList>
</myMainList>
I have edited my question.
I am not familiar with looping through the whole xml and adding the values into my array. Can someone show me how I can add the 4 sharedNumberList values into my array.
Edit:
GDataXMLElement *node;
NSArray * array = [node nodesForXPath:#"//return/myMainList/mySubList" error:nil];
NSLog(#"count :%d",[array count]);
int sharedContacts = [array count];
NSMutableArray *mySharedListArray = [[NSMutableArray alloc]init];
for(int i = 1; i<= sharedContacts; i++){
NSString *xmlDataFetcher = [NSString stringWithFormat:#"//return/myMainList/mySubList[%d]",i ];
NSString *parsedNumbers = [node nodeStringForXPath:[xmlDataFetcher stringByAppendingString:#"/mySharedNumber"]];
NSString *parsedEdit = [node nodeStringForXPath:[xmlDataFetcher stringByAppendingString:#"/edited"]];
NSLog(#"Parsed Edited %#", [node nodeStringForXPath:[xmlDataFetcher stringByAppendingString:#"/edited"]]);
NSLog(#"Parsed sharedNumber %#", [node nodeStringForXPath:[xmlDataFetcher stringByAppendingString:#"/mySharedNumber"]]);
NSString *arrayEntry = [NSString stringWithFormat:#"%#%#", parsedNumbers, parsedEdit];;
[mySharedListArray addObject:arrayEntry];
}
NSLog(#"Array entry %#", mySharedListArray);
I have added a lot of NSLog in the answer, so that you could log it as you wish
I haven't done this most probably this is returning an array from the xpath query so Try this instead
[mySharedListArray addObjectsFromArray:[node nodesForXPath:#"//return/MyList" error:nil]];

Problem with isEqualToString: method and NSInteger

This is my code:
for (int i=0; i<countingArray.count; i++) {
NSDictionary *element=[countingArray objectAtIndex:i];
NSString *source=[element objectForKey:#"id"];
NSInteger count= [[element objectForKey:#"count"] integerValue];
NSLog("source: %#",source); //Works
NSLog("count %d",count); //Don't Work! Error at this line
for(int c=0; c<subscriptions.count; c++) {
SubscriptionArray * element =[subscriptions objectAtIndex:c];
NSLog(#"sorgente sub %#",element.source);
NSLog(#"sorgente counting %#",source);
if([source isEqualToString:element.source]) {
element.count=count;
[subscriptions replaceObjectAtIndex:c withObject:element];
NSLog(#"equal");
//this part of code is never been executed but I'm sure that
//the if condition in some cases returns true
}
}
}
When I try to NSLog("count %d",count); my app crash without any information about.
I've also another problem with if([source isEqualToString:element.source]) I'm sure that some times the condition return true... How can I remove blank space? Like the trim function in php? thanks
Change:
NSString *source=[element objectForKey:#"id"];
NSInteger count= [[element objectForKey:#"count"] integerValue];
to:
NSString *source=[element valueForKey:#"id"];
NSInteger count= [[element valueForKey:#"count"] integerValue];
For removing blank spaces you can try:
NSString *trimmedString = [yourString stringByReplacingOccurrencesOfString:#" " withString:#""];
I didn't notice the first two NSLog statements. They're both of the form NSLog("something: %#", something). That is a C string literal, whereas NSLog takes an NSString for its format. This will lead to a crash. You want NSLog(#"source: %#", source).