my method definition is not found but i'm not sure why - ios

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.

Related

Why the numberOfRowsInSections: method is invoked 5 times ? And the numberOfSections 6 times?

I am posting again this question, which has quite been asked already in this topic:
When is tableView:numberOfRowsInSection: called in UITableView?
I am following the Big Nerd Ranch lesson, and it appears that this method is invoked 5 times in my program, and I don't understand why...
It is invoked far after the viewDidLoad, and even after the initialization. But it is invoked before the tableView:cellForRowAtIndexPath: method is invoked.
I put breakpoint in my code everywhere, and NSLogs everywhere too (I deleted some of them in my code to make it clearer), but still I have no idea what's going on between each time it's invoked.
Here is my code:
BNRAppDelegate.h
#import <UIKit/UIKit.h>
#interface BNRAppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#end
BNRAppDelegate.m
#import "BNRAppDelegate.h"
#import "BNRItemsViewController.h"
#interface BNRAppDelegate ()
#end
#implementation BNRAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
//Create a BNRItemsViewController
BNRItemsViewController *itemsViewController = [[BNRItemsViewController alloc] init];
//Place BNRItemsViewController's table view in the window hierarchy
self.window.rootViewController = itemsViewController;
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
//etc...
#end
BNRItem.h
#import <Foundation/Foundation.h>
#interface BNRItem : NSObject
{
NSString *_itemName;
NSString *_serialNumber;
int _valueInDollars;
NSDate *_dateCreated;
}
#property NSString *itemName;
#property NSString *serialNumber;
#property int valueInDollars;
#property NSDate *dateCreated;
+(instancetype)randomItem;
//Designated initializer for BNRItem
-(instancetype)initWithItemName:(NSString *)name
valueInDollars:(int)value
serialNumber:(NSString *)sNumber;
-(instancetype)initWithItemName:(NSString *)name;
#end
BNRItem.m
#import "BNRItem.h"
#implementation BNRItem
+(instancetype)randomItem
{
//Create an immutable array of three adjectives
NSArray *randomAdjectiveList = #[#"Fluffy", #"Rusty", #"Shiny"];
//Create an immutable array of three nouns
NSArray *randomNounList = #[#"Bear", #"Spork", #"Mac"];
//Get the index of a random adjective/noun from the lists
//Note: the % operator, called the modulo operator, gives you the remainder. So adjectiveIndex is a random number from 0 to 2 inclusive.
NSInteger adjectiveIndex = arc4random() % [randomAdjectiveList count];
NSInteger nounIndex = arc4random() % [randomNounList count];
//Note the NSInteger is not an object but a type definition for "long"
NSString *randomName = [NSString stringWithFormat:#"%# %#",
[randomAdjectiveList objectAtIndex:adjectiveIndex],
[randomNounList objectAtIndex:nounIndex]];
int randomValue = arc4random() % 100;
NSString *randomSerialNumber = [NSString stringWithFormat:#"%c%c%c%c%c",
'0' + arc4random() % 10,
'A' + arc4random() % 26,
'0' + arc4random() % 10,
'A' + arc4random() % 26,
'0' + arc4random() % 10];
BNRItem *newItem = [[self alloc] initWithItemName:randomName
valueInDollars:randomValue
serialNumber:randomSerialNumber];
return newItem;
}
-(instancetype)initWithItemName:(NSString *)name
valueInDollars:(int)value
serialNumber:(NSString *)sNumber
{
//Call the superclass's designated initializer
self = [super init];
//Did the superclass's designated initializer succeed?
if (self) {
//Give the instance variables initial values
self.itemName = name;
self.serialNumber = sNumber;
self.valueInDollars = value;
//Set _dateCreated to the current date and time
self.dateCreated = [[NSDate alloc] init];
}
//Return the address of the newly initialized object
return self;
}
-(instancetype)initWithItemName:(NSString *)name
{
return [self initWithItemName:name
valueInDollars:0
serialNumber:#""];
}
-(instancetype)init
{
return [self initWithItemName:#"Item"];
}
-(NSString *)description
{
NSString *descritptionString = [[NSString alloc] initWithFormat:#"%# (%#): worth $%d, recorded on %#",
self.itemName,
self.serialNumber,
self.valueInDollars,
self.dateCreated];
return descritptionString;
}
#end
BNRItemStore.h
#import <Foundation/Foundation.h>
#class BNRItem;
#interface BNRItemStore : NSObject
#property (nonatomic, readonly) NSArray *allItems;
+(instancetype)sharedStore;
-(BNRItem *)createItem;
#end
BNRItemStore.m
#import "BNRItemStore.h"
#import "BNRItem.h"
#interface BNRItemStore ()
#property (nonatomic) NSMutableArray *privateItems;
#end
#implementation BNRItemStore
+(instancetype)sharedStore
{
static BNRItemStore *sharedStore = nil;
//Do I need to create a sharedStore ?
if (!sharedStore) {
sharedStore = [[self alloc] initPrivate];
}
return sharedStore;
}
//If a programmer calls [[BNRItemsStore alloc] init], let him know the error of his ways
-(instancetype)init
{
#throw [NSException exceptionWithName:#"Singleton"
reason:#"Use +[BNRItemStore sharedStore]"
userInfo:nil];
return nil;
}
//Here is the real (secret) intializer
-(instancetype)initPrivate
{
self = [super init];
if (self) {
_privateItems = [[NSMutableArray alloc] init];
}
return self;
}
-(NSArray *)allItems
{
return self.privateItems;
}
-(BNRItem *)createItem
{
BNRItem *item = [BNRItem randomItem];
[self.privateItems addObject:item];
return item;
}
#end
BNRItemsViewController.h
#import <UIKit/UIKit.h>
#import "BNRItemsViewController.h"
#import "BNRItemStore.h"
#import "BNRItem.h"
#interface BNRItemsViewController : UITableViewController
#property (nonatomic) BNRItemStore *itemStore;
#end
BNRItemsViewController.m
#import "BNRItemsViewController.h"
#import "BNRItemStore.h"
#import "BNRItem.h"
#implementation BNRItemsViewController
-(BNRItemStore *)itemStore
{
BNRItemStore *itemStore = [BNRItemStore sharedStore];
return itemStore;
}
//Designated Initializer is initWithStyle Changing to init
-(instancetype)init
{
//ALWAYS call the superclass's designated initializer
self = [super initWithStyle:UITableViewStylePlain];
if (self) {
for (int i = 0; i < 8; i++) {
BNRItem *item = [self.itemStore createItem];
NSLog(#"The %#, valued %d has been created. It is at index %lud", item.itemName, item.valueInDollars, (unsigned long)[[[BNRItemStore sharedStore] allItems] indexOfObject:item]);
}
}
return self;
}
-(instancetype)initWithStyle:(UITableViewStyle)style
{
return [self init];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"This tableview has %ld section and %lu rows", (long)section, (unsigned long)[[self.itemStore allItems] count]);
return [[self.itemStore allItems] count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Get a new or recycled cell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"UITableViewCell" forIndexPath:indexPath];
//Set the text on the cell with the description of the item that is at the nth index of items, where n = row this cell will appear in on the tableview
NSArray *items = [self.itemStore allItems];
BNRItem *item = items[indexPath.row];
NSLog(#"%# is in indexPath %ld - %ld", item.itemName, (long)[indexPath section], (long)[indexPath row]);
cell.textLabel.text = [item description];
return cell;
}
-(void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"ViewDidLoad1");
[self.tableView registerClass:[UITableViewCell class]
forCellReuseIdentifier:#"UITableViewCell"];
NSLog(#"ViewDidLoad2");
}
#end
I also have another code where I have 2 sections, and so I invoked the method numberOfSections:, and this one is called 6 times ! Two times consecutively first, and the alternatively with numberOfRowsInSection:
What the hell ?
The super class (the UITableView / Controller) does not cache those values, which is a good thing: You don't tell the superclass, when the number has changed, it has to ask. This is consistent with the whitebox approach that Apple chose.
So whenever an algorithm in Apples superclass implementation needs to know these values, it has to call. And when Apple changes some algorithm, the number of calls may change. I would not overthink this. There is nothing wrong.
The only conclusion: implement those methods as cheaply as possible.

Parsing JSON image urls to custom Table View error

I'm trying to parse a JSON file containing some url's to pictures, titles and texts. I've tried to parse another JSON file in the same way, but only with text and it works. But this one will not work. Here's my code:
.h:
#import <UIKit/UIKit.h>
#interface PicturesViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>{
NSURLConnection *conn;
NSMutableData *responseData;
NSMutableArray *news;
NSIndexPath * indexPath;
UIActivityIndicatorView *loading;
}
#property (nonatomic, retain) NSIndexPath * indexPath;
#property (nonatomic, strong) NSArray *tweets;
#property (strong, nonatomic) IBOutlet UITableView *myTableView;
#end
.m:
#import "PicturesViewController.h"
#import "AppDelegate.h"
#import "RNBlurModalView.h"
#import "PictureJSON.h"
#interface PicturesViewController ()
{
NSInteger refreshIndex;
NSArray *images;
}
#end
#implementation PicturesViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Menu" style:UIBarButtonItemStyleBordered target:self action:#selector(showMenu)];
UIPanGestureRecognizer *gestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(swipeHandler:)];
[self.view addGestureRecognizer:gestureRecognizer];
[self issueLoadRequest];
}
- (void)swipeHandler:(UIPanGestureRecognizer *)sender
{
[[self sideMenu] showFromPanGesture:sender];
}
#pragma mark -
#pragma mark Button actions
- (void)showMenu
{
[[self sideMenu] show];
}
#pragma mark - Table view data source
- (void)issueLoadRequest
{
// Dispatch this block asynchronosly. The block gets JSON data from the specified URL and performs the proper selector when done.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData* data = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://my-site/pictureparse.php?name=MyName"]];
[self performSelectorOnMainThread:#selector(receiveData:) withObject:data waitUntilDone:YES];
});
}
- (void)receiveData:(NSData *)data {
// When we have the data, we serialize it into native cocoa objects. (The outermost element from twitter is
self.tweets = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
[self.myTableView reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.tweets.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"PictureJSON";
PictureJSON *cell = (PictureJSON *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"PictureJSON" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
NSDictionary *tweet = [self.tweets objectAtIndex:indexPath.row];
cell.instaImage = [tweet objectForKey:#"link"];
cell.titleLabel.text = [tweet objectForKey:#"title"];
cell.timeLabel.text = [tweet objectForKey:#"published"];
return cell;
}
#end
I have a custom table view file named PictureJSON with a nib file which looks like this:
But when I launch my app I get this error:
Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<PicturesViewController 0x17d86dc0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key instaImage.'
Can someone help me fix this?
Thanks!
Probably the JSON you got not have good structure, check the result of the query in JSONLint - The JSON Validator perhaps this can help you to detect the error.

Memory keep increasing when the UITableView scrolling

there is a strange problem I have not met ever
there is an array() including some custom object named MyClass parsed by JSONKit;
when I keep scrolling the tableview the memory will keeping increasing too.
but when replace
cell.textLabel.text = myclass.name;
with
cell.textLabel.text = #"cool";
or
cell.textLabel.text = [NSString stringWithFormate:#"a-%d", indexPath.row];
it's ok the memory with keep stable
but if I use
cell.textLabel.text = [NSString stringWithFormate:#"a-%#-i",myclass.name, indexPath.row];
it also keep increasing;
It will drive my crazy!!
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = #"Singers";
OMTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
MyClass *myclass = [self.data objectAtIndex:indexPath.row];
if (cell == nil){
cell = [[[OMTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier] autorelease];
}
cell.textLabel.text = myclass.name;
return cell;
}
MyClass
there is two class one Base another inherit
Base:
#interface OMBase : NSObject {
NSMutableDictionary *data;
NSString *name;
NSArray *keys;
}
#property (nonatomic, retain) NSString *name;
#property (nonatomic, copy) NSMutableDictionary *data;
#implementation OMBase
#synthesize data, name;
- (void)setData:(NSMutableDictionary *)adata{
if (data){
[data release];
data = nil;
}
data = [adata mutableCopy];
}
- (void)dealloc{
if (keys){
[keys release];
}
[data release];
[super dealloc];
}
- (id)init{
if (self = [super init]){
self.data = [[[NSMutableDictionary alloc] initWithCapacity:20] autorelease];
}
return self;
}
inherit:
#import "OMBase.h"
#interface OMLyric : OMBase
- (NSString *)songid;
- (NSString *)content;
#import "OMLyric.h"
#implementation OMLyric
- (NSString *)songid{
return [data objectForKey:#"songid"];
}
- (NSString *)content{
return [data objectForKey:#"content"];
}
Seems like your myclass.name getter returns a new allocated object. We can't say more without seeing myclass.

Loading a table view (inside a view controller) with SQLite information

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];

Xcode Data Controller Issue

I have an application that has the following parts:
StoreDataController.h
StoreDataController.m
StoreTableViewController.h
StoreTableViewController.m
I created a property & method in StoreDataController that retrieves data from a URL and converts it to JSON. I then store it in an Array. I'm trying to get the table controller to display the array in the table but it isn't displaying. What do I need to do to have the Table display the contents of the array? Here is the code I have:
StoreDataController.h
#interface StoreDataController : NSObject
#property (nonatomic, retain) NSArray *storeNames;
-(void)addStoreNamesObject:(NSArray *)storeNames;
#end
StoreDataController.m
#import "StoreDataController.h"
#import "SBJson.h"
#implementation StoreDataController
-(void)addStoreNamesObject:(NSArray *)storeNames
{
NSString *strURL = [NSString stringWithFormat:#"http://10.247.245.87/stores/dodge.php"];
NSData *dataURL = [NSData dataWithContentsOfURL:[NSURL URLWithString:strURL]];
NSString *strResult = [[NSString alloc] initWithData:dataURL encoding:NSUTF8StringEncoding];
storeNames = [strResult JSONValue];
}
#end
StoreTableViewController.h
#import <UIKit/UIKit.h>
#class StoreDataController;
#interface StoreTableViewController : UITableViewController
#property (nonatomic, retain) StoreDataController *storeNameController;
#end
StoreTableViewController.m
#import "StoreTableViewController.h"
#import "StoreDataController.h"
#interface StoreTableViewController ()
#end
#implementation StoreTableViewController
- (void)awakeFromNib
{
[super awakeFromNib];
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _storeNameController.storeNames.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.textLabel.text = [_storeNameController.storeNames objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
<#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:#"<#Nib name#>" bundle:nil];
[self.navigationController pushViewController:detailViewController animated:YES];
*/
}
#end
You at least need something to set the storeNameController property inside your StoreTableViewController so that it references the StoreDataController object that is doing the work of building the array.
How you do that depends on what creates the StoreDataController object and how that's related to your view controller.
(Aside: In general, you should use self.propertyName instead of _propertyName.)

Resources