"unrecognized selector sent to instance" when retrieving a sqlite data - iphone

I have been getting this error and have no idea how to fix it. I am a newbie for iOS programming.
Hope the codes below is enough to see what the problem is.
Here is my ListTableController.m
...
#implementation ListTableController
#synthesize listTableView;
#synthesize detailController;
#synthesize listOfTasks;
#synthesize title, note, date;
-(id)initWithTitle:(NSString *)sTitle note:(NSString *)sNote date:(NSString *)sDate {
NSLog(#"FUNC: %s",__FUNCTION__);
self.title = sTitle;
self.note = sNote;
self.date = sDate;
return self;
}
// Retrieve records
-(void) getAllRowsFromTableNamed: (NSString *) tableName {
//---retrieve rows---
NSString *qsql = [NSString stringWithFormat:#"SELECT * FROM %# WHERE status = '1' ORDER BY date ASC",tableName]; sqlite3_stmt *statement;
//---initialize the array---
listOfTasks = [[NSMutableArray alloc] init];
if (sqlite3_prepare_v2( db, [qsql UTF8String], -1, &statement, nil) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
NSString *fieldTitle = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 1)];
NSString *fieldNote = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 2)];
NSString *fieldDate = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 3)];
// Create a new object with the data from the database
NSString *str = [[NSString alloc] initWithTitle :fieldTitle note:fieldNote date:fieldDate];
[listOfTasks addObject:str];
[str release];
[fieldTitle release];
[fieldNote release];
[fieldDate release];
}
//---deletes the compiled statement from memory---
sqlite3_finalize(statement);
}
}
...
Here is my ListTableController.h
#import
#import "sqlite3.h"
#import "TaskDetailController.h"
#interface ListTableController : UITableViewController {
IBOutlet UITableView *listTableView;
sqlite3 *db;
TaskDetailController *detailController;
}
NSString *title;
NSString *note;
NSString *date;
NSMutableArray * listOfTasks;
#property (nonatomic, retain) NSString *title;
#property (nonatomic, retain) NSString *note;
#property (nonatomic, retain) NSString *date;
#property (nonatomic, retain) TaskDetailController *detailController;
#property (nonatomic, retain) IBOutlet UITableView *listTableView;
#property (nonatomic, retain) NSMutableArray *listOfTasks;
-(void) copyDatabaseIfNeeded;
-(NSString *) filePath;
-(IBAction)addCalendar;
-(NSInteger)countToday;
-(id)initWithTitle:(NSString *)sTitle note:(NSString *)sNote date:(NSString *)sDate;
#end
And this is the error log from the console:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSPlaceholderString initWithTitle:note:date:]: unrecognized selector sent to instance 0x4e00470'

Try removing these lines. Class methods as [NSString stringWith.... returns autoreleased objects.
[fieldTitle release];
[fieldNote release];
[fieldDate release];
I think you have to learn about memory management first. You will get a big headache if you don't.

Try removing these lines.
[fieldTitle release];
[fieldNote release];
[fieldDate release];
And if you want to combine title , note , and date as a single line.
then try this
// Create a new object with the data from the database
NSString *str = [[NSString stringWithFormate:#"%# %# %#",fieldTitle,fieldNote,fieldDate];
instead of
// Create a new object with the data from the database
NSString *str = [[NSString alloc] initWithTitle :fieldTitle note:fieldNote date:fieldDate];

Related

Leaky Custom Object for storing data from a plist

I have made a very simple custom object pictureData.
Here is the .h file
#import <Foundation/Foundation.h>
#interface pictureData : NSObject {
NSString *fileName;
NSString *photographer;
NSString *title;
NSString *license;
}
#property (nonatomic, retain) NSString *fileName;
#property (nonatomic, retain) NSString *photographer;
#property (nonatomic, retain) NSString *title;
#property (nonatomic, retain) NSString *license;
+(pictureData*)picDataWith:(NSDictionary*)dictionary;
#end
The .m file
#import "pictureData.h"
#implementation pictureData
#synthesize fileName;
#synthesize photographer;
#synthesize title;
#synthesize license;
+ (pictureData*)picDataWith:(NSDictionary *)dictionary {
pictureData *tmp = [[[pictureData alloc] init] autorelease];
tmp.fileName = [dictionary objectForKey:#"fileName"];
tmp.photographer = [dictionary objectForKey:#"photographer"];
tmp.title = [dictionary objectForKey:#"title"];
tmp.license = [dictionary objectForKey:#"license"];
return tmp;
}
-(void)dealloc {
[fileName release];
[photographer release];
[title release];
[license release];
}
#end
I then set up these objects in an array, like so:
NSString *path = [[NSBundle mainBundle] pathForResource:#"pictureLicenses" ofType:#"plist"];
NSArray *tmpDataSource = [NSArray arrayWithContentsOfFile:path];
NSMutableArray *tmp = [[NSMutableArray alloc] init];
self.dataSource = tmp;
[tmp release];
for (NSDictionary *dict in tmpDataSource) {
pictureData *pic = [pictureData picDataWith:dict];
NSLog(#"%#", pic.title);
[self.dataSource addObject:pic];
}
Everything works smashingly. I have a table view which loads the proper picture images, and information, no problem. Upon running Instruments for leaks, I see that my pictureData object is leaks with every allocation.
I would assume that with having my object autoreleased I would not have to worry about manually allocating and deallocating them.
Perhaps is my issue that I use autorelease, which the autoReleasePool keeps a retain count of +1 and then when I add a pictureData object to my array, that also retains it? Thank you all for your time!
edit: Don't forget to call super! Thank you Sam!
Change dealloc to:
-(void)dealloc {
[fileName release];
[photographer release];
[title release];
[license release];
[super dealloc];
}
(call [super dealloc])
In your function, change the return value to include autorelease, like
+ (pictureData*)picDataWith:(NSDictionary *)dictionary
{
...
...
return [tmp autorelease];
}
When you add pictureData object to dataSource, you increase the retain count, so you should autorelease it while returning.
Hope it helps.

Cannot figure out iPhone/Objective-C Memory Leak in sqlite data retrieval

I am trying to do some basic table retrieval from sqlite and I keep stumbling over some memory leak I cannot figure out, especially since it appears only with one of two equivalent lines.
What I do is simple :
-Create an object (category) to hold my sqlite DB line
-Have a method that queries sqlite and returns an array of these objetcs
I put all the code here (stripped it down a bit to simplify but the I have the memory leak with this very code).
category.h:
#interface Category : NSObject {
int catId;
NSString *description;
int order;
NSString *iconName;
}
#property(nonatomic, readwrite, assign) int catId;
#property(nonatomic, retain) NSString *description;
#property(nonatomic, readwrite, assign) int order;
#property(nonatomic, retain) NSString *iconName;
#end
category.m:
#import "Category.h"
#implementation Category
#synthesize catId;
#synthesize description;
#synthesize order;
#synthesize iconName;
#end
Method to retrieve array:
-(NSMutableArray *)getAll {
NSString *query = "select id, description, catorder, image from category order by catorder";
sqlite3_stmt *statement;
NSMutableArray *categoryArray = [[NSMutableArray alloc] init];
if (sqlite3_prepare_v2([[Database sharedDatabase] instance], [query UTF8String], -1, &statement, nil) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
int dbId = sqlite3_column_int(statement, 0);
char *dbDescription = (char *)sqlite3_column_text(statement, 1);
int dbOrder = sqlite3_column_int(statement, 2);
char *dbIcon = (char *)sqlite3_column_text(statement, 3);
NSString *desc = [[NSString alloc] initWithUTF8String:dbDescription];
NSString *icon = [[NSString alloc] initWithUTF8String:dbIcon];
Category *category = [[Category alloc] init];
category.catId=dbId;
category.description = desc;
//category.description = #"Test";
category.order = dbOrder;
category.iconName = icon;
//category.icon = #"test.png";
[desc release];
[icon release];
[categoryArray addObject:category];
[category release];
}
sqlite3_finalize(statement);
}
[categoryArray autorelease];
return categoryArray;
}
This line leaks
NSString *icon = [[NSString alloc] initWithUTF8String:dbIcon];
This line doesn't
NSString *desc = [[NSString alloc] initWithUTF8String:dbDescription];
Here what instruments shows :
and when I drill down :
You don't have a dealloc method. You need to have this in your Category.m file:
-(void)dealloc
{
[description release];
[iconName release];
[super dealloc];
}
Also, I'm pretty sure you can't have a property named "description". That's a reserved method name.

Objective-C error while implementing class?

I have this class
#import <Foundation/Foundation.h>
#interface SubscriptionArray : NSObject{
NSString *title;
NSString *source;
NSString *htmlUrl;
}
#property (nonatomic,retain) NSString *title;
#property (nonatomic,retain) NSString *source;
#property (nonatomic,retain) NSString *htmlUrl;
#end
and the implementation file is this one:
#import "SubscriptionArray.h"
#implementation SubscriptionArray
#synthesize title,source,htmlUrl;
-(void)dealloc{
[title release];
[source release];
[htmlUrl release];
}
#end
When I use the class like in this example I get an EXEC_BAD_ACCESS error:
for (NSDictionary *element in subs){
SubscriptionArray *add;
add.title=[element objectForKey:#"title"]; //ERROR Happens at this line
add.source=[element objectForKey:#"htmlUrl"];
add.htmlUrl=[element objectForKey:#"id"];
[subscriptions addObject:add];
}
Can someone help me?
P.S. Subscriptions is a NSMutableArray
You need to allocate your SubscriptionArray object like so: SubscriptionArray *add = [[SubscriptionArray alloc] init];
Your for loop will therefore look something like this:
for (NSDictionary *element in subs){
SubscriptionArray *add = [[SubscriptionArray alloc] init];
add.title=[element objectForKey:#"title"];
add.source=[element objectForKey:#"htmlUrl"];
add.htmlUrl=[element objectForKey:#"id"];
[subscriptions addObject:add];
[add release];
}
You need to initialize your SubscriptionArray. i.e.
SubscriptionArray *add = [SubscriptionArray new];

Objective C memory management question: return NSObject inherited class type

I have the following function but I don't know how to release the memory of the temporary object defined:
#import <UIKit/UIKit.h>
#interface PatientsSet : NSObject {
NSString *tableid;
NSString *patient_name;
NSString *patient_surname;
NSString *city;
NSString *State;
NSString *phone;
}
#property (nonatomic, retain) NSString *tableid;
#property (nonatomic, retain) NSString *patient_name;
#property (nonatomic, retain) NSString *patient_surname;
#property (nonatomic, retain) NSString *city;
#property (nonatomic, retain) NSString *State;
#property (nonatomic, retain) NSString *phone;
-(id)initWithSet:(NSString *)dd patient_name:(NSString *)dn patient_surname:(NSString *)dsn city:(NSString *)ct state:(NSString *)st phone:(NSString *)ph ;
#end
(I'm getting from the a SQLITE DB the data into a NSobject derived class)
Shouldn't I use a [set release]; somewhere??
-(PatientsSet *)getPatientById:(NSString *)ID {
PatientsSet *set;
// Setup the database object
sqlite3 *database;
// Init the doctors_set Array
doctors_set = [[NSMutableArray alloc] init];
//NSString * databasePath1=[ [self getDocumentsDirectory] stringByAppendingPathComponent:databaseName ];
// 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
NSString* myString = [NSString stringWithFormat:#"SELECT patients.id,patients.patient_name,patients.patient_surname,patients.phone FROM patients where patients.id = '%#'",ID];
const char *sqlStatement = [myString cString];
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
NSString *aId = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 0)];
NSString *aName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
NSString *aDurname = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
NSString *aPhone = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 3)];
// Create a new set object with the data from the database
set=[[PatientsSet alloc] initWithSet:aId patient_name:aName patient_surname:aDurname city:#"" state:#"" phone:aPhone];
}
}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
return set;
}
You need to return an autoreleased object like so:
return [set autorelease];

Memory Leak in Objective C Class iOS

I have searched high and low to try to resolve this memory leak, but I can't figure out how to make it go away. I have several classes that I use to connect to my sqlite dbase and pull information.
When I run the app using performance tools, leaks, I keep finding that all of my classes leak memory.
Below is the code that I have. Any help resolving this leak would be greatly appreciated.
tbl_materialsList.h
#interface tbl_materialsList : NSObject {
NSInteger materialListID;
NSString *shoppingListID;
NSString *projectID;
NSString *materialName;
NSString *numberOfUnits;
NSString *purchased;
NSString *totalPrice;
NSString *unitPrice;
}
#property (nonatomic, readonly) NSInteger materialListID;
#property (nonatomic, retain) NSString *shoppingListID;
#property (nonatomic, retain) NSString *projectID;
#property (nonatomic, retain) NSString *materialName;
#property (nonatomic, retain) NSString *numberOfUnits;
#property (nonatomic, retain) NSString *purchased;
#property (nonatomic, retain) NSString *totalPrice;
#property (nonatomic, retain) NSString *unitPrice;
- (id)getDataToDisplay:(NSString *)dbPath :(NSString *)selectStatement;
- (void)saveData:(NSString *)dbPath :(NSString *)selectStatement;
- (id)initWithPrimaryKey:(NSInteger)pk;
tbl_materialsList.m
- (id)getDataToDisplay:(NSString *)dbPath :(NSString *)selectStatement {
// Init the data Array
NSMutableArray *data = [[NSMutableArray alloc] init];
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK) {
NSString *sql = selectStatement; //"select * from tbl_projects";
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(database, [sql UTF8String], -1, &selectstmt, NULL) == SQLITE_OK) {
//loop thru and fill the array
while(sqlite3_step(selectstmt) == SQLITE_ROW) {
//reading the results
NSInteger primaryKey = sqlite3_column_int(selectstmt, 0);
tbl_materialsList *listObj = [[tbl_materialsList alloc] initWithPrimaryKey:primaryKey];
listObj.shoppingListID = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 1)];
listObj.projectID = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 2)];
listObj.materialName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 3)];
listObj.numberOfUnits = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 4)];
listObj.purchased = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 5)];
listObj.totalPrice = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 6)];
listObj.unitPrice = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 7)];
[data addObject:listObj];
[listObj release];
}
}
//release the compiled statment from memory
sqlite3_finalize(selectstmt);
}
sqlite3_close(database); //Even though the open call failed, close the database connection to release all the memory.
return data;
}
Your final line:
return data;
should be:
return [data autorelease];
Unless, of course, you intend the returned data object to be owned by the caller, then you should make the method name conform to the Objective-C naming conventions in that method that return objects with a retain count of +1 should contain one of the words "copy" "create" or "new";
But I suspect that this isn't what you intend.
Does your tbl_materialslist implement a dealloc that sets all your retain properties to nil? If not, they are all leaking even though your listObj is being released.
strings should be #property(nonatomic,copy) first of all, and you need to release data. [data release];
An unrelated advice:
Never return an object as (id) unless it's absolutely necessary. For example, your getDataToDisplay:: should be
-(NSMutableArray*)getDataToDisplay:(NSString *)dbPath :(NSString *)selectStatement;
That way, you can get more compiler warnings when you make a mistake.
I guess there's an iPhone programming book which promotes this bad custom. The author of the book should be leashed and the book should be burned ... :p