I keep getting a memory leak indication from this sql statement when I assign the value retrieved from the database...
Person *tmpPerson = [[Person alloc] init];
tmpPerson.personName = [NSString stringWithUTF8String: (char*)sqlite3_column_text(SelectPersonStmt, 0)];
tmpPerson.personEmail = [NSString stringWithUTF8String: (char*)sqlite3_column_text(SelectPersonStmt, 1)];
[personList addObject:tmpPerson];
[tmpPerson release];
However if i replace the nsobject class object ...tmpPerson with regular NSString's ...leaks doesn't complain anymore? Does anyone know why?
NSString * personName = [NSString stringWithUTF8String:(char*)sqlite3_column_text(SelectPersonStmt, 0)];
NSString * personEmail = [NSString stringWithUTF8String:(char*)sqlite3_column_text(SelectPersonStmt, 1)];
Here is my class definition ... is there anything wrong with it?
#interface Person : NSObject {
NSString* personName;
NSString* personMobile;
NSString* personEmail;
}
#property (nonatomic, retain) NSString* personName, *personEmail, *personMobile;
- (id)init
{
if ((self = [super init])) {
personName = [NSString string];
personEmail = [NSString string];
personMobile = [NSString string];
}
return self;
}
Am I missing something here ? Should I be even initializing these strings, it didn't seem to make any difference? I put them there incase i wanted to initialize them with some default value.
While testing this through instruments, i noticed that the memory leak is triggered during the deallocation method. I tried this and it didn't help either
-(void) dealloc
{
personName = nil;
personEmail = nil;
[super dealloc];
}
Any help would be greatly appreciated. I've seen a lot of posts related to this but I'm not sure if folks are getting the same behavior I have mentioned.
You have to release your ivar in the dealloc:
-(void) dealloc
{
[personName release];
[personEmail release];
[personMobile release];
personName = nil; // Optionnal
personEmail = nil; // Optionnal
personMobile = nil; // Optionnal
[super dealloc];
}
You should release the used strings in the Person struct, not setting it to NULL.
Once you set it to NULL and there are no other objects referring to it, you have a leak, the system does not know how to reclaim it.
EDIT: damn, my answer came 10 seconds late :P
Related
I have declared NSString with some string value in ViewdidLoad like..
int i=1;
strval=[NSString stringWithFormat:#"%03d",i];
strval=[NSString stringWithFormat:#"S%#",strval];
NSLog(#"Value %#",strval);
it gives correct result as S001, but when i print this same in IBAction like,
- (IBAction)stringvalue:(id)sender {
NSLog(#"Value %#",strval);
}
it gives unknown values each time.Sometimes it throws EXEC_BAD_ACCESS error.
Please help me..
Try something like this
in .h
#property (nonatomic, strong) NSString *strval;
in .m
#synthesize strval = _strval
- (void)viewDidLoad
{
int i = 4;
// ARC
_strval = [NSString stringWithFormat:#"hello %d", i];
// None ARC
// strcal = [[NSString alloc] initwithFormat:#"hello %d",i];
NSLog(#"%#", _strval);
// Prints "hello 4" in console (TESTED)
}
- (IBAction)buttonPress:(id)sender
{
NSLog(#"%#", _strval);
// Prints "hello 4" in console (TESTED)
}
using ARC. This has been tested and works the way the question has been asked.
Looks like you aren't using ARC, so the string is being released the next time the autorelease pool drains. You need to explicitly retain it in viewDidLoad and explicitly release it in your overwridden dealloc method:
- (void)viewDidLoad
{
...
strval = [[NSString stringWithFormat:#"%03d", i] retain];
....
}
- (void)dealloc
{
[strval release];
...
[super dealloc];
}
(I am assuming you've actually declared strval as an instance method).
in .h
#property (nonatomic, strong) NSString *strval;
in .m
#synthesize strval = _strval
- (void)viewDidLoad
{
...
self.strval = [NSString stringWithFormat:#"%03d", i];
....
}
- (void)dealloc
{
self.strval = nil;
...
[super dealloc];
}
This one works either, with ARC and without.
Just one addition: With ARC the statement [super dealloc]; must be omitted.
Hi, I am trying to get array from StudentDbwithsearchbarViewController class to SearchBarDB class but resultant array not having any data it is giving null Array. Please help me out with this.
thanks in advance
#import <UIKit/UIKit.h>
#interface StudentDbwithsearchbarViewController : UIViewController<UITableViewDelegate,UITableViewDataSource> {
IBOutlet UITextField *txtMarks,*txtSname;
IBOutlet UITableView *tableStudents;
NSMutableArray *arrStudents;
}
#property(nonatomic,retain) NSMutableArray *arrStudents;
-(IBAction)saveStudentDetails;
-(IBAction)gotoSearchpage;
#end
#implementation StudentDbwithsearchbarViewController
#synthesize arrStudents;
- (void)viewDidLoad {
[super viewDidLoad];
arrStudents = [[DbStudent getStudentRecords]retain];
NSLog(#"%#",arrStudents);
NSLog(#"%d",[arrStudents retainCount]);
}
#import "DbStudent.h"
+(NSMutableArray*)getStudentRecords{
NSArray *arrDocPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *strDestPath = [NSString stringWithFormat:#"%#/Student5.sqlite",[arrDocPath objectAtIndex:0]];
NSMutableArray *arrStudents = [[NSMutableArray alloc]init];
sqlite3 *db;
if(sqlite3_open([strDestPath UTF8String], &db)==SQLITE_OK)
{
NSString *query = #"SELECT * FROM Student";
void* v;
char* err_msg;
sqlite3_stmt *studentStmt;
if(sqlite3_prepare_v2(db, [query UTF8String], -1, &studentStmt, &err_msg)==SQLITE_OK)
{
while (sqlite3_step(studentStmt)==SQLITE_ROW) {
int sno = sqlite3_column_int(studentStmt, 0);
NSString *sname = [NSString stringWithUTF8String: sqlite3_column_text(studentStmt, 1)];
float marks = sqlite3_column_double(studentStmt, 2);
Student *st = [[Student alloc]init];
st.Sno = sno;
st.Sname = sname;
st.marks = marks;
[arrStudents addObject:st];
}
}
}
return arrStudents;
}
#import "SearchBarDB.h"
#import"StudentDbwithsearchbarViewController.h"
- (void)viewDidLoad {
[super viewDidLoad];
StudentDbwithsearchbarViewController *sbd = [[StudentDbwithsearchbarViewController alloc]init];
NSLog(#"%d",[sbd.arrStudents retainCount]);
NSLog(#"%#",sbd.arrStudents);
// arrstudentBase = [sbd.arrStudents copy];
arrMatchedString = [[NSMutableArray alloc]init];
}
Lots of potential problems, no definitive answer without a clue as to what you've tried or how you've determined that it failed.
methods should not be prefixed with get; just call it studentRecords or fetchStudentRecords
your memory management code is all over the place; you'll be leaking that array, at the least.
retainCount is useless, don't call it.
writing raw SQL is a waste of time; at least use a wrapper like FMDB or, better yet, move to CoreData
Best guess for failure: the database doesn't exist or the query fails. Have you stepped through the query code?
I'm using TouchXML to parse an element in iOS. I retrieve a response from a web service using an NSInvocationOperation, then parse and display the results. Everything works fine as the background thread displays results on the main thread using [self performSelectorOnMainThread:#selector(displayLoginresult:) withObject:res waitUntilDone:NO]; but then I get an error:
2011-07-18 11:58:06.108 billsApp[873:7107] *** -[CFString release]: message sent to deallocated instance 0x5d809b0
The code to parse the element is:
-(LoginResult *) tryLogin:(NSString *)userName withPassword:(NSString*)password{
NSURL *url = [UrlUtility TryLogin:userName passwordHash:password];
CXMLDocument *responseObj = [UrlUtility xmlDocWithUrl:url];
if(responseObj == [NSNull null])
return [NSNull null];
CXMLElement *eleUser = [responseObj nodeForXPath:#"//User" error:nil];
CXMLElement *eleResult = [responseObj nodeForXPath:#"//Result" error:nil];
LoginResultType resultType;
//NSLog(#"Result: ");
//NSLog(eleResult );
// NSLog([[eleResult stringValue] lowercaseString]);
if ([[[eleResult stringValue] lowercaseString ] isEqualToString: #"successful"]){
resultType = Successful;
} else {
resultType = InvalidUsernameOrPassword;
}
LoginResult *res = [[LoginResult alloc] init];
res.result = resultType;
for (CXMLElement *resultElement in [responseObj children] ) {
NSLog([NSString stringWithFormat:#"%# %#", [resultElement name], [resultElement stringValue]]);
}
//todo: fix enum parsing =[LoginResult loginResultTypeStringToEnum: [eleResult stringValue]];
if(eleUser != nil) {
CXMLElement *eleClientID = [eleUser nodeForXPath:#"ClientID" error:nil];
CXMLElement *eleCompanyName = [eleUser nodeForXPath:#"CompanyName" error:nil];
CXMLElement *eleCompanyContact = [eleUser nodeForXPath:#"CompanyContact" error:nil];
CXMLElement *eleIsAgent = [eleUser nodeForXPath:#"IsAgent" error:nil];
CXMLElement *eleParentID = [eleUser nodeForXPath:#"ParentID" error:nil];
NSInteger *clientId = [[eleClientID stringValue] integerValue];
NSString *companyName = [eleCompanyName stringValue];
NSString *companyContact = [eleCompanyContact stringValue];
bool isAgent = [Utils stringToBool:[eleIsAgent stringValue]];
NSInteger *parentId = [[eleParentID stringValue] integerValue];
User *user = [[User alloc] initWithData:clientId companyName:companyName companyContact:companyContact isAgent:isAgent parentId:parentId];
res.user = user;
// release elements
// [eleClientID release];
// [eleCompanyName release];
// [eleCompanyContact release];
// [eleIsAgent release];
// [eleParentID release];
//release raw values
// [companyName release];
// [companyContact release];
}
// [eleResult release];
// [eleUser release];
return res;
}
Part of me wants to say it's a bug with TouchXML, but I find that very unlikely. Is there any way to further track down the error?
EDIT: The definitions for the properties on the User class is:
#property (nonatomic, readwrite) NSInteger clientId;
#property (nonatomic, retain) NSString *companyName;
#property (nonatomic, retain) NSString *companyContact;
#property (nonatomic, readwrite) bool isAgent;
#property (nonatomic, readwrite) NSInteger parentId;
And the instance is initialized with:
-(User*)initWithData:(NSInteger *)clientId companyName:(NSString *)company companyContact:(NSString*)contact isAgent:(bool)agent parentId:(NSInteger*)parentId {
//[self = super init];
self.clientId= clientId;
self.companyName= company;
self.companyContact= contact;
self.isAgent = agent;
self.parentId = parentId;
return self;
}
And the LoginResult class is:
#interface LoginResult : NSObject {
LoginResultType result;
User *user;
NSString * const loginResultTypeArray[4];
}
#property (nonatomic, readwrite) LoginResultType result;
#property (nonatomic, retain) User *user;
Just a try: are you correctly retaining companyName and companyContatct in your User class?
EDIT:
Next thing I would check is loginResultTypeArray. How are string assigned to it? I guess that this advice will also sound trivial to you, but it is really difficult to come up with useful suggestion with so little code...
Can't you get some idea about which CFString is actually being released? If it is not an autoreleased object, possibly the stack trace could point at the method which is sending the release message... this would be very helpful...
Otherwise, I would try and NSLog some of your NSStrings addresses, so that you can compare them with the address you find in the error log (and, again, try and find out which string was actually reused after deallocation).
Finally, another approach to find out which string is used after deletion could be using method swizzling to replace NSString's dealloc with a method of yours that, before calling the swizzled dealloc, does some logging of the objec. This will produce much log info, but knowing the address of the string you could find easily what you need. Find here info about swizzling.
This was a nightmare to track down. I had a method which returned an NSString *, which was then parsed by another method to produce an XML document, then release by the second method. I actually needed to autorelease it in the first method.
I create a NSMutableString called mutableScoreHolder outside my do-while loop.
I alloc it, 'copy' it into an other object called a 'Match' that contains a NSString.
When I build and analyze the code it reports a potential memory leak of my mutableScoreHolder.
NSString * scoreHolder;
NSMutableString * mutableScoreHolder;
count = 1;
numMatchCounter = 0;
int startOfScoreIndex = 0;
int endOfScoreIndex = 0;
int numberOfGoals=0;
do
{
match = [substring rangeOfString: #"points_bg"];
if (match.location == NSNotFound)
{
break;
}
if ((match.location + match.length) > ([substring length]))
{
break;
}
substring = [substring substringFromIndex:(match.location + match.length)];
match2 = [substring rangeOfString: #">"];
startOfScoreIndex = match2.location+1;
match2 = [substring rangeOfString: #"<"];
endOfScoreIndex = match2.location;
if ((count % 2) == 1)
{
scoreHolder = [substring substringWithRange:NSMakeRange(startOfScoreIndex, (endOfScoreIndex-startOfScoreIndex))];
mutableScoreHolder = [[NSMutableString alloc] initWithString:scoreHolder];
numberOfGoals += [scoreHolder intValue];
}
else
{
Match *aMatch = [theMatchScoresArray objectAtIndex:(numMatchCounter)];
numberOfGoals += [[substring substringWithRange:NSMakeRange(startOfScoreIndex, (endOfScoreIndex-startOfScoreIndex))] intValue];
[scoreHolder stringByAppendingString:#" - "];
[mutableScoreHolder appendString:#" - "];
[scoreHolder stringByAppendingString:[substring substringWithRange:NSMakeRange(startOfScoreIndex, (endOfScoreIndex-startOfScoreIndex))]];
[mutableScoreHolder appendString:[substring substringWithRange:NSMakeRange(startOfScoreIndex, (endOfScoreIndex-startOfScoreIndex))]];
aMatch.theScore = [mutableScoreHolder copy];
aMatch.matchGoalCount = numberOfGoals;
numMatchCounter++;
numberOfGoals=0;
}
count++;
}
while ( match.length != 0 );
Here is my Match Object Class.
#interface Match : NSObject
{
NSString *teamName1;
NSString *teamName2;
NSString *theScore;
int matchGoalCount;
NSMutableArray *scorersArray;
NSMutableArray *scorerOrderArray;
NSString *matchStatus;
NSString *matchDate;
bool matchNotStarted;
}
#property(nonatomic) int matchGoalCount;
#property(nonatomic) bool matchNotStarted;
#property(nonatomic, retain) NSString *teamName1;
#property(nonatomic, retain) NSString *teamName2;
#property(nonatomic, retain) NSString *theScore;
#property(nonatomic, retain) NSString *matchStatus;
#property(nonatomic, retain) NSString *matchDate;
#property(nonatomic, retain) NSMutableArray *scorersArray;
#property(nonatomic, retain) NSMutableArray *scorerOrderArray;
-(id)init;
#end
#import "Match.h"
#implementation Match
#synthesize teamName1;
#synthesize teamName2;
#synthesize theScore;
#synthesize scorersArray;
#synthesize matchDate;
#synthesize matchStatus;
#synthesize matchGoalCount;
#synthesize scorerOrderArray;
#synthesize matchNotStarted;
-(id)init
{
//NSLog(#"****** MATCH INIT ******");
self = [super init];
scorersArray =[[NSMutableArray alloc] init];
scorerOrderArray =[[NSMutableArray alloc] init];
return self;
}
-(void) dealloc
{
[scorersArray release];
[scorerOrderArray release];
[teamName1 release];
[teamName2 release];
[theScore release];
[matchStatus release];
[matchDate release];
[scorersArray release];
[scorerOrderArray release];
[super dealloc];
}
#end
I do find there there is a string leaked when i run instruments checking for leaks. So I think this 'potential leak' might be the leak I see.
Because the scores has a retain
#property(nonatomic, retain) NSString *theScore;
And there is a string copied into it
aMatch.theScore = [mutableScoreHolder copy];
Could that give a retain count of 2? And so then leak?
Sorry for the complicated question! Has my head spinning trying to get my head around it.
Thanks
-Code
You're definitely leaking here, for 2 separate reasons.
The first is you're alloc/init'ing an NSMutableString and stuffing it into mutableScoreHolder. This is a local variable, and as soon as this value goes out of scope (or gets replaced the next time a new array is created) the old value is leaked. This should be an autoreleased value instead, as in [NSMutableString stringWithString:scoreHolder].
The second is you're copying the string and stuffing the resulting value into a property. What you should do is redeclare that property as copy
#property(nonatomic, copy) NSString *theScore;
and then just assign mutableScoreHolder to that property directly
aMatch.theScore = mutableScoreHolder
With your existing code, you copy the array, and then the property retains it. With this change, the property copies it directly, and no extra retains are used.
Note, in general it's a good idea to declare properties with supported types as copy. This includes things like NSString, NSArray, NSDictionary, etc. If you're assigning an already-immutable object to the property, the copy falls back to retain instead and there's no performance hit. But in situations like yours where you're assigning mutable objects, it will copy it as appropriate and keep an immutable snapshot in the property.
And there is a string copied into it
aMatch.theScore = [mutableScoreHolder copy];
Could that
give a retain count of 2? And so then
leak?
exactly. You could change the property of theScore from retain to copy to fix this. THen you can use aMatch.theScore = mutableScoreHolder;
and there is (at least) one other leak:
mutableScoreHolder = [[NSMutableString alloc] initWithString:scoreHolder];
this gets never released.
while(sqlite3_step(selectstmt) == SQLITE_ROW) {
NSInteger primaryKey = sqlite3_column_int(selectstmt, 0);
//Expenseentry* temp=[[[Expenseentry alloc]init]autorelease];
//Expenseentry* temp=[[Expenseentry alloc]init];
temp=nil;
temp=[[Expenseentry alloc]init];
//memory leak here
temp.ID=[NSString stringWithFormat:#"%d",primaryKey];
//memory leak here
int i=1;
#try{
//Expenseentry* temp=[[Expenseentry alloc]init];
//tried this but no luck
NSString *s=[[NSString alloc]initWithFormat:#"%f",sqlite3_column_double(selectstmt, 1)];
temp.amount=s;
[s release];
[arrreturn addObject:temp];
//[temp release];
//if i uncomment this app crashes
//[formatter release];
//printf("\n daata count %d ",[arrreturn count]);
}
#catch(id ex )
{
printf("ooooopssss exception ");
}
i++;
}
my expense entry class
#interface Expenseentry : NSObject {
NSString *ID;
NSString *amount;
}
#property (nonatomic, retain) NSString *ID;
#property (nonatomic, retain) NSString *amount;
#end
and .m is just
- (void)dealloc {
[ID release];
[amount release]
}
It looks like temp is an instance variable for that class
Make sure you release temp when you are done or right before you use it again
Try doing the following
[temp release];
temp=[[Expenseentry alloc]init];
temp.ID=[NSString stringWithFormat:#"%d",primaryKey];
The other option is to release after your done with it inside of the while(sqlite3_step) loop
while(sqlite3_step(selectstmt) == SQLITE_ROW) {
...
temp=[[Expenseentry alloc]init];
temp.ID=[NSString stringWithFormat:#"%d",primaryKey];
... //Use temp
[temp release];
temp = nil; //Best practice to set it to nil
If the temp.ID string is leaking you need to look into the Expenseentry class to make sure your doing proper memory management there.
Edit: I now see the rest of your code posted
[arrreturn addObject:temp];
//[temp release];
//if i uncomment this app crashes
The reason why it is probably crashing is as I said before make sure you set it to nil after releasing
Edit 2: You are reusing the same object inside of the while loop also
You will want to move the temp allocation into the while loop or else every object in that array will point to the same object. I am not sure what you goal is with the code but take at a look at the following code.
while(i>5)
{
temp=[[Expenseentry alloc]init];
temp.ID=[NSString stringWithFormat:#"%d",primaryKey];
#try
{
NSString *s=[[NSString alloc]initWithFormat:#"%f",sqlite3_column_double(selectstmt, 1)];
temp.amount=s;
[s release];
[arrreturn addObject:temp];
}
#catch(id ex )
{
printf("ooooopssss exception ");
}
[temp release];
temp = nil;
i++;
}
the temp=nil seems a bit odd. whenever you assign the variable temp to a new object don't forget to release the previous object.
if you write:
Expenseentry* temp=[[Expenseentry alloc]init];
temp=nil;
you get a memory leak because you have created an Expenseentry object and then said good riddance to the object basically. You need to do a [temp release]; before assigning to nil on the iphone.
there could be other leaks like in your Expenseentry but you don't show how it looks like i.e. how the properties ID are declared.
Ok I found my mistake just posting if any one can explain this behavior:
memory leak cause array and array-object were not released.If I would release any of it app crashes.
mistake 1:[super dealloc] missing in expenseentry's dealloc.
doubt:why is it required to release super? when apple doc says you have to release object you own.
mistake 2:array being returned by this function is stored in instance variable(and synthesized property with retain as attribute) of caller.
and I have released that property in dealloc as it is retained.
receivedArr=fun()
in dealloc
[receivedArr release]