NSRangeException error... NSDictionary, NSArray, UISearchBar - objective-c

I am quite new with Objective C and I have been having trouble a a little while and I have been looking over answers, watching tutorials, and I have not been able to find a solution to my problem. Maybe its right in front of my face and I am not seeing it...I think it has something that has to do with the NSRange of my UISearch Bar. But I am not 100% sure.
I am trying to search through array that has the keys of my dictionary of countries, I have set up several NSLogs and I see that the keys are going into the array I have setup to save them in and then i get the error below...
So to my understanding of this, it is counting countryKeys which has 5, so index 4 should exist, should it not? but then it shows 0 .. 3, So I this is why I am thinking i am using NSRange incorrectly. I have watched some UISearchBar and For loop tutorials so far and i am understanding For loops and them better i guess I need to figure out NSRange then.
Let me know if you don't understand my thought process or anything that I mentioned..
Filtered Countries (
ATE,
ARE,
USA,
JAP,
CAN
)
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 4 beyond bounds [0 .. 3]'
-
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize dictTableView, mySearchBar, countriesInRegion, filteredCountries, isFiltered, regionCodes, countryKey, countryKeys, countryInfo, sortedKeysArray, regionCode, dict1;
- (void)viewDidLoad
{
[super viewDidLoad];
dict1 = [[NSMutableDictionary alloc] init];
NSMutableDictionary *subDict = [[NSMutableDictionary alloc] initWithObjects:[NSArray arrayWithObjects:#"United States",#"US",#"USA", #"NAC", nil]
forKeys: [NSArray arrayWithObjects:#"countryName", #"countryAbbrev", #"countryID", #"countryRegion", nil]];
[dict1 setObject:subDict forKey:#"USA"];
subDict = [[NSMutableDictionary alloc] initWithObjects:[NSArray arrayWithObjects:#"Canada", #"CA", #"CAN", #"NAC", nil]
forKeys: [NSArray arrayWithObjects:#"countryName", #"countryAbbrev", #"countryID", #"countryRegion", nil]];
[dict1 setObject:subDict forKey:#"CAN"];
subDict = [[NSMutableDictionary alloc] initWithObjects:[NSArray arrayWithObjects:#"Japan", #"JP", #"JAP", #"EAS", nil]
forKeys: [NSArray arrayWithObjects:#"countryName", #"countryAbbrev", #"countryID", #"countryRegion", nil]];
[dict1 setObject:subDict forKey:#"JAP"];
subDict = [[NSMutableDictionary alloc] initWithObjects:[NSArray arrayWithObjects:#"United Arab Emirates", #"AE", #"ARE", #"MEA", nil]
forKeys: [NSArray arrayWithObjects:#"countryName", #"countryAbbrev", #"countryID", #"countryRegion", nil]];
[dict1 setObject:subDict forKey:#"ARE"];
subDict = [[NSMutableDictionary alloc] initWithObjects:[NSArray arrayWithObjects:#"Antigua and Barbuda", #"AG", #"ATE", #"LCN", nil]
forKeys: [NSArray arrayWithObjects:#"countryName", #"countryAbbrev", #"countryID", #"countryRegion", nil]];
[dict1 setObject:subDict forKey:#"ATE"];
regionCodes = [[NSMutableDictionary alloc] init];
countryKeys = [dict1 allKeys];
NSLog(#"countryKeys %#", countryKeys);
sortedKeysArray = [countryKeys sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
for (int i = 0; i < [sortedKeysArray count]; i++) {
countryKey = [sortedKeysArray objectAtIndex:i];
countryInfo = [dict1 objectForKey:countryKey]; // NSLog(#"returning countryKey to countryInfo %#", countryInfo);
regionCode = [countryInfo objectForKey:#"countryRegion"]; // NSLog(#" adding countryRegion Key to regionCode %#", regionCode);
// NSLog(#"the contents of countryInfo is %#", countryInfo);
if (![regionCodes objectForKey:regionCode]) {
countriesInRegion = [[NSMutableArray alloc] init];
[regionCodes setObject:countriesInRegion forKey:regionCode];
[countriesInRegion addObject:countryInfo]; // NSLog(#"if adding countryInfo to initialCountries %#", countryInfo);
}
else{
countriesInRegion = [regionCodes objectForKey:regionCode];
[countriesInRegion addObject:countryInfo]; // NSLog(#"else adding countryInfo to initialCountries %#", countryInfo);
}
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
if (isFiltered == NO)
{
return countryInfo.count;
}
else
{
return filteredCountries.count;
}
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
NSArray *sortKey = [regionCodes allKeys];
sortedKeysArray = [sortKey sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
return [sortedKeysArray objectAtIndex:section];
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
{
NSString *regionKey = [[regionCodes allKeys] objectAtIndex:section];
countriesInRegion = [regionCodes objectForKey:regionKey];
if (isFiltered == NO)
{
return countriesInRegion.count;
}
else
{
return filteredCountries.count;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
UITableViewCell *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:(UITableViewCellStyleDefault) reuseIdentifier:#"Cell"];
UILabel *countryNameLabel = [[UILabel alloc] initWithFrame:(CGRectMake(10, 0, 220, 44))];
[countryNameLabel setBackgroundColor:[UIColor clearColor]];
UILabel *countryAbbrevLabel = [[UILabel alloc] initWithFrame:(CGRectMake(230, 0, 75, 44))];
[countryNameLabel setBackgroundColor:[UIColor clearColor]];
UILabel *countryIDLabel = [[UILabel alloc] initWithFrame:(CGRectMake(275, 0, 50, 44))];
[countryNameLabel setBackgroundColor:[UIColor clearColor]];
[cell.contentView addSubview:countryNameLabel];
[cell.contentView addSubview:countryAbbrevLabel];
[cell.contentView addSubview:countryIDLabel];
}
NSArray *regionKeys = [regionCodes allKeys];
NSString *regionKey = [regionKeys objectAtIndex:indexPath.section];
countriesInRegion = [regionCodes objectForKey:regionKey];
NSLog(#"Countries in Region %#", countriesInRegion);
countryInfo = [countriesInRegion objectAtIndex:indexPath.row];
NSArray *subviews = [cell.contentView subviews];
UILabel *nameLabel = [subviews objectAtIndex:0];
UILabel *abbrevLabel = [subviews objectAtIndex:1];
UILabel *idLabel = [subviews objectAtIndex:2];
// NSLog(#"6 - Countries in Region %#", countriesInRegion);
if (isFiltered == NO)
{
nameLabel.text = [countryInfo objectForKey:#"countryName"];
abbrevLabel.text = [countryInfo objectForKey:#"countryAbbrev"];
idLabel.text = [countryInfo objectForKey:#"countryID"];
// NSLog(#"5 - Our list of countries: %#", nameLabel.text);
// NSLog(#"Country Info %#",countryInfo);
}
else
{
nameLabel.text = [filteredCountries objectAtIndex:2];
abbrevLabel.text = [filteredCountries objectAtIndex:1];
idLabel.text = [filteredCountries objectAtIndex:0];
NSLog(#"4 - Here are your results: %#", filteredCountries);
}
return cell;
}
#pragma mark - UISearchBarDelegate Methods
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
if (searchText.length == 0) {
isFiltered = NO;
}
else
{
isFiltered = YES;
NSLog(#"You entered %#", searchText);
filteredCountries = [[NSMutableArray alloc] init];
countryKeys = [dict1 allKeys];
NSLog(#"countryKeys %#", countryKeys);
for (int i = 0; i < countryKeys.count; i++) {
countryKey = [countryKeys objectAtIndex:i];
NSLog(#"country key is %#", countryKey);
{
NSRange countryNameRange = [countryKey rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (countryNameRange.location !=NSNotFound)
{
[filteredCountries addObject:countryKey];
NSLog(#"Filtered Countries %#", filteredCountries);
}
}
}
}
[dictTableView reloadData];
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
[mySearchBar resignFirstResponder];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#end

That error simply means that you are exceeding the bound of an array.
Specifically at a first sight, I think you got wrong the number of sections and that it doesn't match the number of elements in your array.
I noticed that when filtered is equal to YES you are returning filteredCountries.count for both number of rows and number of sections.
It doesn't look right and I think you should double check you indexes.

Related

drilldown tableview

I have a project I am working on and it requires drill down UITableView. i have adapted my code to storyboard and it drills down fine from the first UITableView to the second UITableView but when I select the rows in the second UITableView I only get one of the arrays. when selecting any other row it just shows the detail for one of the rows. i know the description is vague so I am including my codes for more clarification. any help is truly appreciated.
TeamTable.m
#implementation TeamTable
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)dealloc
{
[super dealloc];
}
- (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 - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
teamArray = [[NSMutableArray alloc] init];
[teamArray addObject:#"East Cobb"];
[teamArray addObject:#"West Cobb"];
[teamArray addObject:#"Buckhead Thunder"];
[teamArray addObject:#"Fulton East"];
[teamArray addObject:#"Atlanta Braves"];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [teamArray count];
}
- (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] autorelease];
}
// Configure the cell...
UIImageView *imageView = [[UIImageView alloc] initWithFrame:cell.frame];
UIImage *image = [UIImage imageNamed:#"bgp.png"];
imageView.image = image;
cell.backgroundView = imageView;
[[cell textLabel] setBackgroundColor:[UIColor clearColor]];
[[cell detailTextLabel] setBackgroundColor:[UIColor clearColor]];
cell.textLabel.text = [[teamArray objectAtIndex:indexPath.row] autorelease];
return cell;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([[segue identifier] isEqualToString:#"Table"]){
TeamTable1 *teams = [segue destinationViewController];
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
if ([[teamArray objectAtIndex:indexPath.row] isEqual:#"East Cobb"]) {
teams.teamsInt = 0;
[teams setTitle:[teamArray objectAtIndex:indexPath.row]];
}
if ([[teamArray objectAtIndex:indexPath.row] isEqual:#"West Cobb"]) {
teams.teamsInt = 1;
[teams setTitle:[teamArray objectAtIndex:indexPath.row]];
}
if ([[teamArray objectAtIndex:indexPath.row] isEqual:#"Buckhead Thunder"]) {
teams.teamsInt = 2;
[teams setTitle:[teamArray objectAtIndex:indexPath.row]];
}
if ([[teamArray objectAtIndex:indexPath.row] isEqual:#"Fulton East"]) {
teams.teamsInt = 3;
[teams setTitle:[teamArray objectAtIndex:indexPath.row]];
}
if ([[teamArray objectAtIndex:indexPath.row] isEqual:#"Atlanta Braves"]) {
teams.teamsInt = 4;
[teams setTitle:[teamArray objectAtIndex:indexPath.row]];
}
}
}
#end
second table .h file
#interface TeamTable1 : UITableViewController{
NSMutableArray *eastCobbArray;
NSMutableArray *westCobbArray;
NSMutableArray *buckheadThunderArray;
NSMutableArray *fultonEastArray;
NSMutableArray *atlantaBravesArray;
NSMutableArray *sectionArray;
NSMutableArray *data;
int teamsInt;
}
#property int teamsInt;
- (void) makeData;
#end
second table .m file
#implementation TeamTable1
#synthesize teamsInt;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)dealloc
{
[sectionArray release];
[data release];
[eastCobbArray release];
[westCobbArray release];
[buckheadThunderArray release];
[fultonEastArray release];
[atlantaBravesArray release];
[super dealloc];
}
- (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 - View lifecycle
- (void)viewDidLoad{
[self makeData];
[super viewDidLoad];
}
- (void) makeData
{
data = [[NSMutableArray alloc] init];
sectionArray = [[NSMutableArray alloc] init];
eastCobbArray = [[NSMutableArray alloc] init];
westCobbArray = [[NSMutableArray alloc] init];
buckheadThunderArray = [[NSMutableArray alloc] init];
fultonEastArray = [[NSMutableArray alloc] init];
atlantaBravesArray = [[NSMutableArray alloc] init];
if (teamsInt == 0) {
[sectionArray addObject:#"East Cobb"];
}
if (teamsInt == 1) {
[sectionArray addObject:#"West Cobb"];
}
if (teamsInt == 2) {
[sectionArray addObject:#"Buckhead Thunder"];
}
if (teamsInt == 3) {
[sectionArray addObject:#"Fulton East"];
}
if (teamsInt == 4) {
[sectionArray addObject:#"Atlanta Braves"];
}
[eastCobbArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Coaches", #"name" , #"image1.JPG", #"image" , #"Mark Bayle 3rd Base\nSusane Ballor First Base\nJim Thally Pitching\nSam Bradley Batting", #"description", nil]];
[eastCobbArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Team Outlook", #"name" , #"image2.jpg", #"image" , #"our team has won 26 out of the 35 and it is in first place. We have 2 players on DL and have recalled two players to replace them.", #"description", nil]];
[eastCobbArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Schedule", #"name" , #"image3.jpg", #"image" , #"Sun June 30 VS Thunders # Home\nMon June 31 VS Braves # away\nTue July 1 VS East Cobb # Home", #"description", nil]];
[eastCobbArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Upcomming Events", #"name" , #"image4.jpg", #"image" , #"This is the list of the upcomming events for the month of july:\nJuly 1st:\nBake them all.\nJuly 2nd:\nFamily reunion\nJuly 3rd:\nSuppliers convention.", #"description", nil]];
[eastCobbArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Roster", #"name" , #"image5.jpg", #"image" , #"Jim this 17\nTim duncan 22\nJim thalos 21\nFredrick nitche 24\n", #"description", nil]];
[westCobbArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Coaches", #"name" , #"image1.JPG", #"image" , #"Mark Bayle 3rd Base\nSusane Ballor First Base\nJim Thally Pitching\nSam Bradley Batting", #"description", nil]];
[westCobbArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Team Outlook", #"name" , #"image2.jpg", #"image" , #"our team has won 26 out of the 35 and it is in first place. We have 2 players on DL and have recalled two players to replace them.", #"description", nil]];
[westCobbArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Schedule", #"name" , #"image3.jpg", #"image" , #"Sun June 30 VS Thunders # Home\n Mon June 31 VS Braves # away \n Tue July 1 VS East Cobb # Home \n", #"description", nil]];
[westCobbArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Upcomming Events", #"name" , #"image4.jpg", #"image" , #"This is the list of the upcomming events for the month of july:\nJuly 1st:\nBake them all.\nJuly 2nd:\nFamily reunion\nJuly 3rd:\nSuppliers convention.", #"description", nil]];
[westCobbArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Roster", #"name" , #"image5.jpg", #"image" , #"Jim this 17\nTim duncan 22\nJim thalos 21\nFredrick nitche 24\n", #"description", nil]];
[buckheadThunderArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Coaches", #"name" , #"image1.JPG", #"image" , #"Mark Bayle 3rd Base\nSusane Ballor First Base\nJim Thally Pitching\nSam Bradley Batting", #"description", nil]];
[buckheadThunderArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Team Outlook", #"name" , #"image2.jpg", #"image" , #"our team has won 26 out of the 35 and it is in first place. We have 2 players on DL and have recalled two players to replace them.", #"description", nil]];
[buckheadThunderArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Schedule", #"name" , #"image3.jpg", #"image" , #"Sun June 30 VS Thunders # Home \n MOn June 31 VS Braves # away \n Tue July 1 VS East Cobb # Home \n", #"description", nil]];
[buckheadThunderArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Upcomming Events", #"name" , #"image4.jpg", #"image" , #"This is the list of the upcomming events for the month of july:\nJuly 1st:\nBake them all.\nJuly 2nd:\nFamily reunion\nJuly 3rd:\nSuppliers convention.", #"description", nil]];
[buckheadThunderArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Roster", #"name" , #"image5.jpg", #"image" , #"Jim this 17\nTim duncan 22\nJim thalos 21\nFredrick nitche 24\n", #"description", nil]];
[fultonEastArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Coaches", #"name" , #"image1.JPG", #"image" , #"Mark Bayle 3rd Base\nSusane Ballor First Base\nJim Thally Pitching\nSam Bradley Batting", #"description", nil]];
[fultonEastArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Team Outlook", #"name" , #"image2.jpg", #"image" , #"our team has won 26 out of the 35 and it is in first place. We have 2 players on DL and have recalled two players to replace them.", #"description", nil]];
[fultonEastArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Schedule", #"name" , #"image3.jpg", #"image" , #"Sun June 30 VS Thunders # Home \n MOn June 31 VS Braves # away \n Tue July 1 VS East Cobb # Home \n", #"description", nil]];
[fultonEastArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Upcomming Events", #"name" , #"image4.jpg", #"image" , #"This is the list of the upcomming events for the month of july:\nJuly 1st:\nBake them all.\nJuly 2nd:\nFamily reunion\nJuly 3rd:\nSuppliers convention.", #"description", nil]];
[fultonEastArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Roster", #"name" , #"image5.jpg", #"image" , #"Jim this 17\nTim duncan 22\nJim thalos 21\nFredrick nitche 24\n", #"description", nil]];
[atlantaBravesArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Coaches", #"name" , #"image1.JPG", #"image" , #"Mark Bayle 3rd Base\nSusane Ballor First Base\nJim Thally Pitching\nSam Bradley Batting", #"description", nil]];
[atlantaBravesArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Team Outlook", #"name" , #"image2.jpg", #"image" , #"our team has won 26 out of the 35 and it is in first place. We have 2 players on DL and have recalled two players to replace them.", #"description", nil]];
[atlantaBravesArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Schedule", #"name" , #"image3.jpg", #"image" , #"Sun June 30 VS Thunders # Home\nMon June 31 VS Braves # away\nTue July 1 VS East Cobb # Home\n", #"description", nil]];
[atlantaBravesArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Upcomming Events", #"name" , #"image4.jpg", #"image" , #"This is the list of the upcomming events for the month of july:\nJuly 1st:\nBake them all.\nJuly 2nd:\nFamily reunion\nJuly 3rd:\nSuppliers convention.", #"description", nil]];
[atlantaBravesArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Roster", #"name" , #"image5.jpg", #"image" , #"Jim this 17\nTim duncan 22\nJim thalos 21\nFredrick nitche 24\n", #"description", nil]];
if (teamsInt == 0) {
[data addObject:eastCobbArray];
}
if (teamsInt == 1) {
[data addObject:westCobbArray];
}
if (teamsInt == 2) {
[data addObject:buckheadThunderArray];
}
if (teamsInt == 3) {
[data addObject:fultonEastArray];
}
if (teamsInt == 4) {
[data addObject:atlantaBravesArray];
}
}
- (void)viewDidUnload{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Table view data source
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [sectionArray objectAtIndex:section];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
// Return the number of sections.
return [sectionArray count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [[data objectAtIndex:section] count];
[self.tableView reloadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell1";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell...
UIImageView *imageView = [[UIImageView alloc] initWithFrame:cell.frame];
UIImage *image = [UIImage imageNamed:#"bgp.png"];
imageView.image = image;
cell.backgroundView = imageView;
[[cell textLabel] setBackgroundColor:[UIColor clearColor]];
[[cell detailTextLabel] setBackgroundColor:[UIColor clearColor]];
cell.textLabel.text = [[[data objectAtIndex:indexPath.section] objectAtIndex:indexPath.row] objectForKey:#"name"];
return cell;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([[segue identifier] isEqualToString:#"Detail"]){
TeamDetail *teamDetail = [segue destinationViewController];
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
if (teamsInt == 0)
{
teamDetail.teamImageString = [[NSString alloc] initWithString:[[eastCobbArray objectAtIndex:indexPath.row] objectForKey:#"image"]];
teamDetail.teamTextString = [[NSString alloc] initWithString:[[eastCobbArray objectAtIndex:indexPath.row] objectForKey:#"description"]];
teamDetail.title = [[NSString alloc] initWithString:[[eastCobbArray objectAtIndex:indexPath.row] objectForKey:#"name"]];
}
if (teamsInt == 1)
{
teamDetail.teamImageString = [[NSString alloc] initWithString:[[westCobbArray objectAtIndex:indexPath.row] objectForKey:#"image"]];
teamDetail.teamTextString = [[NSString alloc] initWithString:[[westCobbArray objectAtIndex:indexPath.row] objectForKey:#"description"]];
teamDetail.title = [[NSString alloc] initWithString:[[westCobbArray objectAtIndex:indexPath.row] objectForKey:#"name"]];
}
if (teamsInt == 2)
{
teamDetail.teamImageString = [[NSString alloc] initWithString:[[buckheadThunderArray objectAtIndex:indexPath.row] objectForKey:#"image"]];
teamDetail.teamTextString = [[NSString alloc] initWithString:[[buckheadThunderArray objectAtIndex:indexPath.row] objectForKey:#"description"]];
teamDetail.title = [[NSString alloc] initWithString:[[buckheadThunderArray objectAtIndex:indexPath.row] objectForKey:#"name"]];
}
if (teamsInt == 3)
{
teamDetail.teamImageString = [[NSString alloc] initWithString:[[fultonEastArray objectAtIndex:indexPath.row] objectForKey:#"image"]];
teamDetail.teamTextString = [[NSString alloc] initWithString:[[fultonEastArray objectAtIndex:indexPath.row] objectForKey:#"description"]];
teamDetail.title = [[NSString alloc] initWithString:[[fultonEastArray objectAtIndex:indexPath.row] objectForKey:#"name"]];
}
if (teamsInt == 4)
{
teamDetail.teamImageString = [[NSString alloc] initWithString:[[atlantaBravesArray objectAtIndex:indexPath.row] objectForKey:#"image"]];
teamDetail.teamTextString = [[NSString alloc] initWithString:[[atlantaBravesArray objectAtIndex:indexPath.row] objectForKey:#"description"]];
teamDetail.title = [[NSString alloc] initWithString:[[atlantaBravesArray objectAtIndex:indexPath.row] objectForKey:#"name"]];
}
}
}
#end
TeamDetail.h
#interface TeamDetail : UIViewController{
IBOutlet UIImageView *teamImage;
IBOutlet UITextView *teamText;
NSString *teamImageString;
NSString *teamTextString;
}
#property (nonatomic, retain) NSString *teamImageString;
#property (nonatomic, retain) NSString *teamTextString;
#end
TeamDetail.m
#implementation TeamDetail
#synthesize teamImageString, teamTextString;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"bcp.png"]];
teamImage.image = [UIImage imageNamed:teamImageString];
teamText.text = teamTextString;
// Do any additional setup after loading the view.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
now the connections and segue identifiers are fine and working it drills down all the way to detailview but only shows the first array information and sections and the rest of the arrays are not showing.
thanks in advance for your help
adrian
Anyway it seems that I find your mistake )
You obtain item like this, right:
if (teamsInt == 0)
{
teamDetail.teamImageString = [[NSString alloc] initWithString:[[eastCobbArray objectAtIndex:indexPath.row] objectForKey:#"image"]];
teamDetail.teamTextString = [[NSString alloc] initWithString:[[eastCobbArray objectAtIndex:indexPath.row] objectForKey:#"description"]];
teamDetail.title = [[NSString alloc] initWithString:[[eastCobbArray objectAtIndex:indexPath.row] objectForKey:#"name"]];
}
But look carefully - you use indexPath.row but should use indexPath.section instead! Your row is always 0.
Try this (ready for copy-paste ;)):
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([[segue identifier] isEqualToString:#"Detail"]){
TeamDetail *teamDetail = [segue destinationViewController];
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
if (teamsInt == 0)
{
teamDetail.teamImageString = [[NSString alloc] initWithString:[[eastCobbArray objectAtIndex:indexPath.section] objectForKey:#"image"]];
teamDetail.teamTextString = [[NSString alloc] initWithString:[[eastCobbArray objectAtIndex:indexPath.section] objectForKey:#"description"]];
teamDetail.title = [[NSString alloc] initWithString:[[eastCobbArray objectAtIndex:indexPath.section] objectForKey:#"name"]];
}
if (teamsInt == 1)
{
teamDetail.teamImageString = [[NSString alloc] initWithString:[[westCobbArray objectAtIndex:indexPath.section] objectForKey:#"image"]];
teamDetail.teamTextString = [[NSString alloc] initWithString:[[westCobbArray objectAtIndex:indexPath.section] objectForKey:#"description"]];
teamDetail.title = [[NSString alloc] initWithString:[[westCobbArray objectAtIndex:indexPath.section] objectForKey:#"name"]];
}
if (teamsInt == 2)
{
teamDetail.teamImageString = [[NSString alloc] initWithString:[[buckheadThunderArray objectAtIndex:indexPath.section] objectForKey:#"image"]];
teamDetail.teamTextString = [[NSString alloc] initWithString:[[buckheadThunderArray objectAtIndex:indexPath.section] objectForKey:#"description"]];
teamDetail.title = [[NSString alloc] initWithString:[[buckheadThunderArray objectAtIndex:indexPath.section] objectForKey:#"name"]];
}
if (teamsInt == 3)
{
teamDetail.teamImageString = [[NSString alloc] initWithString:[[fultonEastArray objectAtIndex:indexPath.section] objectForKey:#"image"]];
teamDetail.teamTextString = [[NSString alloc] initWithString:[[fultonEastArray objectAtIndex:indexPath.section] objectForKey:#"description"]];
teamDetail.title = [[NSString alloc] initWithString:[[fultonEastArray objectAtIndex:indexPath.section] objectForKey:#"name"]];
}
if (teamsInt == 4)
{
teamDetail.teamImageString = [[NSString alloc] initWithString:[[atlantaBravesArray objectAtIndex:indexPath.section] objectForKey:#"image"]];
teamDetail.teamTextString = [[NSString alloc] initWithString:[[atlantaBravesArray objectAtIndex:indexPath.section] objectForKey:#"description"]];
teamDetail.title = [[NSString alloc] initWithString:[[atlantaBravesArray objectAtIndex:indexPath.section] objectForKey:#"name"]];
}
}
}
p.s Consider about refactoring your code.
Do not add objects to array, create it in one string like:
teamArray = [[NSMutableArray alloc] initWithObjects:#"East Cobb", #"West Cobb", #"Buckhead Thunder", #"Fulton East", #"Atlanta Braves", nil];
or:
teamArray = #[#"East Cobb", #"West Cobb", #"Buckhead Thunder", #"Fulton East", #"Atlanta Braves"];
Use switch instaed of if() with numerical values
> teams.teamsInt = indexPath.row;
> switch (indexPath.row) {
> case:0
> teams.title = [teamArray objectAtIndex:indexPath.row];
> break;
> //and so on

How can I change this code so that it doesn't infringe MVC principles?

I am making a quiz app for chemistry reactions. The app gives the user a question, and the user types in the reactants and products in two separate textfields.
I have a data class, which contains all the possible quiz questions. Then, based on specific parameters, the data class selects a certain amount of questions from the pool of possible questions and shuffles them into an array, quizQuestions.
I also have a view controller, quizController. For each question, a new instance of quizController is loaded. The vc needs the data to know which question to display, what the correct answer is, etc.
This is my original solution to communicate between the data and the vc's.
I create an instance of the data class, data.
I create vc1 for the first question, and set data as a property of vc1, and set its tag as 1, so that it loads the 1st question from the data.
After the user answers the first question, I create a new view controller, vc2, in a method of vc1, make the tag 1 more than the last vc's so that the second question loads, and pass data from vc1's property to vc2's.
And then I repeat for the other questions.
However, this is not very good design, and I am looking for a better solution. I don't think I can use a class method because the data is supposed to contain a random set of questions. Below I have the code for the data class.
// the data class as it is now, designed for instance methods
- (id)init {
self = [super init];
if (self) {
//Questions of the same type belong to a "ROW" (Reaction of Week)
//individual questions
// Items in array: (1)Question, (2)Reactants, (3)Products, (4)Elements for keyboard
NSArray *R1Q1 = [[NSArray alloc] initWithObjects:#"Methanol is burned completely in air", #"2CH₃OH(l) + 3O₂(g)", #"2CO₂(g) + 4H₂O", #"C,H,O", nil];
NSArray *R1Q2 = [[NSArray alloc] initWithObjects:#"Ammonia is burned in excess oxygen gas", #"4NH₃(g) + 7H₂O(l)", #"4NO₂(g) + 6H₂O(l)", #"N,H,O", nil];
NSArray *R1Q3 = [[NSArray alloc] initWithObjects:#"Hydrogen sulfide gas is burned in excess oxygen gas", #"2H₂S(g) + 3O₂(g)", #"CO₂(g) + 2SO₂(g)", #"H,S,O", nil];
NSArray *R2Q1 = [[NSArray alloc] initWithObjects:#"Solid potassium is added to a flask of oxygen gas", #"K(s) + O₂(g)", #"KO₂(s)", #"K,O", nil];
NSArray *R2Q2 = [[NSArray alloc] initWithObjects:#"Sodium metal is dropped into a flask of pure water", #"2Na(s) + H₂O(l)", #"2Na⁺(aq) + 2OH⁻(aq) + H₂(g)", #"Na,H,O", nil];
NSArray *R2Q3 = [[NSArray alloc] initWithObjects:#"A piece of lithium is heated strongly in oxygen", #"4Li(s) + O₂(g)", #"2Li₂O(s)", #"Li,O", nil];
NSArray *R3Q1 = [[NSArray alloc] initWithObjects:#"Solutions of potassium chloride and silver nitrate are mixed", #"Ag⁺(aq) + Cl⁻(aq)", #"AgCl(s)", #"K,Cl,Ag,N,O", nil];
NSArray *R3Q2 = [[NSArray alloc] initWithObjects:#"Solutions of iron(III) nitrate and sodium hydroxide are mixed", #"Fe³⁺(aq) + 3OH⁻(aq)", #"Fe(OH)₃(s)", #"Fe,N,O,Na,H", nil];
NSArray *R3Q3 = [[NSArray alloc] initWithObjects:#"Solutions of nickel iodide and barium hydroxide are mixed", #"Ni²⁺(aq) + 2OH⁻(aq)", #"Ni(OH)₂(s)", #"Ni,I,Ba,OH", nil];
// add rest
//organize questions into groups
row1 = [[NSArray alloc] initWithObjects:R1Q1, R1Q2, R1Q3, nil];
row2 = [[NSArray alloc] initWithObjects:R2Q1, R2Q2, R2Q3, nil];
row3 = [[NSArray alloc] initWithObjects:R3Q1, R3Q2, R3Q3, nil];
//add rest
// array containing all questions
allRows = [[NSMutableArray alloc] initWithObjects:row1, row2, row3, nil];
//in a real situation, needs to be given to class dynamically
self.maxRowNumber = 3;
self.questionsPerRow = 2;
}
return self;
}
- (void)selectQuestions {
self.quizQuestions = [[NSMutableArray alloc] init];
for (int j = 0; j<self.maxRowNumber; j++) {
//shuffle each row
NSMutableArray *row = [NSMutableArray arrayWithArray:[allRows objectAtIndex:j]];
[row shuffle];
//add questions from each row
for (int k = 0; k<self.questionsPerRow; k++)
[quizQuestions addObject:[row objectAtIndex:k]];
}
[quizQuestions shuffle];
}
View Controller code excerpts
# pragma mark Cell Setup
//1st cell in tableview
- (void) setUpEquationCell: (UITableView *) tableView {
equationCell = (EquationCell *) [tableView dequeueReusableCellWithIdentifier:#"equationCell"];
if (equationCell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"EquationCell" owner:self options:nil];
equationCell = (EquationCell*) [nib objectAtIndex:0];
[equationCell.leftButton addTarget:self action:#selector(addDissociateCell) forControlEvents:UIControlEventTouchUpInside];
[equationCell.rightButton addTarget:self action:#selector(addBalanceCell) forControlEvents:UIControlEventTouchUpInside];
}
}
- (void) setUpBalanceCell: (UITableView *) tableView {
//2nd cell in tableview
balanceCell = (BalanceCell *) [tableView dequeueReusableCellWithIdentifier:#"balanceCell"];
if (balanceCell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"BalanceCell" owner:self options:nil];
balanceCell = (BalanceCell*) [nib objectAtIndex:0];
// stores data from equation cell into model
for (FormulaLabel *label in equationCell.leftView.equationOrder)
[leftData.equation addObject:label.text];
for (FormulaLabel *label in equationCell.rightView.equationOrder)
[rightData.equation addObject:label.text];
[leftData setUpBalancedEquation];
[rightData setUpBalancedEquation];
[self setUpView:balanceCell.leftView fromArray:leftData.equation toArray:leftBalanceItems];
[self setUpView:balanceCell.rightView fromArray:rightData.equation toArray:rightBalanceItems];
[self addBalanceTapMethodInArray:leftBalanceItems Data:leftData];
[self addBalanceTapMethodInArray:rightBalanceItems Data:rightData];
}
}
- (void) setUpDissociateCell: (UITableView *) tableView {
dissCell = (DissociateCell *) [tableView dequeueReusableCellWithIdentifier:#"dissCell"];
if (dissCell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"DissociateCell" owner:self options:nil];
dissCell = (DissociateCell*) [nib objectAtIndex:0];
leftData.disEquation = [[NSMutableArray alloc] init];
rightData.disEquation = [[NSMutableArray alloc] init];
// stores data from equation cell into model
for (FormulaLabel *label in equationCell.leftView.equationOrder)
[leftData.disEquation addObject:label.text];
for (FormulaLabel *label in equationCell.rightView.equationOrder)
[rightData.disEquation addObject:label.text];
[self setUpView:dissCell.leftView fromArray:leftData.disEquation toArray:leftDisItems];
[self setUpView:dissCell.rightView fromArray:rightData.disEquation toArray:rightDisItems];
[self addDissTapToArray:leftDisItems fromData:leftData inView:dissCell.leftView];
[self addDissTapToArray:rightDisItems fromData:rightData inView:dissCell.rightView];
[dissCell.dissociateButton addTarget:self action:#selector(dissociate) forControlEvents:UIControlEventTouchUpInside];
}
[dissCell.rightButton addTarget:self action:#selector(addBalanceCell) forControlEvents:UIControlEventTouchUpInside];
}
- (void)addDissociateCell {
[cellOrder addObject:#"dissociateCell"];
[table reloadData];
NSIndexPath *myIndexPath = [NSIndexPath indexPathForRow:0 inSection:([cellOrder count]-1)];
[table scrollToRowAtIndexPath:myIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
- (void) addDissTapToArray:(NSMutableArray*)viewOrder fromData:(EquationData*)data inView:(UIView*)view {
NSString *leftOrRight;
if (view == dissCell.leftView)
leftOrRight = #"left";
else
leftOrRight = #"right";
for (int j=0; j < [viewOrder count]; j++) {
if (j%2==0) {
UIView *formulaView = [viewOrder objectAtIndex:j];
//dissociate method
FalseTarget *target = [[FalseTarget alloc] initWithVC:self leftOrRightView:leftOrRight];
UITapGestureRecognizer* tap = [[UITapGestureRecognizer alloc] initWithTarget:target action:#selector(dissTap:)];
[formulaView addGestureRecognizer:tap];
// cancelling method
FalseTarget *target2 = [[FalseTarget alloc] initWithVC:self Data:data ViewList:viewOrder view:view];
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:target2 action:#selector(dissLongTap:)];
[formulaView addGestureRecognizer:longPress];
}
}
}
- (void)addCompoundToLabel:(UIGestureRecognizer *)recognizer leftOrRight:(NSString*)leftRight{
if( [recognizer state] == UIGestureRecognizerStateEnded ) {
FormulaLabel* label = (FormulaLabel*)[recognizer view];
dissIndex = label.tag;
dissCell.unDissociated.text = label.text;
currentDissCellView = leftRight;
}
}
- (void)dissociate {
EquationData *data;
NSMutableArray *viewOrder;
UIView *view;
if ([currentDissCellView isEqualToString:#"left"]) {
data = leftData;
viewOrder = leftDisItems;
view = dissCell.leftView;
}
else {
data = rightData;
viewOrder = rightDisItems;
view = dissCell.rightView;
}
FormulaLabel *c1 = [dissCell.leftTextField.equationOrder objectAtIndex:0];
FormulaLabel *c2 = [dissCell.rightTextField.equationOrder objectAtIndex:0];
[data updateDisEquationAtIndex:dissIndex withCompound1:c1.text Compound2:c2.text];
for (UIView *view in viewOrder)
[view removeFromSuperview];
[viewOrder removeAllObjects];
[self setUpView:view fromArray:data.disEquation toArray:viewOrder];
[self addDissTapToArray:viewOrder fromData:data inView:view];
}
- (void) cancelIons:(id)sender fromData:(EquationData *)data inView:(UIView *)view withViewList:(NSMutableArray *)viewlist {
if( [sender state] == UIGestureRecognizerStateEnded ) {
FormulaLabel* label = (FormulaLabel*)[sender view];
int index = label.tag;
[data.disEquation removeObjectAtIndex:index];
for (UIView *formulaView in viewlist)
[formulaView removeFromSuperview];
[viewlist removeAllObjects];
[self setUpView:view fromArray:data.disEquation toArray:viewlist];
[self addDissTapToArray:viewlist fromData:data inView:view];
}
}
- (void)addBalanceCell {
[cellOrder addObject:#"balanceCell"];
[table reloadData];
NSIndexPath *myIndexPath = [NSIndexPath indexPathForRow:0 inSection:([cellOrder count]-1)];
[table scrollToRowAtIndexPath:myIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
leftBalanceItems = [[NSMutableArray alloc] init];
rightBalanceItems = [[NSMutableArray alloc] init];
}
- (void) addBalanceTapMethodInArray:(NSMutableArray *)balanceItems Data:(EquationData *)data {
FalseTarget *target = [[FalseTarget alloc] initWithVC:self Data:data ViewList:balanceItems view:nil];
for (UIView *view in balanceItems) {
UITapGestureRecognizer* tap = [[UITapGestureRecognizer alloc] initWithTarget:target action:#selector(tap:)];
[view addGestureRecognizer:tap];
}
}
- (void)updateBalanceLabelofSender:(UIGestureRecognizer*)sender fromData:(EquationData *)data inArray:(NSMutableArray *)balanceItems {
FormulaLabel* label = (FormulaLabel*)[sender view];
int oldWidth = label.frame.size.width;
label.text = [data updateBalancedatIndex:label.tag];
[label sizeToFit];
int newWidth = label.frame.size.width;
int difference = newWidth - oldWidth;
int labelIndex = label.tag * 2;
for (int j = 0; j<[balanceItems count]; j++) {
// adjusts coordinate of all views to the right of tapped item
if (j > labelIndex){
UIView *item = [balanceItems objectAtIndex:j];
item.frame = CGRectMake(item.frame.origin.x + difference, item.frame.origin.y, item.frame.size.width, item.frame.size.height);
}
}
}
- (void)setUpView:(UIView *)view fromArray:(NSMutableArray *)equationData toArray:(NSMutableArray *)balanceItems {
int labelCount = 0; //label #
int startingPoint = 5; //x vaiue where first label starts
for (NSString *equationText in equationData) {
//add text
FormulaLabel *tempLabel = [[FormulaLabel alloc] initWithFrame:CGRectMake(startingPoint, 2, 10, 22)];
tempLabel.text = equationText;
[tempLabel sizeToFit];
[view addSubview:tempLabel];
tempLabel.tag = labelCount;
[balanceItems addObject:tempLabel];
//set location of '+'
startingPoint = tempLabel.frame.origin.x + tempLabel.frame.size.width + 3;
if (labelCount != [equationData count]-1) { //not the last label
UILabel *plus = [[[UILabel alloc] initWithFrame:CGRectMake(startingPoint, 5, 10, 10)]autorelease];
plus.text = #"+";
plus.font = [UIFont systemFontOfSize:13];
[plus sizeToFit];
[view addSubview:plus];
startingPoint = plus.frame.origin.x + plus.frame.size.width + 3;
[balanceItems addObject:plus];
}
labelCount ++;
[tempLabel release];
}
}
Why can't you use one view controller class with a question-property where you overload the property's setter method to update the UI to the new data:
in QuestionViewController.h file:
#property (retain, nonatomic) Question* myQuestionData;
in QuestionViewController.m
-(void) setMyQuestionData:(Question*)newData {
[myQuestionData autorelease];
myQuestionData = [newData retain];
[self updateUIElements];
}
I wouldn't do like that, because you are forcing the UIViewController to know about the data model (while making it it's property). What I would do, would be a class and using class methods (and not object methods) would create the data source. You would still have to hold the data in the UIViewController somehow, but I think a NSArray or a NSDictionary would be good enough:
-(void)viewDidLoad{
[superViewDidLoad];
myArray = [MyModel createDataSourceForTag:myTag];
}
I guess here you should go with Model structure.
1. Model: Model represents to entity. Here in your case, there i can create two entities Round, Question
#interface Round: NSObject {
NSUInteger *roundId; // 1, 2 = if it is required to check then this mi
NSArray *questions; // Array that contains objects for Question entity
}
#interface Question:NSObject {
NSString *questionText;
NSString *options1Text;
NSString *options2Text;
NSString *options3Text;
}
#interface DataManager:NSObject {
NSArray *rounds; // Array that contains object for Round entity
}
+(void)sharedInstance;
2. DataManger: DataManager will manage your entity objects. This data manager will be an sharedInstance class. So while initializing manager, entities will be created and data will be inserted.
3. ViewController: Now in view controller you can directly use sharedInstace, like this:
[[DataManager sharedInstance] rounds]
You can easily get code for creating sharedInstance class.
Now you can use this rounds anywhere in the entire application.
So it will be quiet easy to access. For example, if you require 1st round 2nd question 3rd option then, write code for same way
Round 1
Round *r = [[[DataManager sharedInstance] rounds] objectAtIndex:0];
Question 2
Question *q = [[r questions] objectAtIndex:1];
Question Text and Option 3
NSLog(#"questionText : %# 3rd Option: %#", q.questionText, q.option3Text)
Enjoy Coding :)

CoreData - could not locate an NSManagedObjectModel

I'm getting the error below, I don't know what I'm doing wrong.
I guess there is the managedobject which cannot be located, but... arf !
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '+entityForName: could not locate an NSManagedObjectModel for entity name 'Boxes''
here is my .m ( only the two main functions )
- (void)loadCoreData
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"Test" object:self];
context = [app managedObjectContext];
NSError *err;
// GET THE JSON
NSString *urlString = [NSString stringWithFormat:#"http://localhost:8888/json.txt"];
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlString]];
NSMutableArray *json = (NSMutableArray* )[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&err];
// FILL THE ENTITY
for (int i = 0; i != 7; i++)
{
Boxes *boxes = [NSEntityDescription insertNewObjectForEntityForName:#"Boxes" inManagedObjectContext:context];
boxes.name = [[[json valueForKey:#"boxesDetail"] objectAtIndex:i] valueForKey:#"name"] ;
boxes.sexe = [[[json valueForKey:#"boxesDetail"] objectAtIndex:i] valueForKey:#"sexe"] ;
boxes.topic = [[[json valueForKey:#"boxesDetail"] objectAtIndex:i] valueForKey:#"topic"] ;
boxes.number = [NSNumber numberWithInt:[[[[json valueForKey:#"boxesDetail"] objectAtIndex:i] valueForKey:#"number"] intValue]];
}
request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Boxes" inManagedObjectContext:context];
[request setEntity:entity];
arrayForPredicate = [context executeFetchRequest:request error:&err];
}
- (void) fillSexArray:(NSString *)sexe
{
// PREDICATE TO GET AN ARRAY OF PRODUCT WITH SEXE EQUAL TO
NSPredicate *sex;
if ([sexe isEqualToString:#"both"])
{
sex = [NSPredicate predicateWithFormat:#"sexe = %# OR sexe = %#", #"female", #"male"];
}
else
{
sex = [NSPredicate predicateWithFormat:#"sexe = %#", sexe];
}
NSArray *BoxWithSex = [arrayForPredicate filteredArrayUsingPredicate:sex];
NSMutableArray *mutableArray = [self createMutableArray:BoxWithSex];
// NSLog(#"%#", [[mutableArray objectAtIndex:1] valueForKey:#"name"]);
// NSUInteger numObjects = [mutableArray count];
}
my .h :
#interface AddViewController : UIViewController
{
IBOutlet UIButton *male;
IBOutlet UIButton *female;
IBOutlet UIButton *couple;
UIButton *maleBtn;
BOOL flag;
NSArray *arrayForPredicate;
NSFetchedResultsController *fetchedResultsController;
NSManagedObjectContext *context;
NSFetchRequest *request;
}
#property (nonatomic, retain) WonderAppDelegate *app;
- (void) fillSexArray:(NSString *)sexe;
- (NSMutableArray *)createMutableArray:(NSArray *)array;
- (void)loadCoreData;
- (void)sexeButtonPressed;
- (void)sexeArray;
#end
EDIT creating the managedObject :
+ (id)boxWithDictionary:(NSDictionary *)dict withManagedObjectContext:(NSManagedObjectContext *)managedObjectContext;
{
Boxes *boxes = [NSEntityDescription insertNewObjectForEntityForName:#"Boxes"
inManagedObjectContext:managedObjectContext];
boxes.name = [dict objectForKey:#"name"];
boxes.sexe = [dict objectForKey:#"sexe"];
boxes.topic = [dict objectForKey:#"topic"];
boxes.number = [dict objectForKey:#"number"];
return boxes;
}
This is my .m and it is working like that but i don't want the code of the function Add there i want it on loadCoreData.
//
// AddViewController.m
// CoreDataTuto
//
// Created by Clement Yerochewski on 30/04/12.
// Copyright (c) 2012 Weblib. All rights reserved.
//
#import "AddViewController.h"
#import "Boxes.h"
#implementation AddViewController
#synthesize app, context;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
UINavigationBar *navBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, 768, 44)];
UINavigationItem *navItem = [[UINavigationItem alloc] initWithTitle:#"Add Detail"];
[navBar pushNavigationItem:navItem animated:NO];
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithTitle:#"Cancel" style:UIBarButtonItemStylePlain target:self action:#selector(cancel)];
UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithTitle:#"Add" style:UIBarButtonItemStyleBordered target:self action:#selector(add)];
navItem.leftBarButtonItem = cancelButton;
navItem.rightBarButtonItem = addButton;
[self.view addSubview:navBar];
app = [[UIApplication sharedApplication] delegate];
}
return self;
}
- (void) add{
[self dismissModalViewControllerAnimated:YES];
// PREDICATE TO GET AN ARRAY OF PRODUCT WITH A LENGTH NAME <= 5
// NSPredicate *length;
// length = [NSPredicate predicateWithFormat:#"name.length <= 5"];
// NSArray *BoxWithCheapPrice = [array filteredArrayUsingPredicate:length];
// NSLog(#"Box %#", BoxWithCheapPrice);
// PREDICATE TO GET AN ARRAY OF PRODUCT WITH PRICE BETWEEN $MIN AND $MAX
// NSNumber *min = [NSNumber numberWithInteger:30];
// NSNumber *max = [NSNumber numberWithInteger:100];
// NSPredicate *between;
// between = [NSPredicate predicateWithFormat:#"number BETWEEN %#", [NSArray arrayWithObjects:min, max, nil]];
// NSArray *BoxWithPriceBetween = [array filteredArrayUsingPredicate:between];
// NSLog(#"Box %#", BoxWithPriceBetween);
// NSLog(#"%#", [BoxWithPriceBetween valueForKey:#"name"]);
}
- (NSMutableArray *)createMutableArray:(NSArray *)array
{
return [NSMutableArray arrayWithArray:array];
}
- (IBAction) sexeChoosen: (id) sender
{
switch ( ((UIButton*)sender).tag ){
case 0:
[self fillSexArray:#"male"];
break;
case 1:
[self fillSexArray:#"female"];
break;
default:
[self fillSexArray:#"both"];
}
[self sexeButtonPressed];
}
- (void)sexeButtonPressed
{
if (flag)
{
UIImage * maleImg2 = [UIImage imageNamed:#"pressed.png"];
[maleBtn setImage:maleImg2 forState:UIControlStateNormal];
flag = NO;
[self sexeArray];
}
else
{
UIImage * maleImg1 = [UIImage imageNamed:#"unpressed.png"];
[maleBtn setImage:maleImg1 forState:UIControlStateNormal];
flag = YES;
[self sexeArray];
}
}
- (void)sexeArray
{
}
- (void)loadCoreData
{
}
- (void) fillSexArray:(NSString *)sexe
{
context = [app managedObjectContext];
// GET THE JSON
NSString *urlString = [NSString stringWithFormat:#"http://localhost:8888/json.txt"];
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlString]];
NSError *err;
NSMutableArray *json = (NSMutableArray* )[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&err];
// FILL THE ENTITY
for (int i = 0; i != 7; i++)
{
Boxes *boxes = [NSEntityDescription insertNewObjectForEntityForName:#"Boxes" inManagedObjectContext:context];
boxes.name = [[[json valueForKey:#"boxesDetail"] objectAtIndex:i] valueForKey:#"name"] ;
boxes.sexe = [[[json valueForKey:#"boxesDetail"] objectAtIndex:i] valueForKey:#"sexe"] ;
boxes.topic = [[[json valueForKey:#"boxesDetail"] objectAtIndex:i] valueForKey:#"topic"] ;
boxes.number = [NSNumber numberWithInt:[[[[json valueForKey:#"boxesDetail"] objectAtIndex:i] valueForKey:#"number"] intValue]];
}
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Boxes" inManagedObjectContext:context];
[request setEntity:entity];
arrayForPredicate = [context executeFetchRequest:request error:&err];
NSPredicate *sex;
// PREDICATE TO GET AN ARRAY OF PRODUCT WITH SEXE EQUAL TO
if ([sexe isEqualToString:#"both"])
{
sex = [NSPredicate predicateWithFormat:#"sexe = %# OR sexe = %#", #"female", #"male"];
}
else
{
sex = [NSPredicate predicateWithFormat:#"sexe = %#", sexe];
}
NSArray *BoxWithSex = [arrayForPredicate filteredArrayUsingPredicate:sex];
NSMutableArray *mutableArray = [self createMutableArray:BoxWithSex];
NSLog(#"SEXE CHOOSEN %#", mutableArray);
// NSLog(#"%#", [[mutableArray objectAtIndex:1] valueForKey:#"name"]);
NSUInteger numObjects = [mutableArray count];
NSLog(#"%d", numObjects);
}
- (void) cancel{
[self dismissModalViewControllerAnimated:YES];
}
- (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 - View lifecycle
- (void)viewDidLoad
{
flag = YES;
maleBtn = [UIButton buttonWithType:UIButtonTypeCustom];
maleBtn.frame = CGRectMake(40, 47, 107, 75);
[maleBtn setTitle:#"male" forState:UIControlStateNormal];
UIImage * maleImg1 = [UIImage imageNamed:#"unpressed.png"];
[maleBtn setImage:maleImg1 forState:UIControlStateNormal];
[maleBtn addTarget:self action:#selector(sexeChoosen:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:maleBtn];
[self loadCoreData];
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
Have you updated your model after creating the persistent store? Try to delete your app from the simulator (or the database file) and run it again..

removeObjectAtIndex crashing the app

In the .h file I have set the below line.
NSMutableArray *repArray;
In the .m file I have placed the below lines.(I put just the required lines of code for this ex)
-(void)read_data_fromDB
{
objectsForCharacters = [[NSMutableDictionary alloc]init];
sqlite3 *db = [contactAppDelegate getNewDBConnection];
NSMutableString *query = nil;
query = [NSMutableString stringWithFormat:#"select representative, title, business_name, uid from corporate where profiler_type <> 'OWN_CORPORATE' order by representative asc"];
const char *sql = [query UTF8String];
sqlite3_stmt *selectAllStmt = nil;
if(sqlite3_prepare_v2(db,sql, -1, &selectAllStmt, NULL)!= SQLITE_OK)
NSAssert1(0,#"error preparing statement",sqlite3_errmsg(db));
else
{
repArray = [[NSMutableArray alloc]init];
businessArray = [[NSMutableArray alloc]init];
titleArray = [[NSMutableArray alloc]init];
uidArray = [[NSMutableArray alloc]init];
while(sqlite3_step(selectAllStmt)==SQLITE_ROW)
{
char *chrstr =(char *)sqlite3_column_text(selectAllStmt, 0);
if(chrstr !=NULL)
{
corpRepresentative = [NSString stringWithUTF8String:chrstr];
[repArray addObject:corpRepresentative];
}
chrstr =(char *)sqlite3_column_text(selectAllStmt, 1);
if(chrstr !=NULL)
{
corpTitle = [NSString stringWithUTF8String:chrstr];
[titleArray addObject:corpTitle];
}
chrstr =(char *)sqlite3_column_text(selectAllStmt, 2);
if(chrstr !=NULL)
{
corpBusiness_name = [NSString stringWithUTF8String:chrstr];
[businessArray addObject:corpBusiness_name];
}
chrstr =(char *)sqlite3_column_text(selectAllStmt, 3);
if(chrstr !=NULL)
{
corporteUid = [NSString stringWithUTF8String:chrstr];
[uidArray addObject:corporteUid];
}
}
}
sqlite3_finalize(selectAllStmt);
sqlite3_close(db);
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
UILongPressGestureRecognizer *longPressGesture =
[[[UILongPressGestureRecognizer alloc]
initWithTarget:self action:#selector(longPress:)] autorelease];
[cell addGestureRecognizer:longPressGesture];
}
// Configure the cell...
UILabel *txtLbl = [[UILabel alloc]initWithFrame:CGRectMake(70, 0, 175, 26)];
//[txtLbl setBackgroundColor:[UIColor greenColor]];
[txtLbl setTextAlignment:UITextAlignmentLeft];
NSString *txtStr = [repArray objectAtIndex:indexPath.row];
UIFont *fontTxtLbl = [UIFont fontWithName: #"FuturaMdBT" size:16];
[txtLbl setFont:fontTxtLbl];
[txtLbl setText:txtStr];
[cell.contentView addSubview:txtLbl];
[txtLbl release];
UILabel *txtDetailLbl = [[UILabel alloc]initWithFrame:CGRectMake(70, 27, 175, 20)];
// [txtDetailLbl setBackgroundColor:[UIColor redColor]];
[txtDetailLbl setTextAlignment:UITextAlignmentLeft];
NSString *txtDetailStr = [titleArray objectAtIndex:indexPath.row];
UIFont *fontTxtDetailLbl = [UIFont fontWithName: #"Arial" size:12];
[txtDetailLbl setFont:fontTxtDetailLbl];
[txtDetailLbl setText:txtDetailStr];
[cell.contentView addSubview:txtDetailLbl];
[txtDetailLbl release];
UILabel *txtDetailLbl1 = [[UILabel alloc]initWithFrame:CGRectMake(70, 47, 175, 20)];
//[txtDetailLbl1 setBackgroundColor:[UIColor blueColor]];
[txtDetailLbl1 setTextAlignment:UITextAlignmentLeft];
NSString *txtDetailStr1 = [businessArray objectAtIndex:indexPath.row];
UIFont *fontTxtDetailLbl1 = [UIFont fontWithName: #"Arial" size:12];
[txtDetailLbl1 setFont:fontTxtDetailLbl1];
[txtDetailLbl1 setText:txtDetailStr1];
[cell.contentView addSubview:txtDetailLbl1];
[txtDetailLbl1 release];
// cell.textLabel.text = [repArray objectAtIndex:indexPath.row];
//cell.detailTextLabel.text = [titleArray objectAtIndex:indexPath.row];
cell.imageView.image=[imagearray objectAtIndex:indexPath.row];
UIView *viewSelected = [[[UIView alloc] init] autorelease];
viewSelected.backgroundColor = [UIColor colorWithRed:224.0/255.0
green:229.0/255.0
blue:241.0/255.0
alpha:1.0];
cell.selectedBackgroundView = viewSelected;
cell.textLabel.highlightedTextColor=[UIColor colorWithRed:46.0/255.0
green:77.0/255.0
blue:141.0/255.0
alpha:1.0];
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *tempUID = [uidArray objectAtIndex:indexPath.row];
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setObject:tempUCID forKey:#"corpUcid"];
[prefs setObject:#"PROFILER" forKey:#"selProfiler"];
CorpPrevFront *corpPrevFront = [[CorpPrevFront alloc]initWithNibName:#"CorpPrevFront" bundle:nil];
[self.navigationController pushViewController:corpPrevFront animated:NO];
[corpPrevFront release];
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
//FOR VIEW
if (buttonIndex == 1 && [alertView tag] == 1) {
// IT WILL BE MATCH ON CorpPrevFront CLASS
}
//FOR DELETE
if(buttonIndex == 2 && [alertView tag] == 1){
} else if(buttonIndex == 1 && [alertView tag] == 2){
DeleteProfiler *delProfiler = [[DeleteProfiler alloc]init];
BOOL del = [delProfiler deleteProfiler:selectedCpUid];
//[delProfiler deleteProfiler:selectedCpUcid];
if (del == YES) {
[repArray removeObjectAtIndex:selectedIndexPath.section];
[businessArray removeObjectAtIndex:selectedIndexPath.row];
[titleArray removeObjectAtIndex:selectedIndexPath.row];
[ucidArray removeObjectAtIndex:selectedIndexPath.row];
[self.corporateTable reloadData];
}
}
}
I am trying to delete an array element from a method. If I execute the below line then the app crashes automatically in my iPod Touch. But it works fine in simulator without any errors.
[repArray removeObjectAtIndex:selectedIndexPath.row];
or
[repArray removeObjectAtIndex:0];
both crashes the app even if I have more than one elements in array.
When you app crashes like that, 99% of the time you are trying to remove an object beyond the bounds of array.

cannot delete the right cell in the table

I am making a small app. And having a trouble right now. Trouble by deleting a table customized cell.
it keep removing the top cell instead of the right selected cell. I delete cell number 20, it still delete the cell number 1. I don't know why. please help me out. Really appreciate.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
[sortedArray removeObjectAtIndex:indexPath.row];
[self.tableView reloadData];
}
and here is the array:
- (void)viewDidLoad
{
[super viewDidLoad];
if (detail == nil) {
detail = [[UrlDetail alloc] init];
}
NSString *path = [[NSBundle mainBundle] pathForResource:#"data" ofType:#"plist"];
self.arrayData = [NSMutableArray arrayWithContentsOfFile:path];
NSMutableArray *filterArr = [self filterArray];
sortedArray = [[NSMutableArray alloc] initWithArray:filterArr copyItems:YES];
self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
target:self
action:#selector(actionAddNewURL:)] autorelease];
}
and here is the filter function:
-(NSMutableArray *)filterArray
{
NSMutableArray *filterArr = [[NSMutableArray alloc] init];
NSMutableArray *tempArray = [[NSMutableArray alloc] init];
[filterArr addObject:tempArray];
[tempArray release];
for (NSDictionary *item in arrayData) {
if ([tempArray count]==0)
{
[tempArray addObject:item];
}
else
{
NSDictionary *anItem = [tempArray objectAtIndex:0];
NSString *first = [[anItem objectForKey:#"url"] substringToIndex:1];
NSString *last = [[item objectForKey:#"url"] substringToIndex:1];
if ( [first isEqualToString:last])
{
[tempArray addObject:item];
} else
{
tempArray = [[NSMutableArray alloc] init];
[tempArray addObject:item];
[filterArr addObject:tempArray];
[tempArray release];
}
}
}
// NSMutableArray *newArray = [[NSMutableArray alloc] initWithArray:filterArr copyItems:YES];
return filterArr;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
if([sortedArray count]>0){
NSLog(#"number of section: %d", [sortedArray count]);
return [sortedArray count];
}
return 0;
}
- (NSString *)tableView:(UITableView *)aTableView titleForHeaderInSection:(NSInteger)section
{
if (isTab) {
if ([self.sortedArray count] > section) {
NSDictionary *dictionary = [[sortedArray objectAtIndex:section] objectAtIndex:0];
NSString *string = [dictionary objectForKey:#"url"];
return [NSString stringWithFormat:#"%#", [[string substringToIndex:1] uppercaseString]];
}
else return nil;
} else
{
return nil;
}
}
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
CustomCell *cell = (CustomCell *)[aTableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
[[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil];
cell = myOwnCell;
}
NSDictionary *dataItem = [[sortedArray objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
cell.urlName.text = [dataItem objectForKey:#"url"];
cell.titleLabel.text = [dataItem objectForKey:#"title"];
cell.urlName.font = [UIFont italicSystemFontOfSize:14.0];
cell.imageIcon.image = [UIImage imageNamed:[dataItem objectForKey:#"image"]];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
// Configure the cell.
return cell;
}
Try this one if it works:
- (void) tableView:(UITableView *)aTableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
if (editingStyle == UITableViewCellEditingStyleDelete) {
NSString *key = [[sortedArray allKeys] objectAtIndex:indexPath.row];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationTop];
[sortedArray removeObjectForKey:key];
}
}