I'm getting these errors in the console:
2010-01-07 18:15:19.036 FlagLearner[13310:207] *** -[NSCFString objectForKey:]: unrecognized selector sent to instance 0x3814530
2010-01-07 18:15:19.039 FlagLearner[13310:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSCFString objectForKey:]: unrecognized selector sent to instance 0x3814530'
2010-01-07 18:15:19.047 FlagLearner[13310:207] Stack: (
I have no warnings, no build errors, and no analyzer results whatsoever. Yet, it crashes! Can anyone figure out why?
Feel free to email me at █████████████#gmail.com if you want me to send you the source to take a look at.
Here's the implementation file:
//
// RootViewController.m
// Pop,Cap,Flag!
//
// Created by Samstrix Apps on 6/01/10.
// Copyright __MyCompanyName__ 2010. All rights reserved.
//
#import "RootViewController.h"
#import "Pop_Cap_Flag_AppDelegate.h"
#import "DetailViewController.h"
#implementation RootViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"here1");
//init array
listOfItems = [[NSMutableArray alloc] init];
//add items
NSLog(#"here2");
NSString *filePathA = [[NSBundle mainBundle] pathForResource:#"A" ofType:#"txt"];
NSString *myTextA= [NSString stringWithContentsOfFile:filePathA encoding:NSUTF8StringEncoding error:nil];
NSArray *arrayStructuresA = [myTextA componentsSeparatedByString:#"-"];
NSLog(#"here3");
NSString *filePathB = [[NSBundle mainBundle] pathForResource:#"B" ofType:#"txt"];
NSString *myTextB= [NSString stringWithContentsOfFile:filePathB encoding:NSUTF8StringEncoding error:nil];
NSArray *arrayStructuresB = [myTextB componentsSeparatedByString:#"-"];
NSString *filePathC = [[NSBundle mainBundle] pathForResource:#"C" ofType:#"txt"];
NSString *myTextC= [NSString stringWithContentsOfFile:filePathC encoding:NSUTF8StringEncoding error:nil];
NSArray *arrayStructuresC = [myTextC componentsSeparatedByString:#"-"];
NSString *filePathD = [[NSBundle mainBundle] pathForResource:#"D" ofType:#"txt"];
NSString *myTextD= [NSString stringWithContentsOfFile:filePathD encoding:NSUTF8StringEncoding error:nil];
NSArray *arrayStructuresD = [myTextD componentsSeparatedByString:#"-"];
NSString *filePathE = [[NSBundle mainBundle] pathForResource:#"E" ofType:#"txt"];
NSString *myTextE= [NSString stringWithContentsOfFile:filePathE encoding:NSUTF8StringEncoding error:nil];
NSArray *arrayStructuresE = [myTextE componentsSeparatedByString:#"-"];
NSString *filePathF = [[NSBundle mainBundle] pathForResource:#"F" ofType:#"txt"];
NSString *myTextF= [NSString stringWithContentsOfFile:filePathF encoding:NSUTF8StringEncoding error:nil];
NSArray *arrayStructuresF = [myTextF componentsSeparatedByString:#"-"];
NSString *filePathG = [[NSBundle mainBundle] pathForResource:#"G" ofType:#"txt"];
NSString *myTextG= [NSString stringWithContentsOfFile:filePathG encoding:NSUTF8StringEncoding error:nil];
NSArray *arrayStructuresG = [myTextG componentsSeparatedByString:#"-"];
NSString *filePathH = [[NSBundle mainBundle] pathForResource:#"H" ofType:#"txt"];
NSString *myTextH= [NSString stringWithContentsOfFile:filePathH encoding:NSUTF8StringEncoding error:nil];
NSArray *arrayStructuresH = [myTextH componentsSeparatedByString:#"-"];
NSString *filePathI = [[NSBundle mainBundle] pathForResource:#"I" ofType:#"txt"];
NSString *myTextI= [NSString stringWithContentsOfFile:filePathI encoding:NSUTF8StringEncoding error:nil];
NSArray *arrayStructuresI = [myTextI componentsSeparatedByString:#"-"];
NSString *filePathJ = [[NSBundle mainBundle] pathForResource:#"J" ofType:#"txt"];
NSString *myTextJ= [NSString stringWithContentsOfFile:filePathJ encoding:NSUTF8StringEncoding error:nil];
NSArray *arrayStructuresJ = [myTextJ componentsSeparatedByString:#"-"];
NSString *filePathK = [[NSBundle mainBundle] pathForResource:#"K" ofType:#"txt"];
NSString *myTextK= [NSString stringWithContentsOfFile:filePathK encoding:NSUTF8StringEncoding error:nil];
NSArray *arrayStructuresK = [myTextK componentsSeparatedByString:#"-"];
NSString *filePathL = [[NSBundle mainBundle] pathForResource:#"L" ofType:#"txt"];
NSString *myTextL= [NSString stringWithContentsOfFile:filePathL encoding:NSUTF8StringEncoding error:nil];
NSArray *arrayStructuresL = [myTextL componentsSeparatedByString:#"-"];
NSString *filePathM = [[NSBundle mainBundle] pathForResource:#"M" ofType:#"txt"];
NSString *myTextM= [NSString stringWithContentsOfFile:filePathM encoding:NSUTF8StringEncoding error:nil];
NSArray *arrayStructuresM = [myTextM componentsSeparatedByString:#"-"];
NSString *filePathN = [[NSBundle mainBundle] pathForResource:#"N" ofType:#"txt"];
NSString *myTextN = [NSString stringWithContentsOfFile:filePathN encoding:NSUTF8StringEncoding error:nil];
NSArray *arrayStructuresN = [myTextN componentsSeparatedByString:#"-"];
NSString *filePathO = [[NSBundle mainBundle] pathForResource:#"O" ofType:#"txt"];
NSString *myTextO= [NSString stringWithContentsOfFile:filePathO encoding:NSUTF8StringEncoding error:nil];
NSArray *arrayStructuresO = [myTextO componentsSeparatedByString:#"-"];
NSString *filePathP = [[NSBundle mainBundle] pathForResource:#"P" ofType:#"txt"];
NSString *myTextP= [NSString stringWithContentsOfFile:filePathP encoding:NSUTF8StringEncoding error:nil];
NSArray *arrayStructuresP = [myTextP componentsSeparatedByString:#"-"];
NSString *filePathQ = [[NSBundle mainBundle] pathForResource:#"Q" ofType:#"txt"];
NSString *myTextQ= [NSString stringWithContentsOfFile:filePathQ encoding:NSUTF8StringEncoding error:nil];
NSArray *arrayStructuresQ = [myTextQ componentsSeparatedByString:#"-"];
NSString *filePathR = [[NSBundle mainBundle] pathForResource:#"R" ofType:#"txt"];
NSString *myTextR= [NSString stringWithContentsOfFile:filePathR encoding:NSUTF8StringEncoding error:nil];
NSArray *arrayStructuresR = [myTextR componentsSeparatedByString:#"-"];
NSString *filePathS = [[NSBundle mainBundle] pathForResource:#"S" ofType:#"txt"];
NSString *myTextS= [NSString stringWithContentsOfFile:filePathS encoding:NSUTF8StringEncoding error:nil];
NSArray *arrayStructuresS = [myTextS componentsSeparatedByString:#"-"];
NSString *filePathT = [[NSBundle mainBundle] pathForResource:#"T" ofType:#"txt"];
NSString *myTextT= [NSString stringWithContentsOfFile:filePathT encoding:NSUTF8StringEncoding error:nil];
NSArray *arrayStructuresT = [myTextT componentsSeparatedByString:#"-"];
NSString *filePathU = [[NSBundle mainBundle] pathForResource:#"U" ofType:#"txt"];
NSString *myTextU= [NSString stringWithContentsOfFile:filePathU encoding:NSUTF8StringEncoding error:nil];
NSArray *arrayStructuresU = [myTextU componentsSeparatedByString:#"-"];
NSString *filePathV = [[NSBundle mainBundle] pathForResource:#"V" ofType:#"txt"];
NSString *myTextV= [NSString stringWithContentsOfFile:filePathV encoding:NSUTF8StringEncoding error:nil];
NSArray *arrayStructuresV = [myTextV componentsSeparatedByString:#"-"];
NSString *filePathW = [[NSBundle mainBundle] pathForResource:#"W" ofType:#"txt"];
NSString *myTextW= [NSString stringWithContentsOfFile:filePathW encoding:NSUTF8StringEncoding error:nil];
NSArray *arrayStructuresW = [myTextW componentsSeparatedByString:#"-"];
//none with "X"
//NSString *filePathX = [[NSBundle mainBundle] pathForResource:#"X" ofType:#"txt"];
//NSString *myTextX= [NSString stringWithContentsOfFile:filePathX encoding:NSUTF8StringEncoding error:nil];
//NSArray *arrayStructuresX = [myTextX componentsSeparatedByString:#"-"];
NSString *filePathY = [[NSBundle mainBundle] pathForResource:#"Y" ofType:#"txt"];
NSString *myTextY= [NSString stringWithContentsOfFile:filePathY encoding:NSUTF8StringEncoding error:nil];
NSArray *arrayStructuresY = [myTextY componentsSeparatedByString:#"-"];
NSString *filePathZ = [[NSBundle mainBundle] pathForResource:#"Z" ofType:#"txt"];
NSString *myTextZ= [NSString stringWithContentsOfFile:filePathZ encoding:NSUTF8StringEncoding error:nil];
NSArray *arrayStructuresZ = [myTextZ componentsSeparatedByString:#"-"];
NSLog(#"here4");
NSLog(#"here5");
[listOfItems addObjectsFromArray:arrayStructuresA];
[listOfItems addObjectsFromArray:arrayStructuresB];
[listOfItems addObjectsFromArray:arrayStructuresC];
[listOfItems addObjectsFromArray:arrayStructuresD];
[listOfItems addObjectsFromArray:arrayStructuresE];
[listOfItems addObjectsFromArray:arrayStructuresF];
[listOfItems addObjectsFromArray:arrayStructuresG];
[listOfItems addObjectsFromArray:arrayStructuresH];
[listOfItems addObjectsFromArray:arrayStructuresI];
[listOfItems addObjectsFromArray:arrayStructuresJ];
[listOfItems addObjectsFromArray:arrayStructuresK];
[listOfItems addObjectsFromArray:arrayStructuresL];
[listOfItems addObjectsFromArray:arrayStructuresM];
[listOfItems addObjectsFromArray:arrayStructuresN];
[listOfItems addObjectsFromArray:arrayStructuresO];
[listOfItems addObjectsFromArray:arrayStructuresP];
[listOfItems addObjectsFromArray:arrayStructuresQ];
[listOfItems addObjectsFromArray:arrayStructuresR];
[listOfItems addObjectsFromArray:arrayStructuresS];
[listOfItems addObjectsFromArray:arrayStructuresT];
[listOfItems addObjectsFromArray:arrayStructuresU];
[listOfItems addObjectsFromArray:arrayStructuresV];
[listOfItems addObjectsFromArray:arrayStructuresW];
// [listOfItems addObjectsFromArray:arrayStructuresX];
[listOfItems addObjectsFromArray:arrayStructuresY];
[listOfItems addObjectsFromArray:arrayStructuresZ];
//set the titles
self.navigationItem.title = #"Countries";
NSLog(#"here6");
//[StartWithA addObjectFromArray:arrayStructuresA];
NSLog(#"here6.5");
NSDictionary *StartWithADict = [NSDictionary dictionaryWithObject:arrayStructuresA forKey:#"Countries"];
NSLog(#"here7");
//NSDictionary *countriesToLiveInDict = [NSDictionary dictionaryWithObject:countriesToLiveInArray forKey:#"Countries"];
//[StartWithB addObjectsFromArray:arrayStructuresB];
NSDictionary *StartWithBDict = [NSDictionary dictionaryWithObject:arrayStructuresB forKey:#"Countries"];
//[StartWithC addObjectsFromArray:arrayStructuresC];
NSDictionary *StartWithCDict = [NSDictionary dictionaryWithObject:arrayStructuresC forKey:#"Countries"];
// [StartWithD addObjectsFromArray:arrayStructuresD];
NSDictionary *StartWithDDict = [NSDictionary dictionaryWithObject:arrayStructuresD forKey:#"Countries"];
// [StartWithE addObjectsFromArray:arrayStructuresE];
NSDictionary *StartWithEDict = [NSDictionary dictionaryWithObject:arrayStructuresE forKey:#"Countries"];
//[StartWithF addObjectsFromArray:arrayStructuresF];
NSDictionary *StartWithFDict = [NSDictionary dictionaryWithObject:arrayStructuresF forKey:#"Countries"];
// [StartWithG addObjectsFromArray:arrayStructuresG];
NSDictionary *StartWithGDict = [NSDictionary dictionaryWithObject:arrayStructuresG forKey:#"Countries"];
// [StartWithH addObjectsFromArray:arrayStructuresH];
NSDictionary *StartWithHDict = [NSDictionary dictionaryWithObject:arrayStructuresH forKey:#"Countries"];
// [StartWithI addObjectsFromArray:arrayStructuresI];
NSDictionary *StartWithIDict = [NSDictionary dictionaryWithObject:arrayStructuresI forKey:#"Countries"];
// [StartWithJ addObjectsFromArray:arrayStructuresJ];
NSDictionary *StartWithJDict = [NSDictionary dictionaryWithObject:arrayStructuresJ forKey:#"Countries"];
// [StartWithK addObjectsFromArray:arrayStructuresK];
NSDictionary *StartWithKDict = [NSDictionary dictionaryWithObject:arrayStructuresK forKey:#"Countries"];
//[StartWithL addObjectsFromArray:arrayStructuresL];
NSDictionary *StartWithLDict = [NSDictionary dictionaryWithObject:arrayStructuresL forKey:#"Countries"];
// [StartWithM addObjectsFromArray:arrayStructuresM];
NSDictionary *StartWithMDict = [NSDictionary dictionaryWithObject:arrayStructuresM forKey:#"Countries"];
//[StartWithN addObjectsFromArray:arrayStructuresN];
NSDictionary *StartWithNDict = [NSDictionary dictionaryWithObject:arrayStructuresN forKey:#"Countries"];
// [StartWithO addObjectsFromArray:arrayStructuresO];
NSDictionary *StartWithODict = [NSDictionary dictionaryWithObject:arrayStructuresO forKey:#"Countries"];
// [StartWithP addObjectsFromArray:arrayStructuresP];
NSDictionary *StartWithPDict = [NSDictionary dictionaryWithObject:arrayStructuresP forKey:#"Countries"];
// [StartWithQ addObjectsFromArray:arrayStructuresQ];
NSDictionary *StartWithQDict = [NSDictionary dictionaryWithObject:arrayStructuresQ forKey:#"Countries"];
//[StartWithR addObjectsFromArray:arrayStructuresR];
NSDictionary *StartWithRDict = [NSDictionary dictionaryWithObject:arrayStructuresR forKey:#"Countries"];
// [StartWithS addObjectsFromArray:arrayStructuresS];
NSDictionary *StartWithSDict = [NSDictionary dictionaryWithObject:arrayStructuresS forKey:#"Countries"];
/// [StartWithT addObjectsFromArray:arrayStructuresT];
NSDictionary *StartWithTDict = [NSDictionary dictionaryWithObject:arrayStructuresT forKey:#"Countries"];
// [StartWithU addObjectsFromArray:arrayStructuresU];
NSDictionary *StartWithUDict = [NSDictionary dictionaryWithObject:arrayStructuresU forKey:#"Countries"];
// [StartWithV addObjectsFromArray:arrayStructuresV];
NSDictionary *StartWithVDict = [NSDictionary dictionaryWithObject:arrayStructuresV forKey:#"Countries"];
// [StartWithW addObjectsFromArray:arrayStructuresW];
NSDictionary *StartWithWDict = [NSDictionary dictionaryWithObject:arrayStructuresW forKey:#"Countries"];
//NSMutableArray *StartWithX;
//[StartWithX addObjectsFromArray:arrayStructuresX];
//NSDictionary *StartWithXDict = [NSDictionary dictionaryWithObject:arrayStructuresX forKey:#"Countries"];
// [StartWithY addObjectsFromArray:arrayStructuresY];
NSDictionary *StartWithYDict = [NSDictionary dictionaryWithObject:arrayStructuresY forKey:#"Countries"];
// [StartWithZ addObjectsFromArray:arrayStructuresZ];
NSDictionary *StartWithZDict = [NSDictionary dictionaryWithObject:arrayStructuresZ forKey:#"Countries"];
NSLog(#"Here8");
[listOfItems addObject:StartWithADict];
[listOfItems addObject:StartWithBDict];
[listOfItems addObject:StartWithCDict];
[listOfItems addObject:StartWithDDict];
[listOfItems addObject:StartWithEDict];
[listOfItems addObject:StartWithFDict];
[listOfItems addObject:StartWithGDict];
[listOfItems addObject:StartWithHDict];
[listOfItems addObject:StartWithIDict];
[listOfItems addObject:StartWithJDict];
[listOfItems addObject:StartWithKDict];
[listOfItems addObject:StartWithLDict];
[listOfItems addObject:StartWithMDict];
[listOfItems addObject:StartWithNDict];
[listOfItems addObject:StartWithODict];
[listOfItems addObject:StartWithPDict];
[listOfItems addObject:StartWithQDict];
[listOfItems addObject:StartWithRDict];
[listOfItems addObject:StartWithSDict];
[listOfItems addObject:StartWithTDict];
[listOfItems addObject:StartWithUDict];
[listOfItems addObject:StartWithVDict];
[listOfItems addObject:StartWithWDict];
//[listOfItems addObject:StartWithXDict];
[listOfItems addObject:StartWithYDict];
[listOfItems addObject:StartWithZDict];
NSLog(#"Here9");
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark Table view methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSLog(#"Here10");
NSLog(#"%d", [listOfItems count]);
return [listOfItems count];
}
//this sets the number of row in the table view, by couting the number of objects (countries) in the array//
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"Here12");
//Number of rows it should expect should be based on the section
NSDictionary *dictionary = [listOfItems objectAtIndex:section];
NSArray *array = [dictionary objectForKey:#"Countries"];
NSLog(#"this is the array count - %d", [array count]);
return [array count];
NSLog(#"Here13");
}// Customize the number of rows in the table view.
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Here14");
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell.
NSDictionary *dictionary = [listOfItems objectAtIndex:indexPath.section];
NSArray *array = [dictionary objectForKey:#"Countries"];
NSString *cellValue = [array objectAtIndex:indexPath.row];
[cell.textLabel setText:cellValue];
//NSString *cellValue = [listOfItems objectAtIndex:indexPath.row];
//[cell.textLabel setText:cellValue];
//[cell.textLabel setText:cellValue];
NSLog(#"Here15");
return cell;
//NSLog(cellValue);
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
NSLog(#"Here16");
if (section == 0) {
return #"A";
}
if (section == 1) {
return #"B";
}
if (section == 2) {
return #"C";
}
if (section == 3) {
return #"D";
}
if (section == 4) {
return #"E";
}
if (section == 5) {
return #"F";
}
if (section == 6) {
return #"G";
}
if (section == 7) {
return #"H";
}
if (section == 8) {
return #"I";
}
if (section == 9) {
return #"J";
}
if (section == 10) {
return #"K";
}
if (section == 11) {
return #"L";
}
if (section == 12) {
return #"M";
}
if (section == 13) {
return #"N";
}
if (section == 14) {
return #"O";
}
if (section == 15) {
return #"P";
}
if (section == 16) {
return #"Q";
}
if (section == 17) {
return #"R";
}
if (section == 18) {
return #"S";
}
if (section == 19) {
return #"T";
}
if (section == 20) {
return #"U";
}
if (section == 21) {
return #"V";
}
if (section == 22) {
return #"W";
}
//if (section==0) {
//return #"X";
//}
if (section == 23) {
return #"Y";
}
if (section == 24) {
return #"Z";
}
return #"";
//NSLog(#"%d", [listOfItems count]);
NSLog(#"That whole error thing");
}
- (UITableViewCellAccessoryType)tableView:(UITableView *)tableView accessoryTypeForRowWithIndexPath:(NSIndexPath *)indexPath{
NSLog(#"Here17");
return UITableViewCellAccessoryDisclosureIndicator;
}
// Override to support row selection in the table view.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Here18");
//Get the selected country
NSDictionary *dictionary = [listOfItems objectAtIndex:indexPath.section];
NSArray *array = [dictionary objectForKey:#"Countries"];
NSString *selectedCountry = [array objectAtIndex:indexPath.row];
//Initialize the detail view controller and display it.
DetailViewController *dvController = [[DetailViewController alloc] initWithNibName:#"DetailView" bundle:[NSBundle mainBundle]];
dvController.selectedCountry = selectedCountry;
[self.navigationController pushViewController:dvController animated:YES];
[dvController release];
dvController = nil;
/*
NSString *selectedCountry = [listOfItems objectAtIndex:indexPath.row];
//init the detail view controller and display it.
DetailViewController *dvController = [[DetailViewController alloc] initWithNibName:#"DetailView" bundle:[NSBundle mainBundle]];
dvController.selectedCountry = selectedCountry;
[self.navigationController pushViewController:dvController animated:YES];
[dvController release];
dvController = nil;
*/
// Navigation logic may go here -- for example, create and push another view controller.
// AnotherViewController *anotherViewController = [[AnotherViewController alloc] initWithNibName:#"AnotherView" bundle:nil];
// [self.navigationController pushViewController:anotherViewController animated:YES];
// [anotherViewController release];
NSLog(#"Here19");
}
- (void)dealloc {
//dealloc the array
[listOfItems release];
NSLog(#"Here20");
[super dealloc];
}
#end
The error message is a bit cryptic, but it basically says that you tried to send the message "objectForKey:" to an object of class "NSString", and that method doesn't exist in the NSString class. It sounds like you're programatically grabbing an object and expecting that object to be an NSDictionary. At runtime, your NSDictionary * is actually being set to an NSString *, and you don't get an exception until that object is actually used incorrectly.
The fact that you can say "give me this object of unknown type, assume it's a dictionary, and call this function" is actually pretty cool once you get comfortable with Objective-C, but it's hell to get used to. I've always found that Objective-C assumes you know what you're doing. Some people love it because it lets them write clean, concise code -- but it raises the learning curve quite a bit.
Feel free to post a code snippet if you need more help tracking this one down!
Ben
UPDATE:
It looks like when you setup your data in viewDidLoad:, you are loading a bunch of arrays from separate files. Then you add the contents of those arrays to your main data array like this:
[listOfItems addObjectsFromArray:arrayStructuresF];
I think those lines shouldn't be there. Further down, you're creating dictionaries for each letter and then adding those to the listOfItems. At the end of the function, listOfItems contains a whole bunch of string items AND a whole bunch of dictionaries. The string items come first, so you're getting NSStrings when you expect NSDictionaries.
P.S. You might want to condense some of this into loops once it's all working. You could create an array of the letters A,B,C,D, etc... and then load all the files in a loop using filenames made using NSString's stringWithFormat:. Just a thought!
The object at 0x3814530 is a NSString and yet you treat it as a NSDictionary, and you get a runtime exception.
This article describes breaking on exceptions.
Use the debugger to inspect the code that is adjacent to your exception.
Try turning on NSZombiesEnabled.
Double-click your executable in the Executable group of your project.
Click the Arguments tab.
In the "Variables to be set in the environment:" section, create a new variable called NSZombieEnabled and set it to YES.
I'm betting you'll find you're sending a message to an object that's already been released to the point that it's been deallocated.
Related
I want to pass values inside for(NSDictionary *jsonDictionary in myJsonArray) which I get in NSLog to [array addObject:[[SaveList alloc] initWithEmail:email withPhone:phone withDate:date withName:name]];
Code is here
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSError *error = nil;
NSURL *url = [NSURL URLWithString:#" http:// Some url "];
NSString *json = [NSString stringWithContentsOfURL:url encoding:NSASCIIStringEncoding error:&error];
NSLog(#"\n\n JSON : %#, \n Error: %#", json, error);
if(!error)
{
NSData *jsonData = [json dataUsingEncoding:NSASCIIStringEncoding];
NSArray *myJsonArray = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
// NSDictionary *jsonDictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&error];
for(NSDictionary *jsonDictionary in myJsonArray)
{
NSLog(#"JSON Dictionary = %#", jsonDictionary);
NSString *name = jsonDictionary[#"Name"];
NSString *date = jsonDictionary[#"Date"];
NSString *email = jsonDictionary[#"Email"];
NSString *phone = jsonDictionary[#"Phone"];
NSLog(#"Name = %#", name);
NSLog(#"Date = %#", date);
NSLog(#"Email = %#", email);
NSLog(#"Phone = %#", phone);
}
}
});
//Table implementation
array = [[NSMutableArray alloc]init];
//**Get email, phone, date, name here**
[array addObject:[[SaveList alloc] initWithEmail:email withPhone:phone withDate:date withName:name]];
self.tableView.dataSource = self;
self.tableView.delegate = self;
Why don't you add the objects as you receive them? Since this block of code will be executed asynchronously you could prepare your array, set your tableview and then execute the block where you fill your array and refresh the tableview.
Something like this:
// Prepare your array
array = [NSMutableArray arrayWithCapacity:0];
// Set your tableview's datasource & delegate
self.tableView.dataSource = self;
self.tableView.delegate = self;
// Fetch data asynchronously
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSError *error = nil;
NSURL *url = [NSURL URLWithString:#" http:// Some url "];
NSString *json = [NSString stringWithContentsOfURL:url encoding:NSASCIIStringEncoding error:&error];
NSLog(#"\n\n JSON : %#, \n Error: %#", json, error);
if(!error)
{
NSData *jsonData = [json dataUsingEncoding:NSASCIIStringEncoding];
NSArray *myJsonArray = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
NSMutableArray *tmp = [NSMutableArray arrayWithCapacity:myJsonArray.count];
for(NSDictionary *jsonDictionary in myJsonArray)
{
NSString *name = jsonDictionary[#"Name"];
NSString *date = jsonDictionary[#"Date"];
NSString *email = jsonDictionary[#"Email"];
NSString *phone = jsonDictionary[#"Phone"];
//**Get email, phone, date, name here**
[tmp addObject:[[SaveList alloc] initWithEmail:email
withPhone:phone
withDate:date
withName:name]];
}
// Reload your tableview
dispatch_sync(dispatch_get_main_queue(), ^{
array = tmp; // Or add them to your datasource array, whatever suits you...
[self.tableView reloadData];
});
}
});
set number of rows
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
[array count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
SavedList *savedList = [array objectAtIndex:indexPath.row];
cell.text = savedList.name;
}
return cell;
}
I hope it will be helpful.
// U need to reload table view data whenever you add new object in it. It does work like a thread.
dispatch_sync(dispatch_get_main_queue(), ^{
array = myJsonArray;
[self.tableView reloadData];
I need to extract a variable's value from a string, which happens to be a URL. The string/url is loaded as part of a separate php query, not the url in the browser.
The url's will look like:
http://gmail.com?access_token=ab8w4azq2xv3dr4ab37vvzmh&token_type=bearer&expires_in=3600
How can I capture the value of the access_token which in this example is ab8w4azq2xv3dr4ab37vvzmh?
This code should do it:
- (NSString *)extractToken:(NSURL *)URL
{
NSString *urlString = [URL absoluteString];
NSRange start = [urlString rangeOfString:#"access_token="];
if (start.location != NSNotFound)
{
NSString *token = [urlString substringFromIndex:start.location+start.length];
NSRange end = [token rangeOfString:#"&"];
if (end.location != NSNotFound)
{
//trim off other parameters
token = [token substringToIndex:end.location];
}
return token;
}
//not found
return nil;
}
Alternatively, here is a more general solution that will extract all the query parameters into a dictionary:
- (NSDictionary *)URLQueryParameters:(NSURL *)URL
{
NSString *queryString = [URL query];
NSMutableDictionary *result = [NSMutableDictionary dictionary];
NSArray *parameters = [queryString componentsSeparatedByString:#"&"];
for (NSString *parameter in parameters)
{
NSArray *parts = [parameter componentsSeparatedByString:#"="];
NSString *key = [[parts objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
if ([parts count] > 1)
{
id value = [[parts objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[result setObject:value forKey:key];
}
}
return result;
}
Good Category for NSDictionary:
#import "NSDictionary+URL.h"
#implementation NSDictionary (URL)
+ (NSDictionary *)dictionaryWithUrlString:(NSString *)urlString{
NSRange urlRange = [urlString rangeOfString:#"?"];
if(urlRange.length>0){
urlString = [urlString substringFromIndex:urlRange.length+urlRange.location];
}
NSArray *pairsArray = [urlString componentsSeparatedByString:#"&"];
NSMutableDictionary *parametersDictionary = [[NSMutableDictionary alloc] initWithCapacity:[pairsArray count]];
for(NSString *pairString in pairsArray){
NSArray *valuesArray = [pairString componentsSeparatedByString:#"="];
if([valuesArray count]==2){
[parametersDictionary setValue:[valuesArray objectAtIndex:1] forKey:[valuesArray objectAtIndex:0]];
}
}
return [parametersDictionary autorelease];
}
#end
NSMutableDictionary *querycomponent = [[NSMutableDictionary alloc] init];
if (![query isEqualToString:#""]){
NSArray *queryArray = [query componentsSeparatedByString:#"&"];
for (NSString *subquery in queryArray){
NSArray *subqueryArray = [subquery componentsSeparatedByString:#"="];
NSString *key = [subqueryArray objectAtIndex:0];
NSString *val = [subqueryArray objectAtIndex:1];
[querycomponent setObject:val forKey:key];
}
NSLog(#"querycomponent %#",querycomponent);
}
below is the JSON i want to parse it in such a way that for e.g date 1st should all events in that section of table and 2nd date should show all related events in another section
I am parsing using below code but i am not getting required sequence
SBJsonParser *parser= [[SBJsonParser alloc] init];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.krsconnect.no/community/api.html?method=bareListEventsByCategory&appid=620&category-selected=350&counties-selected=Vest-Agder,Aust-Agder"]];
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSDictionary *object = [parser objectWithString:json_string error:nil];
NSArray *results = [parser objectWithString:json_string error:nil];
appDelegate.books1 = [[NSMutableArray alloc] init];
appDelegate.dates =[[NSMutableArray alloc]init];
for (int j=0;j<10; j++) {
NSDictionary *dictOne = [results objectAtIndex:j];
NSLog(#"%# - %#", [dictOne objectForKey:#"date"]);
Date *aDate = [[Date alloc] initWithDictionary:[results objectAtIndex:j]];
[appDelegate.dates addObject:aDate];
[aDate release];
}
for (int i=0; i<10; i++) {
NSDictionary *dictOne = [results objectAtIndex:i];
NSArray *activitiesArray = [dictOne objectForKey:#"events"];
NSDictionary *dictTwo = [activitiesArray objectAtIndex:i];
NSDictionary *eventDict=[dictTwo objectForKey:#"event"];
// NSLog(#"%# - %#", [dictOne objectForKey:#"date"]);
// NSLog(#"%# - %#", [dictTwo objectForKey:#"affectedDate"]);
// NSLog(#"%# - %#", [eventDict objectForKey:#"location"]);
NSInteger*date=[dictOne objectForKey:#"date"];
NSInteger*affectedDate=[dictTwo objectForKey:#"affectedDate"];
NSString*appId =[eventDict objectForKey:#"appId"];
NSString*eventId=[eventDict objectForKey:#"eventId"];
NSString*location=[eventDict objectForKey:#"location"];
NSString*municipality=[eventDict objectForKey:#"municipality"];
NSString*title=[eventDict objectForKey:#"title"];
Book1 *aBook=[[Book1 alloc] initWithDate:date affectedDate:affectedDate location:location municipality:municipality title:title];
[appDelegate.books1 addObject:aBook];
int count=[appDelegate.books1 count];
}
the json format is given below
http://www.krsconnect.no/community/api.html?method=bareListEventsByCategory&appid=620&category-selected=350&counties-selected=Vest-Agder,Aust-Agder
You need to aggregate your data in some different way.
Here is how I'd do that:
...
// why do you parse your json string two times?
//NSDictionary *object = [parser objectWithString:json_string error:nil];
NSArray *results = [parser objectWithString:json_string error:nil];
// You have memory leak here. I assume that books1 and dates are both properties with "retain" flag set.
//appDelegate.books1 = [[NSMutableArray alloc] init];
//appDelegate.dates =[[NSMutableArray alloc]init];
NSMutableArray *data = [NSMutableArray array]
self.data = data;
// check that what we've parsed is NSArray
if (results && [results isKindOfClass:[NSArray class]]) {
for (NSDictionary *sectionDict in results) {
if ([sectionDict isKindOfClass:[NSDictionary class]]) {
NSString *sectionTitle = [[sectionDict objectForKey:#"date"] description];
NSArray *events = [sectionDict objectForKey:#"events"];
if (date && events && [events isKindOfClass:[NSArray class]]) {
NSMutableArray *rows = [NSMutableArray arrayWithCapacity:[events count]];
for (NSDictionary *eventDict in events) {
if ([eventDict isKindOfClass:[NSDictionary class]]) {
[rows addObject:#"testRow"];
}
}
[data addObject:[NSDictionary dictionaryWithObjectsAndKeys: sectionTitle, #"section", rows, #"rows", nil]];
}
}
}
}
- (NSInteger) numberOfSectionsInTableView:(UITableView *)tblView {
return [data count];
}
- (NSInteger) tableView:(UITableView *)tblView numberOfRowsInSection:(NSInteger)section {
return [[[data objectAtIndex:section] objectForKey:#"rows"] count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [[data objectAtIndex:section] objectForKey:#"section"];
}
- (UITableViewCell *) tableView:(UITableView *)tblView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellID = #"DefaultCell";
UITableViewCell *cell = (UITableViewCell *)[tblView dequeueReusableCellWithIdentifier:cellID];
if ( cell == nil ) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID] autorelease];
}
cell.textLabel.text = [[[data objectAtIndex:indexPath.section] objectForKey:#"rows"] objectAtIndex:indexPath.row];
return cell;
}
-(void) readRestaurantFromXml {
SGAAppDelegate *app = (SGAAppDelegate *)[[UIApplication sharedApplication] delegate];
NSString *myRequestString = [NSString stringWithFormat:#"%#getXml.aspx",app.SERVER_URL];
NSURL *url = [NSURL URLWithString: myRequestString];
CXMLDocument *rssParser = [[[CXMLDocument alloc] initWithContentsOfURL:url options:0 error:nil] autorelease];
resultNodes = [rssParser nodesForXPath:#"//item" error:nil];
listOfItems = [[NSMutableArray alloc] init];
for (CXMLElement *resultElement in resultNodes) {
NSString *theatre_id = [[resultElement childAtIndex:0] stringValue];
NSString *theatre_name = [[resultElement childAtIndex:1] stringValue];
NSString *restaurant_id = [[resultElement childAtIndex:2] stringValue];
NSString *restaurant_name = [[resultElement childAtIndex:3] stringValue];
NSString *restaurant_desc = [[resultElement childAtIndex:4] stringValue];
NSString *deal_avail = [[resultElement childAtIndex:5] stringValue];
NSString *deal_details = [[resultElement childAtIndex:6] stringValue];
Restaurant *workVal = [[Restaurant alloc] initWithRestTitle:restaurant_name restDesc:restaurant_desc theatreId:theatre_id theatreName:theatre_name restId:restaurant_id restDeals:deal_avail restDealDesc:deal_details];
[listOfItems addObject:workVal];
[workVal release];
}
}
-(void)myTask{
NSLog(#"%d",[listOfItems count]);
}
The NSMutableArray listofItems has 3 values.So how can i extract the array value in another method?
Help me
Fast enumeration is the preferred method.
for (id object in listOfItems) {
//Do something...
}
If you want a single object at an index:
id object = [listOfItems objectAtIndex:someIndex];
If you just want an object (expecting the array to have a single object:
id object = [listOfItems lastObject];
for(int i=0; i < [listOfItems count]; ++i) {
Restaurant* r = [listofItems objectAtIndex:i];
}
I am having a little trouble saving to a plist file, when i am reading the data i am using:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return amounts.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//Create Cell
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"cell"];
//Fill cell
NSDictionary *budgetItem = [amounts objectAtIndex:indexPath.row];
cell.textLabel.text = [budgetItem objectForKey:#"value"];
cell.detailTextLabel.text = [budgetItem objectForKey:#"description"];
//Return it
return cell;
}
- (void) loadData{
// Load items
NSString *error;
NSPropertyListFormat format;
NSString *localizedPath = [[NSBundle mainBundle] pathForResource:#"savebudget" ofType:#"plist"];
NSData *plistData = [NSData dataWithContentsOfFile:localizedPath];
NSArray *amountData = [NSPropertyListSerialization propertyListFromData:plistData
mutabilityOption:NSPropertyListImmutable
format:&format
errorDescription:&error];
if (amountData) {
self.amounts = [[NSMutableArray alloc] initWithCapacity:[amountData count]];
for (NSDictionary *amountsDictionary in amountData) {
[self.amounts addObject:amountsDictionary];
}
}
Which works fine from a static plist file with-in my resources folder, but when i try and create my own, nothing seems to happen:
-(void) addData {
NSString *path = [[NSBundle mainBundle] pathForResource:#"saveBudget" ofType:#"plist"];
NSMutableDictionary* plist = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
[plist setValue:amountTxt.text forKey:#"value"];
[plist writeToFile:path atomically:YES];
[plist release];
}
- (IBAction)add:(id)sender {
[self addData];
[self.delegate budgetEnterMinusViewControllerDidFinish:self];
}
Any help more than welcome...
Ugh. Terrible and confusing code. First: use this to load instead:
NSString* path = [[NSBundle mainBundle] pathForResource:#"savebudget" ofType:#"plist"];
NSDictionary* amountData = [NSDictionary dictionaryWithContentsOfFile: path error: NULL];
if (amountData) {
self.amounts = [NSMutableArray arrayWithArray: amountData];
}
Note, no retain or alloc/init here because you are assigning to a retaining property.
So the real problem:
You are reading a plist that that you say contains an array of dictionaries. But then when you add data, you try to write back one single dictionary to that same plist.
Also, in your addData method you do not actually add any data.
And ... If you load your initial data from your app's bundle, then you should write it back to your ~/Documents directory after changing it. And of course read it back from there the next time your app starts.