I have a view that is inserting information into the database. This view displays that information inside a table view (top half of view is being used for something else)
I have the view controller's class, an object class, and a table view cell class (this is what's throwing me off I think because the image and text labels are in here whereas the actual database information is in the view controller).
Here's the NSObject class:
// car.h
#import <Foundation/Foundation.h>
#interface Car : NSObject {
NSString *displayedMake;
NSString *displayedModel;
NSString *displayedImage;
}
#property (nonatomic, strong) NSString *displayedMake;
#property (nonatomic, strong) NSString *displayedModel;
#property (nonatomic, strong) NSString *displayedImage;
-(id)initWithName:(NSString *)n description:(NSString *)d url:(NSString *)u;
#end
//car.m
#import "Car.h"
#implementation Car
#synthesize displayedMake, displayedModel, displayedImage;
-(id)initWithName:(NSString *)n description:(NSString *)d url:(NSString *)u {
self.displayedMake = n;
self.displayedModel = d;
self.displayedImage = u;
return self;
}
#end
Here's the table view cell class:
//DisplayCarsCell.h
#import <UIKit/UIKit.h>
#interface DisplayCarsCell : UITableViewCell
#property (nonatomic, strong) IBOutlet UIImageView *carImage;
#property (nonatomic, strong) IBOutlet UILabel *makeLabel;
#property (nonatomic, strong) IBOutlet UILabel *modelLabel;
#end
//DisplayCarsCell.m
#import "DisplayCarsCell.h"
#import "ViewController.h"
#implementation DisplayCarsCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
#end
And finally, the view controller:
//ViewController.h
#import <UIKit/UIKit.h>
#import "/usr/include/sqlite3.h"
#interface ViewController : UIViewController <UITableViewDelegate> {
//NSString *databasePath;
sqlite3 *carsDB;
NSArray *carImages;
NSMutableArray *cars;
}
#property (nonatomic, retain) NSMutableArray *cars;
#property (strong, nonatomic) IBOutlet UILabel *status;
#end
//ViewController.m
#import "ViewController.h"
#import "DisplayCarsCell.h"
#import "Car.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize cars;
-(NSString *) filePath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
return [[paths objectAtIndex:0] stringByAppendingPathComponent:#"cars.db"];
}
-(void) openDB {
if (sqlite3_open([[self filePath]UTF8String],&carsDB) != SQLITE_OK){
sqlite3_close(carsDB);
NSAssert(0, #"Database failed to open");
}
else{
NSLog(#"database opened");
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Opens the database and creates the table if its the first time
[self readCarsFromDatabase];
}
- (void)readCarsFromDatabase
{
// Setup the database object
//sqlite3 *database;
// Init the animals Array
cars = [[NSMutableArray alloc] init];
// Open the database from the users filessytem
[self openDB];
const char *sql_stmt = "CREATE TABLE IF NOT EXISTS apps (name text, id text, image text)";
if (sqlite3_exec(carsDB, sql_stmt, NULL, NULL, NULL) == SQLITE_OK)
{
NSLog(#"create db");
}
//Setup the SQL Statement and compile it for faster access
const char *sqlStatement = "select * from apps";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(carsDB, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
// Loop through the results and add them to the feeds array
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
// Read the data from the result row
//image, or first column in table
NSString *displayedImage=[NSString stringWithFormat: #"%s",(const char *)sqlite3_column_text(compiledStatement, 0)];
//name, or second column in table
NSString *displayedMake=[NSString stringWithFormat: #"%s",(const char *)sqlite3_column_text(compiledStatement, 1)];
//model, or third column in table
NSString *displayedModel=[NSString stringWithFormat: #"%s",(const char *)sqlite3_column_text(compiledStatement, 2)];
NSLog(#"%#, %#, %#",displayedImage, displayedMake, displayedModel);
_status.text = displayedMake;
NSLog(#"here");
// Create a new animal object with the data from the database
Car *carObject = [Car alloc];
carObject.displayedImage = [NSString stringWithFormat: #"%s",(const char *)sqlite3_column_text(compiledStatement, 0)];
// Add the animal object to the animals Array
[cars addObject:carObject];
//NSLog(#"%#",displayedImage);
}
}
else
{
printf( "could not prepare statement: %s\n", sqlite3_errmsg(carsDB) );
}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
sqlite3_close(carsDB);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
#pragma mark Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return carImages.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"DisplayCarsCell";
DisplayCarsCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[DisplayCarsCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
// Configure the cell...
//UIImage *displayedImage = [UIImage imageNamed:
//[carImage objectAtIndex: [indexPath row]]];
// Car *carObj = [cars objectAtIndex:indexPath.row];
ViewController *viewController = (ViewController *)[[UIApplication sharedApplication] delegate];
Car *car = (Car *)[viewController.cars objectAtIndex:indexPath.row];
//[cell setImage:car.displayedImage];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// TODO: Select Item
NSLog(#"Selected");}
#end
The view controller itself is getting the array of data obviously from readCarsFromDatabase and is logging each row of the database correctly on viewDidLoad (did this to make sure that part wasn't wrong), but I need it to update the rows of the table view that is inside.
You have to call reloadData for your tableview once you're done adding records to cars, for example at the end of readCarsFromDatabase. I don't see an IBOutlet for the UITableView, but if it was simply tableView, then you'd add a line after sqlite3_close that says:
[self.tableView reloadData];
Obviously, make sure the table view's delegate is set to be your view controller.
Also, I would have thought that the following lines from your view controller's cellForRowAtIndexPath that currently say:
ViewController *viewController = (ViewController *)[[UIApplication sharedApplication] delegate];
Car *car = (Car *)[viewController.cars objectAtIndex:indexPath.row];
should be changed to simply say:
Car *car = self.cars[indexPath.row];
Related
I am creating an iOS app. Since I am a beginner, I started with checking out some tutorials.
I started with creating an app with a Table View. The cells are dynamically filled through a database connection. This works fine.
However now I'm trying to define a push segue that opens a detail view for the cells. These also have to become filled dynamically with data. To achieve this, I started going through this tutorial and got it working up to "Passing Data Using Segue". In that step, you have to assign an identifier to your segue and fill in the prepareForSegue:sender: method.
I believe the implementation of my method causes the above error, because it isn't doing what it's supposed to. Looking up the error did not provide me with (understandable) answers since I fail to see how this problem has arisen.
Could someone please take a look at my code? Thanks in advance.
Main.storyboard:
In case you might be wondering, I did add an identifier to my segue, named showEventDetails.
EventsTableViewController.h
#import <UIKit/UIKit.h>
#import <sqlite3.h>
#interface EventsTableViewController : UITableViewController {
NSMutableArray *EventsArray;
sqlite3 *db;
}
#property (nonatomic, retain) NSMutableArray *EventsArray;
#property (nonatomic, strong) IBOutlet UITableView *eventTable;
-(NSMutableArray *) EventList;
#end
EventsTableViewController.m
#import "EventsTableViewController.h"
#import "TableCellViewController.h"
#import "Event.h"
#import <sqlite3.h>
#implementation EventsTableViewController
#synthesize EventsArray;
#synthesize eventTable;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (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 EventList];
[super viewDidLoad];
}
- (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];
}
- (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 [self.EventsArray count];
}
- (NSMutableArray *) EventList
{
EventsArray = [[NSMutableArray alloc] initWithCapacity:10];
#try {
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSString *dbPath = [[[NSBundle mainBundle] resourcePath]stringByAppendingPathComponent:#"eventsDb.sqlite"];
BOOL success = [fileMgr fileExistsAtPath:dbPath];
if(!success) {
NSLog(#"Cannot locate database file '%#'.", dbPath);
}
if (!(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK)) {
NSLog(#"An error has occured: %s", sqlite3_errmsg(db));
}
const char *sql = "SELECT * FROM events";
sqlite3_stmt *sqlStatement;
if(sqlite3_prepare(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK) {
NSLog(#"Problem with prepare statement: %s", sqlite3_errmsg(db));
}
else {
while (sqlite3_step(sqlStatement) == SQLITE_ROW) {
Event *event = [[Event alloc] init];
event.name = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement, 1)];
event.date = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement, 2)];
event.starttime = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement, 3)];
event.endtime = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement, 4)];
event.location = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement, 5)];
event.description = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement, 6)];
event.favourite = sqlite3_column_int(sqlStatement, 7);
[EventsArray addObject:event];
event = nil;
}
}
sqlite3_finalize(sqlStatement);
}
#catch (NSException *exception) {
NSLog(#"Problem with prepare statement: %s", sqlite3_errmsg(db));
}
#finally {
sqlite3_close(db);
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"EventCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
int rowCount = indexPath.row;
Event *event = [self.EventsArray objectAtIndex:rowCount];
cell.textLabel.text = event.name;
cell.detailTextLabel.text= event.description;
return cell;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showEventDetails"]) {
NSIndexPath *indexPath = [self.eventTable indexPathForSelectedRow];
TableCellViewController *destViewController = segue.destinationViewController;
destViewController.eventName = [EventsArray objectAtIndex:indexPath.row];
}
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
}
#end
TableCellViewController.h
#import <UIKit/UIKit.h>
#interface TableCellViewController : UIViewController
#property(nonatomic, copy) NSString *eventName;
#property(nonatomic, strong) IBOutlet UILabel * eventNameLabel;
#property(nonatomic, copy) NSString *eventDate;
#property(nonatomic, strong) IBOutlet UILabel * eventDateLabel;
#property(nonatomic, copy) NSString *eventStarttime;
#property(nonatomic, strong) IBOutlet UILabel * eventStarttimeLabel;
#property(nonatomic, copy) NSString *eventEndtime;
#property(nonatomic, strong) IBOutlet UILabel * eventEndtimeLabel;
#property(nonatomic, copy) NSString *eventLocation;
#property(nonatomic, strong) IBOutlet UILabel * eventLocationLabel;
#property(nonatomic, copy) NSString *eventDescription;
#property(nonatomic, strong) IBOutlet UILabel * eventDescriptionLabel;
#property(nonatomic, assign) NSInteger eventFavourite;
#property(nonatomic, strong) IBOutlet UILabel * eventFavouriteLabel;
#end
TableCellViewController.m
#import "TableCellViewController.h"
#interface TableCellViewController ()
#end
#implementation TableCellViewController
#synthesize eventName;
#synthesize eventNameLabel;
#synthesize eventDate;
#synthesize eventDateLabel;
#synthesize eventStarttime;
#synthesize eventStarttimeLabel;
#synthesize eventEndtime;
#synthesize eventEndtimeLabel;
#synthesize eventLocation;
#synthesize eventLocationLabel;
#synthesize eventDescription;
#synthesize eventDescriptionLabel;
#synthesize eventFavourite;
#synthesize eventFavouriteLabel;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Set the eventNameLabel with the name of the event
eventNameLabel.text = eventName;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
#end
Thanks again!
This is the offending line:
destViewController.eventName = [EventsArray objectAtIndex:indexPath.row];
You're trying to assign an object of type Event stored in the array, to an object of type NSString.
Since your string is defined with the copy modifier, the assignment tries to copy to object on the right side of the assignment (Event) but apparently this object doesn't conform to the NSCopying protocol, hence the error unrecognized selector... copyWithZone....
This is my View Controller, as you can see, there is a UITableView in the lower part.
I put the delegate and datasource in the .h file
#interface CourseFindrViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
While my .m file is this:
#interface CourseFindrViewController ()
{ sqlite3 *_db;}
#property (nonatomic, weak) IBOutlet UILabel *jNameLabel;
#property (weak, nonatomic) IBOutlet UITextView *jDescLabel;
#property (nonatomic, weak) IBOutlet UILabel *jEarningsLabel;
#property (weak, nonatomic) IBOutlet UITableView *cTableLabel;
#end
#implementation CourseFindrViewController
#synthesize jDetails =_jDetails;
-(void)viewWillAppear:(BOOL)animated {
_jDetails = (Jobs *)self.jDetails;
[self.jNameLabel setText:_jDetails.jName];
[self.jDescLabel setText:_jDetails.jDesc];
[self.jEarningsLabel setText:_jDetails.jEarnings];
NSLog(#"%d", _jDetails.jID);
}
- (void)viewDidUnload
{
[super viewDidUnload];
self.jNameLabel = nil;
self.jDescLabel = nil;
self.jEarningsLabel = nil;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(NSArray *)course;
{
NSString *sqLiteDb = [[NSBundle mainBundle]pathForResource:#"CourseFindr" ofType:#"sqlite"];
sqlite3_stmt *statement;
NSMutableArray *retrieve = [[NSMutableArray alloc] init];
if (sqlite3_open([sqLiteDb UTF8String], &_db) != SQLITE_OK)
{
NSString *query= [NSString stringWithFormat:#"SELECT course. * FROM course INNER JOIN jobsCourse ON jobsCourse.courseID = course.cID WHERE jobsCourse.jobID = %d", _jDetails.jID];
if (sqlite3_prepare_v2(_db, [query UTF8String], -1, &statement, nil) == SQLITE_OK)
{
while (sqlite3_step(statement) == SQLITE_ROW)
{
int _cID = sqlite3_column_int(statement, 0);
char *cNameChars = (char *) sqlite3_column_text(statement,1);
char *cDescChars = (char *) sqlite3_column_text(statement, 2);
char *cSchoolChars = (char *) sqlite3_column_text (statement, 3);
char *cProgramChars = (char *) sqlite3_column_text(statement, 4);
NSString *_cName =cNameChars?[[NSString alloc]initWithUTF8String:cNameChars]:#"";
NSString *_cDesc = cDescChars?[[NSString alloc]initWithUTF8String:cDescChars]:#"";
NSString *_cSchool = cSchoolChars?[[NSString alloc]initWithUTF8String:cSchoolChars]:#"";
NSString *_cProgram = cProgramChars?[[NSString alloc]initWithUTF8String:cProgramChars]:#"";
Course *courses = [[Course alloc]
initWithCID:_cID
cName:_cName
cDesc:_cDesc
cSchool:_cSchool
cProgram:_cProgram];
[retrieve addObject:courses];
}
sqlite3_finalize(statement);
}
}
return retrieve;
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *title1 = _jDetails.jName;
self.navigationItem.title = title1;
}
- (void)dealloc {
}
The code stops here. I added a breakpoint.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.course count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"courseCell"];
NSLog(#"Here.");
Course *courses = [self.course objectAtIndex:indexPath.row];
cell.textLabel.text =courses.cName;
cell.detailTextLabel.text =courses.cSchool;
return cell;
}
And it's still not passing the data to the table.. the table isn't appearing.
You have to add connection between table view and your datasource and delegate.
To do that simple control drag from your table view to view controller and select datasource and do the same but this time select delegate.
You must connect datasource and delegate in the xib. Plese let me know if this answer helped you.
I have a storyboard with tabbed browsing. One of the tabs is a table view. The table is populated by a list of animal "titles". when the title is pressed, a detailed view is opened that displays the title in addition to a sound and the number of times that the animal has been clicked. I have a view controller set up. I also have item.h/m and itemstore.h/m. there is also a detailedviewcontroller. my current problem is that in the item store i have two arays set up but right off the bat xcode is telling me that method definitions aren't found. its also giving my undeclared identifier errors.
FSAnimalsViewController.h (this is my table view controller)
#import <AVFoundation/AVAudioPlayer.h>
#import <UIKit/UIKit.h>
#import "FSDetailViewController.h"
#interface FSAnimalsViewController : UITableViewController
{
}
#end
FSAnimalsViewController.m
#import "FSAnimalsViewController.h"
#import "FSItemStore.h"
#import "FSItem.h"
#implementation FSAnimalsViewController
- (id)init
{
// Call the superclass's designated initializer
self = [super initWithStyle:UITableViewStyleGrouped];
if (self)
{
UINavigationItem *n = [self navigationItem];
[n setTitle:#"FoxSays"];
// Create a new bar button item that will send
// addNewItem: to ItemsViewController
[[self navigationItem] setLeftBarButtonItem:[self editButtonItem]];
}
return self;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[self tableView] reloadData];
}
- (id)initWithStyle:(UITableViewStyle)style
{
return [self init];
}
- (void)tableView:(UITableView *)aTableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
FSDetailViewController *detailViewController = [[FSDetailViewController alloc] init];
NSArray *items = [[FSItemStore defaultStore] allItems];
FSItem *selectedItem = [items objectAtIndex:[indexPath row]];
// Give detail view controller a pointer to the item object in row
[detailViewController setItem:selectedItem];
// Push it onto the top of the navigation controller's stack
[[self navigationController] pushViewController:detailViewController
animated:YES];
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
return [[[FSItemStore defaultStore] allItems] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Set the cell identifier
static NSString *CellIdentifier = #"BasicCell";
// Reuse the cell from the identifier
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell if it doesn't exist
if (!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Log the row for debugging
NSLog(#"%d", [indexPath row]);
// Get object from store
FSItem *item = [[[FSItemStore defaultStore] allItems] objectAtIndex:[indexPath row]];
// Set label to from property in object
[[cell textLabel] setText:[item title]];
return cell;
}
#end
FSItem.h
#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVAudioPlayer.h>
#interface FSItem : NSObject
#property (nonatomic, copy) NSString *title;
#property (nonatomic) SystemSoundID *sound;
#property (nonatomic) int plays;
- (NSArray *)animals;
- (NSArray *)sounds;
#end
FSItem.m
#import <AudioToolbox/AudioToolbox.h>
#import "FSItem.h"
#implementation FSItem
NSString *title;
SystemSoundID *sound;
int plays;
- (NSArray *)animals
{
NSArray *animals = [NSArray arrayWithObjects:#"Dog",#"Cat",#"Bird",#"Mouse",#"Cow",#"Frog",#"Elephant",#"Duck",#"Fish",#"Seal",#"Fox", nil];
return animals;
}
- (NSArray *)sounds
{
NSArray *sounds = [NSArray arrayWithObjects:
#"Woof.mp3",
#"Meow.mp3",
#"tweet.mp3",
#"Squeak.mp3",
#"Moo.mp3",
#"Croak.mp3",
#"Toot.mp3",
#"Quack.mp3",
#"Blub.mp3",
#"OWOwOw.mp3",
#"Fox.mp3",
nil];
return sounds;
}
#end
FSItemStore.h
#import <AVFoundation/AVAudioPlayer.h>
#import <AudioToolbox/AudioToolbox.h>
#import <Foundation/Foundation.h>
#class FSItem;
#interface FSItemStore : NSObject
{
NSMutableArray *allItems;
}
#property (nonatomic) int i;
+ (FSItemStore *)defaultStore;
- (NSArray *)allItems;
- (NSArray *)animals;
- (NSArray *)sounds;
- (FSItem *)createItem;
#end
FSItemStore.m
#import <AudioToolbox/AudioToolbox.h>
#import "FSItem.h"
#import "FSItemStore.h"
#implementation FSItemStore
int i = 0;
- (NSArray *)allItems
{
return allItems;
}
+ (FSItemStore *)defaultStore;
{
static FSItemStore *defaultStore = nil;
if(!defaultStore)
defaultStore = [[super allocWithZone:nil] init];
return defaultStore;
}
- (FSItem *)createItem
{
FSItem *item = [[FSItem alloc] init];
if (i < [animals count])
{
[item setTitle: [animals objectAtIndex: i]];
[item setSound: [sounds objectAtIndex: i]];
[item setPlays: 0];
i++;
[allItems addObject: item];
}
return item;
}
#end
FSItemStore is where my problems seem to be. Its saying that method definition for sounds and animals isn't found and both sounds and animals are undeclared identifiers. Anyone got any ideas?
Your problem is that in your H file you are declaring that your class will implement a method called animals that will return an NSArray, and a method call sounds that will return another NSArray, but in your M file you are not implementing these methods.
In your FSItemStore.m you should implement these methods:
- (NSArray *)animals{
//Do whatever this method is supposed to do, return an NSArray.
}
- (NSArray *)sounds
{
//Do whatever this method is supposed to do, return an NSArray.
}
EDIT
If what you pretend is that FSItemStore inherits the methods from FSItem, you have to declare the interface that way:
#interface FSItemStore : FSItem //FSItem instead of NSObject
{
NSMutableArray *allItems;
}
If I understood your code correctly you want to set one of the animals and sounds initialized in FSItem::sounds and FSItem::animals to the new item that you create in FSItemStore::createItem. So the animals and sounds methods should be executed ont eh correct object - the FSItem object. Change your code in FSItemStore::createItem to this -
- (FSItem *)createItem
{
FSItem *item = [[FSItem alloc] init];
if (i < [animals count])
{
[item setTitle: [[item animals] objectAtIndex: i]];
[item setSound: [[item sounds] objectAtIndex: i]];
[item setPlays: 0];
i++;
[allItems addObject: item];
}
return item;
}
This is still a bad way of doing what you want, as the NSArray will be initialized everytime you create an item. If the number of sounds and animals is fixed, better define them so that they just get initialized once e.g. static objects in FSItem or property on FSItemStore
You haven't defined any properties or variables that are called animals or items. You have only defined the getter methods.
e.g.
#property(nonatomic,strong) NSArray *animals;
#property(nonatomic,strong) NSArray *items;
Then the implementation of your getters, would return these properties.
I'm new to IOS and this is My first crud operation on it And I named this App As BIDDatabaseApp
Kindly be gentle with me i am just a learner i am getting difficulty to debug this problem.
I'm getting the error No visible #interface for BidProducts declares the selector nameProd and descProd which both are the properties at BidProducts , and the same error on NSArray with addObject
Now what i am doing is that i have make a database in Sqlite and use the storyboard with 3buttons for add view and delete.
OK, and this is my file hierarchy
BIDProducts.h
Sub-Class of NSObject
#import <Foundation/Foundation.h>
#interface BIDProducts : NSObject
#property (nonatomic, strong)NSString *nameProd;
#property (nonatomic, strong)NSString *descProd;
#end
BIDProducts.h
#import "BIDProducts.h"
#implementation BIDProducts
#synthesize nameProd,descProd;
#end
BIDViewController.h
here in BIDViewcontroller.h file i am importing the sqlite3.h it is xcode is not getting it by code i am writing it in a static way and it is not giving any error and it is not making a connection with the db also. I am still not able to connect with database.
#import <UIKit/UIKit.h>
#import "sqlite3.h"
#import "BIDProducts.h"
#interface BIDViewController : UIViewController<UITableViewDataSource , UITableViewDelegate>
#property (weak, nonatomic) IBOutlet UITextField *txtNameFeild;
#property (weak, nonatomic) IBOutlet UITextField *txtDescFeild;
#property (weak, nonatomic) IBOutlet UITableView *txtAreaViewList;
- (IBAction)btnAddProduct:(id)sender;
- (IBAction)btnDeleteProduct:(id)sender;
- (IBAction)btnViewProduct:(id)sender;
#end
BIDViewController.M
#import "BIDViewController.h"
#import "BIDProducts.h"
#interface BIDViewController ()
{
NSArray *arrayOFProducts;
sqlite3 *productsDB;
NSString *dbPathString;
}
#end
#implementation BIDViewController
- (void)viewDidLoad
{
[super viewDidLoad];
arrayOFProducts = [[NSMutableArray alloc]init];
[[self txtAreaViewList]setDelegate:self];
[[self txtAreaViewList]setDataSource:self];
[self createOrOpenDb];
// Do any additional setup after loading the view, typically from a nib.
}
-(void)createOrOpenDb
{
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES);
NSString *docPath = [path objectAtIndex:0];
dbPathString = [docPath stringByAppendingPathComponent:#"productsDB.sqlite"];
char *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:dbPathString]) {
const char *dbPath = [dbPathString UTF8String];
if (sqlite3_open(dbPath, &productsDB) == SQLITE_OK) {
const char *sqlStmt = "CREATE TABLE IF NOT EXISTS TBLLISTPRODUCT (ID INTEGER PRIMERYKEY AUTOINCREMENT, PRODNAME VARCHAR, PRODDESC VARCHAR ) ";
sqlite3_exec(productsDB, sqlStmt, NULL, NULL, &error);
sqlite3_close(productsDB);
}
}
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [arrayOFProducts count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
BIDProducts *aProduct = [arrayOFProducts objectAtIndex:indexPath.row];
cell.textLabel.text = aProduct.nameProd;
cell.textLabel.text = aProduct.descProd;
return cell;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)btnAddProduct:(id)sender {
char *error;
if (sqlite3_open([dbPathString UTF8String], &productsDB) == SQLITE_OK) {
NSString *insertStmt = [NSString stringWithFormat:#"INSERT INTO TBLLISTPRODUCT(PRODNAME,PRODDESC) values ('%s', '%s') ", [self.txtNameFeild.text UTF8String] , [self.txtDescFeild.text UTF8String]];
const char *insert_stmt = [insertStmt UTF8String];
if (sqlite3_exec(productsDB, insert_stmt, NULL, NULL, &error) == SQLITE_OK) {
NSLog(#"person added");
BIDProducts *products = [[BIDProducts alloc]init];
[products nameProd:self.txtNameFeild.text];
[products descProd:self.txtDescFeild.text];
[arrayOFProducts addObject:products];
}
sqlite3_close(productsDB);
}
}
- (IBAction)btnDeleteProduct:(id)sender {
}
- (IBAction)btnViewProduct:(id)sender {
}
#end
Your syntax to set a property is wrong, it should be
products.nameProd = self.txtNameFeild.text;
which the compiler translates to the equivalent
[products setNameProd:self.txtNameFeild.text];
And arrayOFProducts should be declared as NSMutableArray
if you want to add objects to it.
(Note that you can remove the #synthesize statements from your source code,
the current Clang compiler synthesizes properties automatically.)
I am new to iOS development and i face weird problem (cuz the same code in both table view controller and sql class works pretty good with other entity).
I am trying to retrive the data from sqlite database to my table view controller..
and this error shows up when i try to insert more than one record in the database.
2012-11-10 19:04:20.577 my app[7032:11303] * Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
* First throw call stack:
Any help will be appreciated.
Thank you.
import <UIKit/UIKit.h>
import "Category.h"
import "DbOperations.h"
import "AddCategoriesTVC.h"
import "CategoryDetailTVC.h"#interface CategoriesTVC : UITableViewController <UITableViewDataSource, UITableViewDelegate,AddCategoriesTVCDelegate, CategoryDetailTVCDelegate>
#property (strong, nonatomic) Category *categoryItem;
#property(nonatomic, strong) DbOperations * ops;
#property(nonatomic, strong) NSMutableArray * myCategoryArray;
#property (strong, nonatomic) IBOutlet UITableView * categoryTable;
#end
///////////
import "CategoriesTVC.h"
import "Category.h"
import "DbOperations.h"
import "sqlite3.h"
#implementation CategoriesTVC
#synthesize categoryTable;
#synthesize categoryItem,myCategoryArray,ops;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (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
{ops = [[DbOperations alloc]init];
[ops selectCategories];
myCategoryArray = [ops categoryArray];
self.editButtonItem.title = #"edit";
self.navigationItem.leftBarButtonItem = self.editButtonItem;
[super viewDidLoad];
}
- (void)viewDidUnload
{
[self setCategoryTable:nil];
[super viewDidUnload];
}
- (void)viewWillAppear:(BOOL)animated
{[super viewWillAppear:animated];
//myCategoryArray =[[NSMutableArray alloc]init];//]
[ops selectCategories];
myCategoryArray = [ops categoryArray];
[categoryTable reloadData];}
//pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
// Return the number of sections.
return 1;}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"JJJJ2");
// Return the number of rows in the section.
return [self.myCategoryArray count];}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Category Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
Category * categoryObj = [ops.categoryArray objectAtIndex:indexPath.row];
cell.textLabel.text = categoryObj.categoryName;
cell.textLabel.textAlignment = NSTextAlignmentCenter;//UITextAlignmentCenter;
return cell;}
#interface DbOperations : NSObject
{
sqlite3 * db;
}
//to add the contents of the database which will be the data source for the table
#property(nonatomic,strong)NSMutableArray * categoryArray;
//instance methods for ** Category Entity **
-(void) selectCategories;
-(void) insertCategory:(NSString *)categoryName;
-(void) updateCategory:(NSString *)categoryName:(NSString *)categoryName2;
-(void) deleteCategory:(NSString *)categoryName;
------------------------------------------
------------------------------------------
-(void) selectCategories{
categoryArray = [[NSMutableArray alloc] init];
//Get list of directories in Document path
NSArray * dirPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
//Define new path for database
NSString * documentPath = [[dirPath objectAtIndex:0] stringByAppendingPathComponent:#"SmartSpeakerDB.sqlite"];
//By default there should only have one item in the array, so the index is always 0 unless you add subdirectories.
if(!(sqlite3_open([documentPath UTF8String], &db) == SQLITE_OK))
{
NSLog(#"An error has occured.");
return;
}else{//e2
const char *sql = "SELECT categoryName FROM Category";
//const char * sql, will be execute the SELECT statement.
sqlite3_stmt *sqlStatement;
if(sqlite3_prepare_v2(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK)
{
NSLog(#"There is a problem with prepare statement Hah");
return;
}else{
while (sqlite3_step(sqlStatement)==SQLITE_ROW) {
NSLog (#"ENTER while");
char * checkChar = (char*)sqlite3_column_text(sqlStatement,0);//1
if (checkChar!= NULL) {
NSString *s=[NSString stringWithUTF8String:checkChar];
Category * newCategory = [[Category alloc] init];
newCategory.categoryName = s;
NSLog (#"***");
[categoryArray addObject:newCategory];
NSLog(#"Name %#",newCategory.categoryName);
newCategory = nil;
}//END IF
}//END While
sqlite3_finalize(sqlStatement);
sqlite3_close(db);
}//END ELSE 1
}//END ELSE 2
}//End
I looks like it is probably because you are using:
[self.myCategoryArray count];
in numberOfRowsInSection but:
[ops.categoryArray objectAtIndex:indexPath.row];
in cellForRowAtIndexPath.
If the two arrays have different numbers of objects, then you will have this problem. You typically use the same array for both functions so that this can't happen.
You don't state where in all of that code you are actually having the problem but I see one likely issue. In your tableView:numberOfRowsInSection: method you return:
[self.myCategoryArray count];
But then in your tableView:cellForRowAtIndexPath: method you call:
Category * categoryObj = [ops.categoryArray objectAtIndex:indexPath.row];
You are using two different arrays here. These should be based on the same data.
For future reference, when posting these type of questions, point out the exact line the exception is coming from and only post relevant code.