iOS NSArray of NSDictionaries from SQLite in UITableView - sql

I have been struggling for the last two days with this problem and I can't quite seem to figure it out. I have a SQlite database with the following structure.
it's a one to many relationship between List and List_Items
I access the database and create an object that is then added to a NSDictionary which is added to a NSArray. I do this twice, once for the List table and once for the List_Items.
Then I use the list Array to count the number of lists for my tableview rows, I then add them to the tableview.
The problem comes in when I get to the method
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
I can't seem to figure out how to match up the records from Lists and List_Items to show the List Items that pertain to that list in a drill down tableview.
Specific code examples would be helpful as my mind is mush at this point :(
Here is the related code that I have up to my current Writersblock.
//#******************************************************#
// *******Start Database*******
//#******************************************************#
-(void)checkAndCreateDatabase
{
// Check if the SQL database has already been saved to the users phone, if not then copy it over
BOOL success;
// Create a FileManager object, we will use this to check the status
// of the database and to copy it over if required
NSFileManager *fileManager = [NSFileManager defaultManager];
// Check if the database has already been created in the users filesystem
success = [fileManager fileExistsAtPath:databasePath];
// If the database already exists then return without doing anything
if(success) return;
// If not then proceed to copy the database from the application to the users filesystem
// Get the path to the database in the application package
NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:databaseName];
// Copy the database from the package to the users filesystem
[fileManager copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];
}
-(void)readItemsFromDatabase
{
// Setup the database object
sqlite3 *database;
// Init the Items Array
items = [[NSMutableArray alloc] init];
lists = [[NSMutableArray alloc] init];
//---------------### SELECT THE LISTS #####---------------//
// Open the database from the users filessytem
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK)
{
NSLog(#"SQL Opened");
// Setup the SQL Statement and compile it for faster access
const char *sqlStatement = "SELECT * from List";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
// Loop through the results and add them to the array
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
// Read the data from the result row
NSString *aListName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
NSString *aUserID = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
NSString *aListID = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 3)];
NSLog(#"SQL Compiled");
// Create a new list object with the data from the database
List *list = [[List alloc] initWithlistName:(NSString *)aListName userID:(NSString *)aUserID listID:(NSString *)aListID];
listNames = [NSDictionary dictionaryWithObjectsAndKeys:list.listName,#"listName",list.listID,#"listID",list.listID,#"listID",nil];
// Add the Shopping object to the list Array
[lists addObject:listNames];
}
}
else { NSLog(#"Database Not Found");}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
//---------------### SELECT THE LIST_ITEMS #####---------------//
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK)
{
NSLog(#"SQL Opened");
// Setup the SQL Statement and compile it for faster access
const char *sqlStatement = "SELECT * from List_Items";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
// Loop through the results and add them to the array
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
// Read the data from the result row
NSString *aBrandName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
NSString *aItemName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
NSString *aItemQuantity = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 4)];
NSString *aImageUrl = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 5)];
NSString *aListID = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 6)];
NSLog(#"SQL Compiled");
// Create a new items object with the data from the database
Shopping *shopping = [[Shopping alloc] initWithlistID:(NSString *)aListID brandName:(NSString *)aBrandName itemName:(NSString *)aItemName itemQuantity:(NSString *)aItemQuantity imageURL:(NSString *)aImageUrl];
itemList = [NSDictionary dictionaryWithObjectsAndKeys:shopping.listID,#"listID",shopping.brandName,#"brandName",shopping.itemName,#"itemName",shopping.itemQuantity,#"itemQuantity",shopping.imageURL,#"imageURL",nil];
// Add the Shopping object to the items Array
[items addObject:itemList];
}
}
else { NSLog(#"Database Not Found");}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
NSLog(#"%#",items);
NSLog(#"%#",lists);
}
sqlite3_close(database);
}
//#******************************************************#
// *******END Database*******
//#******************************************************#
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
int rowcount;
rowcount = [lists count];
return rowcount;
}
-(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];
}
// Set up the cell...
NSString *cellValue = [[lists objectAtIndex:indexPath.row] objectForKey:#"listName"];
cell.textLabel.text = cellValue;
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([[lists objectAtIndex:indexPath.row] objectForKey:#"listID"] != NULL)
{
NSString *listIndex = [[lists objectAtIndex:indexPath.row] objectForKey:#"listID"];
int i = [listIndex intValue];
NSLog(#"indexPath: %d",i);
}
}
EDIT**********
The single Sql statement returns more than one Listname. This is an issue because I only need one of each list name.

So first of all, You're creating a List object and then creating an NSDictionary object that's pretty much the same as the List Object. Why? Why not just add the List object to the the Array. If you're not performing any functions on the properties in the List item, then don't use a List object at all, just put the fields directly in the NSDictionary.
Secondly, don't do two different SQL calls to get the info, use only one to get the List and the list_items for that list at the same time. Then if you're using your List object, add a NSMutableArray property call items, and add your listItems to that array. You can do the same thing in an NSDictionary, just add an NSMutableArray object for key items, then add the list_items to that array.
Now you'll be able to setup the tableview to do what you want.
Amended answer in response to comments below
Select * FROM List, List_Items WHERE List.list_id = List.list_id

Anyone interested this is how I ened up figuring it out.
I get the listID for the list then I make an array and loop through the list items an compair them against the listID. If they are the same as the listID I add them to the array and once it's finished with the for loop it adds the results to my dataobject protocol (to make it available to the next view) then I present a modal view controller and load the array from the dataobject. Once i'm done with the modal view I set the dataobject back to nil and Tada! it works.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([[lists objectAtIndex:indexPath.row] objectForKey:#"listID"] != NULL)
{
[listTableView deselectRowAtIndexPath:indexPath animated:YES];
NSString *listIndex = [[lists objectAtIndex:indexPath.row] objectForKey:#"listID"];
NSMutableArray *itemArray = [[NSMutableArray alloc]init];
int i; int itemCount = [items count];
for (i = 0; i < itemCount; i++)
{
if ([[[items objectAtIndex:i] objectForKey:#"listID"] isEqual:listIndex])
{
[itemArray addObject:[items objectAtIndex:i]];
NSLog(#"Item Array:%#",itemArray);
}
}
if (i == itemCount)
{
AppDataObject* theDataObject = [self theAppDataObject];
theDataObject.itemArray = itemArray;
ItemView *temp = [[ItemView alloc] initWithNibName:#"ItemView" bundle:nil];
[self presentModalViewController: temp animated: YES];
}
}
}

Related

Xcode find table view section row on detail text label

I have an index set up with my table and I am able to return the correct arrays for the textLabel.text according to the section header. My problem is I have an a separate array that i need to return in the detailTextLabel.text.
It just repeats in each section starting from the first index from the first section. For example:
A
Apple
apple
Alligator
alligator
B
Ball
apple
Bat
alligator
I've generated index characters and table headers. This is what I have to return the cell.
NSString *alphabet = [arrayIndex objectAtIndex:[indexPath section]];
//---get all of First array's beginning with the letter---
NSPredicate *predicate =
[NSPredicate predicateWithFormat:#"SELF beginswith[c] %#", alphabet];
NSArray *firstArray = [First filteredArrayUsingPredicate:predicate];
NSArray *secondArray = [Second filteredArrayUsingPredicate:predicate];
if ([FirstArray count]>0) {
//---extract the relevant state from the states object---
NSString *cellValue = [firstArray objectAtIndex:indexPath.row];
//<--This line throws and error assuming it is trying to find the first letter to return the detail text -->
NSString *cellValueA = [secondArray objectAtIndex:indexPath.row];
//Returns value from first section and row in all section//
//NSString *cellValueA = [Second objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
cell.detailTextLabel.text = cellValueA;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
How do I find the matching row to the First Array to return the correct index in the Second Array. Any help would be much appreciated. Thank You :-)
FULL CODE
-(void)loadSQL {
// Path to the database
NSString* dbPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"DATABASE_NAME.sqlite"];
NSLog(#"databasePath: %#",dbPath);
sqlite3 *database;
NSString *firstString;
NSString *secondString;
// Open the database
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK) {
NSString *querySQL = [NSString stringWithFormat:
#"SELECT * FROM songs WHERE items LIKE %# ", viewItems];
const char *sql = [querySQL UTF8String];
sqlite3_stmt *compiledStmt;
// Fetch all names
if (sqlite3_prepare_v2(database, sql, -1, &compiledStmt, NULL) == SQLITE_OK) {
// Append each name
while (sqlite3_step(compiledStmt) == SQLITE_ROW) {
const char* cFirst = (char*)sqlite3_column_text(compiledStmt, 2);
const char* cSecond = (char*)sqlite3_column_text(compiledStmt, 3);
if (cFirst == NULL)
// There should not be a NULL name
NSLog(#"Null name!!");
else {
firstString = [NSString stringWithUTF8String:cName];
secondString = [NSString stringWithUTF8String:cArtist];
[First addObject:firstString];
[Second addObject:secondString];
//[First release];
//[Second release];
}
}
sqlite3_finalize(compiledStmt); // Cleanup the statement
}
else {
NSLog(#"Error retrieving data from database.");
}
sqlite3_close(database);
}
else {
NSLog(#"Error: Can't open database!");
}
//Creating section with 1st letter of the First field//
for (int i=0; i<[First count]-1; i++){
//---get the first char of each state---
char alphabet = [[First objectAtIndex:i] characterAtIndex:0];
NSString *uniChar = [NSString stringWithFormat:#"%C", alphabet];
//---add each letter to the index array---
if (![arrayIndex containsObject:uniChar])
{
[arrayIndex addObject:uniChar];
}
}
}
#pragma mark Table view methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
if (searching)
return 1;
else
return [arrayIndex count];
}
//---set the title for each section---
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
if (searching)
return nil;
else
return [arrayIndex objectAtIndex:section];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (searching)
return([searchedFirst count]);
else{
//return([First count]);
NSString *alphabet = [songIndex objectAtIndex:section];
NSPredicate *predicate =[NSPredicate predicateWithFormat:#"SELF beginswith[c] %#", alphabet];
NSArray *firstArray = [First filteredArrayUsingPredicate:predicate];
return [firstArray count];
}
}
//---set the index for the table---
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
if (searching) {
return nil;
}
return arrayIndex;
}
//return the cell info
- (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];
if(searching) {
cell.textLabel.text = [searchedFirst objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [searchedSecond objectAtIndex:indexPath.row];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
else{
//---get the letter in the current section---
NSString *alphabet = [arrayIndex objectAtIndex:[indexPath section]];
//---get all states beginning with the letter---
NSPredicate *predicate =
[NSPredicate predicateWithFormat:#"SELF beginswith[c] %#", alphabet];
NSArray *firstArray = [First filteredArrayUsingPredicate:predicate];
NSArray *secondArray = [Second filteredArrayUsingPredicate:predicate];
if ([songArray count]>0) {
NSString *firstValue = [firstArray objectAtIndex:indexPath.row];
NSString *secondValue = [secondArray objectAtIndex:indexPath.row];
cell.textLabel.text = firtValue;
cell.detailTextLabel.text = secondValue;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
}
return cell;
}
I am not sure I understand what you need, but if you are looking for the index in the array of a given object, then you can use:
indexOfObject:
Returns the lowest index whose corresponding array value is equal to a given object.
- (NSUInteger)indexOfObject:(id)anObject
(ref)
Answering the question from comments about restructuring....
First, create a custom class:
// CellLabels.h
#import <Foundation/Foundation.h>
#interface CellLabels : NSObject
#property (nonatomic, copy) NSString *firstText;
#property (nonatomic, copy) NSString *secondText;
#end
//CellLabels.m
#import "CellLabels.h"
#implementation CellLabels
#synthesize firstText = _firstText;
#synthesize secondText = _secondText;
#end
Instead of First and Second, create and initialize one NSMutableArray called cellData. Replace...
[First addObject:firstString];
[Second addObject:secondString];
...with...
CellLabels *labels = [[CellLabels alloc] init];
labels.first = firstString;
labels.second = secondString;
[cellData addObject:labels];
Then, your array filtering works by comparing "SELF.firstText" and your array references work by using:
CellLabels *labels = [filteredArray objectAtIndex:indexPath.row];
cell.textLabel.text = labels.firstText;
cell.detailTextLabel.text = labels.secondText;
(OK, I didn't check to make sure all that compiled but it should give you the idea.)

Array not getting populated with new data

In my app I am using an array to get some data inside the method but every time after adding the object to the array, I check its contents then always it shows me 0 objects inside the array and also after that I am reloading the table view but nothing is happening.no event are called. I am showing my code here:
in .h file
#interface ModalView:UIViewController
<UITableViewDelegate,UITableViewDataSource,UIScrollViewDelegate>
{
NSMutableArray *imageName;
}
#property (nonatomic,retain)NSMutableArray *imageName;
in .m file:-
#synthesize imageName;
- (void)viewDidLoad {
[super viewDidLoad];
imageName=[[NSMutableArray alloc] init];
[tableView1 reloadData];
tableView1.delegate=self;
tableView1.dataSource=self;
}
-(void)searchImagesInCategory:(NSString *)string
{
string1=string;
NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory= [paths objectAtIndex:0];
NSString *path=[documentsDirectory stringByAppendingPathComponent:#"1.sqlite"];
//Open the database
//might have to make database as property
if(sqlite3_open([path UTF8String], &dataBase) ==SQLITE_OK)
{
sqlite3_stmt *statement;
NSString *strSQL = [[NSString alloc]init];
strSQL = #"select ImageName from tblLanguageElement where Category='";
strSQL = [[strSQL stringByAppendingString:string1] stringByAppendingString:#"'"];
const char *bar = [strSQL UTF8String];
if(sqlite3_prepare(dataBase, bar, -1, &statement, NULL) == SQLITE_OK)
{
while (sqlite3_step(statement) == SQLITE_ROW)
{
NSLog(#"%#",[NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 0)]);
NSString *string2=[NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 0)];
// [imageName addObject:[NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 0)]];
NSLog(string2);
[imageName addObject:string2];
[imageName retain];
}
//tableView1.delegate=self;
//tableView1.dataSource=self;
[self.tableView1 reloadData];
}
}
//return 1;
//[tableView1 reloadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView1 cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView1 dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
cell.imageView.image= [UIImage imageNamed:[imageName objectAtIndex:indexPath.row]];
return cell;
}
This is my code. Why my array (imageName) is not getting the data inside the method and why table view is not reloading?
I know you're instantiating your array in viewDidLoad, but what happens if you add it at the beginning of the method -(void)searchImagesInCategory:(NSString *)string:
imageName = [[NSMutableArray alloc] init];
Since you declared the object in your header file as nonatomic retain, then synthesized and allocated it in your implementation, you do not need to retain it each time you add something to it. You should try removing the [imageName retain];

Unable to load data into the table view

In my app.i have some classes and inside one class I am calling method in other class. In my other class I have a table view and an array "data". When the query is executed in this method then I am adding the data obtained from the execution of the query to the array and then I am calling reload data for the table view. But to my surprise table view is not getting reloaded and I am not getting any sort of data on the table view. It is showing just a blank table view.
The method which is called from other class:
-(void)searchImagesInCategory:(NSString *)string
{
data=[[NSMutableArray alloc]init];
string1=string;
NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory= [paths objectAtIndex:0];
NSString *path=[documentsDirectory stringByAppendingPathComponent:#"Table.sqlite"];
//Open the database
//might have to make database as property
if(sqlite3_open([path UTF8String], &dataBase) ==SQLITE_OK)
{
sqlite3_stmt *statement;
NSString *strSQL = [[NSString alloc]init];
strSQL = #"select ImageName from tblLanguageElement where Category='";
strSQL = [[strSQL stringByAppendingString:string1] stringByAppendingString:#"'"];
const char *bar = [strSQL UTF8String];
//strSQL = [strSQL stringByAppendingString:"''"];
//NSLog(strSQL);
if(sqlite3_prepare(dataBase, bar, -1, &statement, NULL) == SQLITE_OK)
{
while (sqlite3_step(statement) == SQLITE_ROW)
{
NSLog(#"%#",[NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 0)]);
[data addObject:[NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 0)]];
}
tableView1.delegate=self;
tableView1.dataSource=self;
}
}
[tableView1 reloadData];
}
My cell for row at index path method:-
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView1 cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView1 dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
cell.imageView.image= [UIImage imageNamed:[data objectAtIndex:indexPath.row]];
return cell;
}
Why i am not getting the reloaded Table view.Please help.
Thanks,
Christy
In your method you are re-initializing your "data" array. Try making this a local variable by declaring it in your header file and then in your viewDidLoad method call:
data= [[NSMutableArray alloc]init];
Also there is no need to reset the delegate and data source. Just do it once and leave it.
This is an edit from something else I have seen. You need to bind your variable and not just append the string. Here is an example....
- (NSMutableArray*) getAllImagesForCategory:(NSString*)category {
NSMutableArray *tempArray = [[NSMutableArray alloc]init]autorelease];;
const char *sqlStatement = "select ImageName from tblLanguageElement where Category=?";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
sqlite3_bind_text(compiledStatement,1,category); //this is where you put your variable into the statement
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
// Read the data from the result row
NSString *imageName = [NSString stringWithUTF8String:(char*)sqlite3_column_text(compiledStatement, 1)];
[tempArray addObject:imageName];
}
} else {
NSLog(#"ERROR: Failed to select all images with message '%s'",sqlite3_errmsg(database));
}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
return tempArray;
}
So this is the SQL statement that will get the stuff from the database. To call this method you go something like this.
_data = [self getAllImagesForCategory];
[tableView1 reloadData];
I hope this helps any questions just ask.
Make sure you are returning the correct number in tableView:numberOfRowsInSection:.

Read plist data into a NSArray but get null

I got same warning here “local declaration hides instance variable” warning
but I got more problems...
Here is my code
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.someaddress.php"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
// create the connection with the request
// and start loading the data
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
NSLog(#"\n\nCONNECTION: %#", theConnection);
NSData *returnData = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:nil error:nil];
NSString *listFile = [[NSString alloc] initWithData:returnData encoding:NSASCIIStringEncoding];
NSMutableArray *plist = [[NSMutableArray alloc] init];
plist = [listFile propertyList];
NSLog( #"\n 1111 plist is \n%#", plist );
//I can get a plist format data here,But nothing in 2222
NSLog(#"Now you see me tableView Row Count");
NSLog(#"TOTAL PLIST ROW COUNT IS = %i", [plist count]);
// Return the number of rows in the section.
return [plist count];
}
and I got Warning here"Local declaration of 'plist' hides instance variable"
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"LightCell";
LightCell0 *cell =(LightCell0 *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[LightCell0 alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
// Set up the cell…
NSLog(#"Now you see me Load Data %i", indexPath.row);
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
//I try to get list data here But RETURN NULL
NSLog( #"\n 2222 plist is \n %#", plist);
switch (indexPath.row) {
case 0:
if ([plist valueForKey:#"nodeStatus"] == 0){
cell.lightImageView.image = [UIImage imageNamed:#"lightOff.png"];
NSLog(#"value for key Node Status : %#" ,[self.plists Valuefokey:#"nodeStatus"]);
//also return NULL !!
}
else if([self valueForKey:#"nodeStatus"] == 1){
cell.lightImageView.image = [UIImage imageNamed:#"lightOn.png"];
}
break;
case 1:
cell.lightLocation.text =[plist valueForKey:#"nodeName"] ;
if ([plist valueForKey:#"nodeStatus"] == 0){
cell.lightImageView.image = [UIImage imageNamed:#"lightOff.png"];
}
else if([plist valueForKey:#"nodeStatus"] == 1){
cell.lightImageView.image = [UIImage imageNamed:#"lightOn.png"];
};
break;
default:
break;
}
return cell;
}
This is the tow items I create in a plist
{
category = Light;
nodeID = 1;
nodeName = "Living Room";
nodeStatus = 0;
nodeTrigger = 0;
nodeType = "light_sw";
},
{
category = Light;
nodeID = 2;
nodeName = Kitchen;
nodeStatus = 0;
nodeTrigger = 0;
nodeType = "light_sw";
}
So that's my question ,Why can't I pass "plist" from
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
...
}
to
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...
}
and I use NSMutableArray *plist = [[NSMutableArray alloc] init];
But still appear "Local declaration of 'plist' hides instance variable"
???
hope someone can figure out this problem
Best Regards !
and I got Warning here"Local declaration of 'plist' hides instance variable"
Well, then, you should fix that.
The warning is telling you that you've declared two variables named plist: One local to this instance method, and the other an instance variable. The local variable, having a narrower scope, hides the instance variable, so that when you refer to plist in the method, you are referring to the local variable. This means that you cannot access anything stored in the instance variable by another method, nor store anything in it for another method to retrieve.
The solution is either to kill off or to rename the local variable. If the latter is what you want, use Xcode's “Edit All in Scope” feature.
Also:
NSMutableArray *plist = [[NSMutableArray alloc] init];
plist = [listFile propertyList];
Creating the array on the first of those lines is redundant, because you immediately replace your pointer to that array with the pointer to another array, returned by propertyList. Thus, you never use and you leak the first array. You should at least cut out the creation of the first array, and you should probably cut out the entire first line (thereby cutting out both the first array and the local variable).
Here is the code I fix the warning ,the program can build without any warning
it also can display the result after reading the plist in tableview
1.Load the plist:
- (void)viewDidLoad {
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www. someaddress.php"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
NSData *returnData = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:nil error:nil];
NSString *listFile = [[NSString alloc] initWithData:returnData encoding:NSASCIIStringEncoding];
plist = [listFile propertyList];
}
2.return the number to rows
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [plist count];
}
3.read the plist data to show result in cells
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"LightCell0";
LightCell0 *cell =(LightCell0 *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[LightCell0 alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
// Set up the cell…
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
int i;
for (i=0; i<[plist count]; i++) {
//Get nodeName
if(indexPath.row == i)
{
cell.lightLocation.text = [[[plist objectAtIndex:i] valueForKey: #"nodeName"]description];
//Get Light Status to show the image
if ([[[plist objectAtIndex:i] valueForKey: #"nodeStatus"] intValue] == 0){
cell.lightImageView.image = [UIImage imageNamed:#"lightOff.png"];
}
else if([[[plist objectAtIndex:i] valueForKey: #"nodeStatus"] intValue] == 1){
cell.lightImageView.image = [UIImage imageNamed:#"lightOn.png"];
cell.lightSwitch.on=YES;
}
}
}
return cell;
}
It can get the right data ,and display the correct result in the tableview cells
BUTTTTTTT
If you scroll up the tableview,it's ok,when you on the top it will scroll down Automatically
When you "scroll down" the tableview,program crash ???
WHY ??? did I write anything wrong ???
plist = [listFile propertyList];=====>self.plist = [listFile propertyList];
THAT IS CORRECT

sqlite3 - stringWithUTF8String is leaking!

I would appreciate if someone could help me solve my leaking problem. The leaks occur at: aImage, aCategory, aDescription, category and categories. I release them in dealloc, but obviously that is not sufficient:
-(void) readListFromDatabase:(char *) sqlStatement {
// Setup some globals
databaseName = #"mydatabase.sql";
// Get the path to the documents directory and append the databaseName
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
databasePath = [documentsDir stringByAppendingPathComponent:databaseName];
// Setup the database object
sqlite3 *database;
// Init the categories Array
categories = [[NSMutableArray alloc] init];
// Open the database from the users filessytem
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
// Setup the SQL Statement and compile it for faster access
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, 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
aImage = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 0)];
aCategory = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
aDescription = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
// Create a new category object with the data from the database
category=[[Category alloc] initWithName:aImage category_name:aCategory description_text:aDescription];
// Add the category object to the categories Array
[categories addObject:category];
[category release];
}
}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
}
- (void)dealloc {
[databaseName release];
[databasePath release];
[categories release];
[aImage release];
[aCategory release];
[aDescription release];
[category release];
[super dealloc];
}
If the method is called multiple times, then the strings will leak because you need to release the previous values. You also overrelease the strings in dealloc because you never retained them. You should write the assignments like this:
[aImage release];
aImage = [[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 0)] retain];
The only other way these strings could be leaking is if you are calling this method from a thread and you didn't create an auto release pool.
If the method is being called from a new thread, you need an autorelease pool:
- (void)myThreadFunction {
NSAutoReleasePool *pool = [[NSAutoReleasePool alloc] init];
try {
// ...
[self readListFromDatabase:whatever];
// ...
} #finally {
[pool release];
}
}
Is that method that you posted being called more than once on the same object? If it is, categories from the first call will leak because it is overwritten each time readListFromDatabase: is called. Try:
// Init the categories Array
[categories release];
categories = [[NSMutableArray alloc] init];
Why does the application terminate when I include [aImage autorelease] in the loop (it also terminates if [aImage release])?
A bit late, but I was updating an old project and came across a similar problem.
I had a convenience method that was incorrectly named!
- (NSString *)initStringFromPosition:(int)index {
char *str = (char *)sqlite3_column_text(init_statement, index);
return (str) ? [NSString stringWithUTF8String:str] : #"";
}
Analyse said I had a memory leak, but a simple rename to
- (NSString *)stringFromPosition:(int)index {
solved the problem