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]
Related
I have this code:
// .m
- (void)viewDidLoad {
NSMutableArray *array = [[NSMutableArray alloc] init];
[self addToArray];
}
- (void)addToArray {
NSString *stringA;
[stringA isEqualToString:#"door"];
NSString *stringB;
[stringB isEqualToString:textField.text];
[array addObject:stringA];
if ([stringA isEqual:stringB]) {
[stringA isEqual:nil];
[tableView reloadData];
} else {
[array addObject:stringB];
[tableView reloadData];
}
}
When I call the method addToArray it keeps returning me an error called Thread 1: Program recived signal "EXC_BAD_ACCESS", and the debugger output says : Single stepping until exit from function objc_msgSend, which has no line number information. at the line [self addToArray]. Any idea of how to solve it? I have wasted to much time with it, please help me!
As was said by others, array should be an instance variable or property of the class, declared in the .h file:
#property (strong) NSMutableArray *array;
Or, without ARC:
#property (retain) NSMutableArray *array;
Now you #synthesize array; in your implementation file and can access it from anywhere. Then you can do:
- (void) viewDidLoad
{
self.array = [[NSMutableArray alloc] init];
[self addToArray];
}
You seem to assume that isEqualToString does an assignment. It doesn't, it checks strings for (textual) equality. Try this:
- (void) addToArray
{
NSString *stringA = #"door";
NSString *stringB = textField.text;
[array addObject: stringA];
if (![stringA isEqualToString: stringB])
[array addObject: stringB];
[tableView reloadData];
}
These two variables are uninitialized and will cause you big problems:
NSString *stringA;
[stringA isEqualToString:#"door"];
NSString *stringB;
[stringB isEqualToString:textField.text];
You have not assigned anything to either stringA or stringB. Besides the result of your call to isEqualToString is never used.
Two things I can notice in your code:
1) Make array a class variable, so you can access it from your -[addToArray] method. Better do this in your .h file, for example:
#interface MyViewController : UIViewController {
#private
// ...skipped...
NSMutableArray * array;
// ...rest of class skipped...
}
#end
Then, in your .m file the method should look like this:
// .m
- (void)viewDidLoad {
array = [[NSMutableArray alloc] init];
[self addToArray];
}
And don't forget to release the array:
- (void)dealloc {
[array release];
[super dealloc];
}
2) Do not mess up -[NSString isEqualToString:] method with simple assigment to a variable. So in your -[addToArray] method, for example, replace this:
NSString *stringA;
[stringA isEqualToString:#"door"];
with this:
NSString *stringA = #"door";
And this:
NSString *stringB;
[stringB isEqualToString:textField.text];
with this:
NSString *stringB = textField.text;
3) Check the logic of -[addToArray] method - it is not very clear what are you going achieve.
interface file:
// ...
UITextView *statusTextView_;
UITableView *accountListTableView_;
NSMutableArray *accountList_;
NSString *lastStatus_;
// ...
#property (retain) UITextView *statusTextView;
#property (retain) UITableView *accountListTableView;
#property (retain) NSMutableArray *accountList;
#property (retain) NSString *lastStatus;
// ...
implement file:
// ...
#synthesize statusTextView=statusTextView_;
#synthesize accountListTableView=accountListTableView_;
#synthesize accountList=accountList_;
#synthesize lastStatus=lastStatus_;
- (void)aBtnTapAction:(id)sender
{
[self.lastStatus release];
NSString *buf = [[NSString alloc] initWithString:self.statusTextView.text];
self.lastStatus = buf;
[buf release];
for (NSDictionary *dict in self.accountList) {
if (TRUE == [[dict objectForKey:#"checked"] boolValue]) {
NSString *selectorName = [[NSString alloc] initWithFormat:#"%#:", [dict objectForKey:#"name"]];
SEL sel = NSSelectorFromString(selectorName);
[selectorName release];
if (YES == [self respondsToSelector:sel]) {
[self performSelectorInBackground:sel withObject:dict];
}
}
}
}
selectorName is one of followings
- (void)sina:(NSDictionary *)info
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
SinaController *sina = [[FooController alloc]
initWithUsername:[info objectForKey:#"username"]
andPasswd:[info objectForKey:#"passwd"]];
code = [sina post:self.lastStatus];
[sina release];
[pool release];
}
- (void)qq:(NSDictionary *)info
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
QQController *qq = [[FooController alloc]
initWithUsername:[info objectForKey:#"username"]
andPasswd:[info objectForKey:#"passwd"]];
code = [qq post:self.lastStatus];
[qq release];
[pool release];
}
app always crash in qq or sina thread, log said:
warning: check_safe_call: could not restore current frame
warning: Unable to restore previously selected frame.
Testing environment: MacOS10.6.7, XCode4 & Simulator.
I can't find any useful information by XCode Product -> analyze or Profile -> memory leaks.
I'm following Memory Management Programming Guide and try my best to fix it, but it still crash.
What's wrong with my code, why it crash ?
What are best practices that Objective-C coder when writing multiple thread pragram ?
Thanks for reply.
By releasing using the dot notation, you are over-releasing.
[self.lastStatus release];
should just be
self.lastStatus = nil;
Otherwise you are calling a release on lastStatus and then when you assign the new value using
self.lastStatus = buf;
Then this is first calling a release on the already released object. For more information read up about properties, the dot notation and memory management.
When should I be releasing [self.activeLocations], which is an NSMutableArray inside my custom object? I am also getting memory leaks in initWithValue.
Also the Location object below. Am I calling this and releasing this properly?
Method in Custom Object.m:
- (id)initWithValue:(NSString *)value {
if ((self = [super init])) {
self.couponId = [value valueForKey:#"couponId"];
self.couponName = [value valueForKeyPath:#"couponName"];
self.qrCode = [value valueForKeyPath:#"description"];
self.companyName = [value valueForKeyPath:#"companyName"];
self.categoryName = [value valueForKeyPath:#"categoryName"];
self.distance = [value valueForKeyPath:#"distance"];
NSDictionary *activeLocationsDict = [value valueForKeyPath:#"activeLocations"];
//self.activeLocations = [[[NSMutableArray alloc] init] autorelease];
self.activeLocations = [NSMutableArray array];
for (id val in activeLocationsDict) {
// Add JSON objects to array.
Location *l = [[Location alloc] initWithValue:val];
[self.activeLocations addObject:l];
[l release];
}
}
return self;
}
- (void)dealloc {
[super dealloc];
couponId = nil;
couponName = nil;
qrCode = nil;
companyName = nil;
categoryName = nil;
distance = nil;
activeLocations = nil;
}
My Custom Object.h
#interface Coupon : NSObject {
NSNumber *couponId;
NSString *couponName;
NSString *qrCode;
NSString *companyName;
NSString *categoryName;
NSString *distance;
NSMutableArray *activeLocations;
}
#property (nonatomic, copy) NSNumber *couponId;
#property (nonatomic, copy) NSString *couponName;
#property (nonatomic, copy) NSString *qrCode;
#property (nonatomic, copy) NSString *companyName;
#property (nonatomic, copy) NSString *categoryName;
#property (nonatomic, copy) NSString *distance;
#property (nonatomic, retain) NSMutableArray *activeLocations;
- (id)initWithValue:(NSString *)value;
This is how I'm using the above initWithValue:
- (NSMutableArray *)createArrayOfCoupons:(NSString *)value {
NSDictionary *responseJSON = [value JSONValue];
// Loop through key value pairs in JSON response.
//NSMutableArray *couponsArray = [[NSMutableArray alloc] init] autorelease];
NSMutableArray *couponsArray = [NSMutableArray array];
for (id val in responseJSON) {
// Add JSON objects to array.
Coupon *c = [[Coupon alloc] initWithValue:val];
[couponsArray addObject:c];
[c release];
}
return couponsArray;
}
I get memory leaks on initWithValue in the above method as well...
Location Custom Object:
- (id)initWithValue:(NSString *)value {
if ((self = [super init])) {
self.locationId = [value valueForKeyPath:#"locationId"];
self.companyName = [value valueForKeyPath:#"companyName"];
self.street1 = [value valueForKeyPath:#"street1"];
self.street2 = [value valueForKeyPath:#"street2"];
self.suburb = [value valueForKeyPath:#"suburb"];
self.state = [value valueForKeyPath:#"state"];
self.postcode = [value valueForKeyPath:#"postcode"];
self.phoneNo = [value valueForKeyPath:#"phoneNo"];
self.latitude = [value valueForKeyPath:#"latitude"];
self.longitude = [value valueForKeyPath:#"longitude"];
}
return self;
}
- (void)dealloc {
[super dealloc];
locationId = nil;
companyName = nil;
street1 = nil;
street2 = nil;
suburb = nil;
state = nil;
postcode = nil;
phoneNo = nil;
latitude = nil;
longitude = nil;
}
- (id)init {
....
}
Get rid of this. It does nothing.
- (id)initWithValue:(NSString *)value {
[super init];
There's a specific pattern you should use for initialization:
- (id)initWithValue:(NSString *)value {
if (( self = [super init] )) {
// everything except the return
}
return self;
}
Finally, to answer your actual question, assuming you're using retain with your property, there's two places you'll need to release.
Here's the first:
self.activeLocations = [[NSMutableArray alloc] init];
Why: [[NSMutableArray alloc] init] makes your code own the object by retaining it. But the property set also claims ownership by retaining it. You don't really want this NSMutableArray owned by the code and your custom object, you want it owned by your object.
My suggestion is to just use this:
self.activeLocations = [NSMutableArray array];
The second place is in your dealloc:
- (void)dealloc {
self.activeLocations = nil;
// ...and everything else you've set as a property using retain
[super dealloc];
}
(Personally, I've gone back and forth on whether to use dot notation in dealloc rather than [activeLocations release];. I'm favouring setting to nil using the property now, which puts all the memory management rules in a single location.)
Apple has a great document on memory management you should read: Memory Management Programming Guide: Object Ownership and Disposal.
First of all, your overridden -init method is completely unnecessary because by default when a method is invoked, the runtime will perform an upward traversal of the inheritance hierarchy until the specified method is found, so it will find NSObject's -init method and invoke it.
Second, you should invoke release on all of your owned properties (ones with copy or retain) in your overridden -dealloc method.
Third, in your case, when you call the property setter passing in an object that is already owned locally, you must send the object the release message after invoking the setter to correctly hand off ownership of the object to the receiver.
There are two ways to do this:
One way is to create an object that you own using alloc, copy or new, and then invoke the property setter, passing in that object, then send it the release message.
Another way is to pass in an autoreleased object to the property setter, which will then retain or copy its argument and thereby obtain ownership
The answer to when you should be releasing it is a question of whether or not the activeLocations array and all the elements in that array (remember each element in the array is retained by the array itself) are necessary throughout the lifetime of the Location object.
If you use the activeLocations array for some temporary purpose, for example in a method or chain of methods, then don't need it again, or you plan to refresh its members at some later time when you need it next, then it makes sense to release the array (and its elements, which is automatic) when you're done using it, in whatever function last uses the array. You will use the convention
self.activeLocations = nil;
to let the runtime system release the array and set the member to nil.
If, on the other hand, the activeLocations array data is mandatory for the Locations object to function and must exist as long as the Location object exists, then you will want to release the array inside the dealloc method of the Location object, for example:
- (void) dealloc {
[activeLocations release];
[super dealloc];
}
As it happens, you're pretty much always going to want to release member objects such as activeLocations in a dealloc method. This ensures that when the Location object is released the members it contains are cleaned up. Remember that Objective-C does not call methods on null pointers, so if you have previously set activeLocations to nil the call in dealloc is a safe no-op.
Given then that you'll always set things up to release in dealloc, now you really just have to ask yourself if you need a release/recreate phase somewhere in your object lifecycle (again, determined by frequency-of-use requirements).
It depends on what you're asking. In the initWithValue: method that you've shared, you are double-retaining the array. It should be released or autoreleased once within initWithValue:.
The array should be released a second time in the custom object's dealloc method.
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
Testing my app on the device it returns a leak whe i call the copy of a custom object ande i can't understand why.
this is the call:
NSMutableArray *arr = [[NSMutableArray alloc] initWithCapacity:5];
for (SinglePart *sp in [copyFrom partList]) {
[arr addObject:[sp copy]];
}
self.partList = arr;
[arr release];
this is the method:
- (id)copyWithZone:(NSZone *)zone {
SinglePart *copy = [[[self class] allocWithZone:zone] initWithSinglePart:self];
[copy loadImage];
return copy;
}
this is the method that is called by copyWithZone:
- (id)initWithSinglePart:(SinglePart *)copyFrom {
if (self = [super init]) {
self.imagePath = [copyFrom.imagePath copy];
self.color = [UIColor colorWithCGColor:copyFrom.color.CGColor];
self.hasOwnColor = copyFrom.hasOwnColor;
self.blendingMode = copyFrom.blendingMode;
}
return self;
}
copy returns a new object with retain count 1. Meaning you need to release the new object, which you are not doing.
NSMutableArray *arr = [[NSMutableArray alloc] initWithCapacity:5];
for (SinglePart *sp in [copyFrom partList]) {
SingPart *theCopy = [sp copy];
[arr addObject:theCopy];
[theCopy release];
}
self.partList = arr;
[arr release];
Even your custom copyWithZone: method inits an object, but does not autorelease it, which is the expected behavior of a copy method. Copy must be balanced just like a retain or init, meaning you must balance it with release at some point.
Lastly, your initWithSinglePart: method leaks the imagePath as well. In this case if you declare the imagePath property as copy instead of retain then you don't need to do this manually at all. Then you simply assign the value and let the property setter do it for you.
// Header
#property (copy) NSString *imagePath;
// Now this will do the copy for you
self.imagePath = copyFrom.imagePath;
Also, is the property imagePath defined with retain or copy semantics?
If so you need to add an autorelease here:
self.imagePath = [[copyFrom.imagePath copy] autorelease];
because the default setter will retain/copy it too.
So, you either need to autorelease, or omit the "self." to bypass the default setter.
You are making a copy of sp and then adding it to the array. The array then retains the object so your retain count is now 2.
In the end you release arr, thus making the retain count of it's items 1.
You should either add another release to the sp objects, or not use copy.
Try this:
self.partList = [NSMutableArray arrayWithCapacity:5];
for (SinglePart *sp in [copyFrom partList]) {
[arr addObject:sp];
}