Is only one release is needed in my Objective C code? - iphone

For some reason I can't use arc, so in my code below..
Foo.h
#interface Foo : NSObject
#property (nonatomic, copy) NSString * string;
#end
Foo.m
#implementation Foo
#synthesize string=_string;
- (void) bar {
self.string = [NSString stringWithFormat:#"test1"];
self.string = [NSString stringWithFormat:#"test2"];
}
-(void) dealloc
{
[_string release];
[super dealloc];
}
#end
The bar method might not always be called, or they can be called multitime.
Is only one release in the dealloc is all needed?

Yes, since you are using properties so setter method will take care of releasing memory allocation.It will allocate memory as follows:
-(void)setValue:(NSString *)strValue
{
if(string)
{
[string release];
string = nil;
}
string = [strValue copy];
}

Is only one release in the dealloc is all needed?
Yes.
Explanation: the setter method releases the old object that was assigned to the property and retains the new one.

Related

NSMutableArray with memory leak

I am using following code to create NSMutableArray. When I run the same in “Profile” mode, it is showing a memory leakage.
SampleArray.h
#interface SampleArray: NSObject {
}
#property (assign, retain) NSMutableArray *array;
#end
SampleArray.m
#import "SampleArray.h"
#implementation SampleArray
#synthesize array;
-(void) viewDidLoad {
self.array =[ [NSMutableArray alloc] init];
}
-(void) viewWillDisappear:(BOOL)animated {
[self.array release];
}
#end
When I am using autorelease, then I can’t able to access the same in other function or method and return null value. Please help me to find the issue.
releasing this array in viewWilLDisappear is not a good idea, you should release in the dealloc function. You should worry about over-releasing this item and causing a program crash since viewWilLDisappear may get called multiple times during the lifetime of this ViewController.
Anyhow, you are double retaining the item beacuse your property has a retain on it (and make it nonatomic, not assign), add an autorelease to your alloc/init:
self.array =[[[NSMutableArray alloc] init] autorelease];
and move
[array release];
to your dealloc function. Or convert to ARC and don't worry any longer...
Try setting it to (nonatomic, retain), then autoreleasing.
It is better to handle memory de-allocation in your -dealloc() and set your array to nil to be more secure in your -viewDidUnload()
so it will be:
-(void) viewDidUnload
{
self.array = nil;
}
-(void) dealloc
{
[array release];
[super dealloc];
}
and like other people said, declare your property as (nonatomic, retain) instead of (assign, retain)
First of all I'm assuming that you are using
#property (nonatomic, retain) NSMutableArray *array;
use this
-(void) viewDidLoad {
array =[[NSMutableArray alloc] init];
}
-(void) viewWillDisappear:(BOOL)animated {
[array release];
}
I will recommend you to use dealloc instead of viewWillDisappear
-(void) dealloc {
[array release];
[super dealloc];
}
Explanation of your code
-(void) viewDidLoad {
// here you are allocating a mutable array thus retain count becomes one
// then you are assigning it to the property which is retain and thus retains it
// making the retain count 2
self.array =[ [NSMutableArray alloc] init];
}
-(void) viewWillDisappear:(BOOL)animated {
// here you are releasing it so its retain count becomes 1 from 2
// thus shows memory leak
[self.array release];
}

Avoid Memory Leak When Property Assigning Twice

Let say i have an class named as MyTestClass.h.
Class structure is look like
#interface MyTestClass : NSObject {
NSString *testString;
}
#property (nonatomic, retain)NSString * testString;
#end
.m file
#implementation MyTestClass
#synthesize testString;
-(id) init{
[self setTestString:#""];
return self;
}
-(void)dealloc{
[self.testString release];
testString = nil;
[super dealloc];
}
#end
Now i created an object of MyTestClass and assigned testString twice
MyTestClass * myTestClass = [[MyTestClass alloc] init];
[myTestClass setTestString:#"Hi"];
[myTestClass setTestString:#"Hello"];
Now i think, two times my testStrings memory is leaked!! (one through init() and another one through my first setTestString method)
Am i correct? or will #property (nonatomic, retain) handle/release previous allocated memory?
or ,in this kind of cases ,will i need to override the setTestString() in MyTestClass.m like below code
-(void)setTestString:(NSString *)tempString{
[testString release];
testString = nil;
testString = [tempString retain];
}
Any help on this question is appreciated.
Thanks.
Any help on this question is appreciated.
I'll take this as a licence to make sone observations not necessarily directly related to your question.
Firstly, if you declare a retain property (as you have done) and synthesize it, the automatically generated getters and setters handle memory management correctly for you.
If you manually create setter (which you are allowed to do even with an #synthesize existing), you have to do the memory management yourself. Use either of trojanfoe's examples.
The setter in your question contains a bug in that if testString == tempString i.e. you assign the value of the property to itself, you could end up with assigning a dangling pointer to the property because you effectively release tempString and then retain it.
This is an implementation detail that you an safely ignore, but string literals e.g. #"blah" are compiled into the executable and will never be deallocated no matter how many times they are released. So, with your example, even if the setter did not do correct memory management, there will be no leak.
By the way, the normal pattern for an init method is
-(id) init
{
self = [super init];
if (self != nil)
{
// init stuff
}
return self;
}
or logical equivalent.
You should get into the habit of using it because you need to call the super class's init method and it is allowed to change the value of self, even to nil.
Also, while it is very good practice normally to set the object reference to nil after releasing it, in both cases when you do it, it is unnecessary. the first time, the variable is about to go out of scope and the second time you immediately assign it from some other object.
It's not a leak. Synthesized variable are correctly handled.
A synthesized method is implemented in this way (for a retain keyword)
#property (nonatomic, retain) NSString *string;
//backed by variable NSString *_string;
- (void)setString:(NSString*)newString
{
if (newString != _string) {
[_string release];
_string = [newString retain];
}
}
Of course this is a leak:
- (void)aMethod //of my class with string property
{
NSString *aString = [[NSString alloc] initWithString:#"hello"];
self.string = aString; //retain count of 2
self.string = #"hello2"; //retain count of 1 for aString
//now I don't release aString.... leak
}
If you use the auto-generated setter (in your case, setTestString:, which is also called by self.testString = ...;), the previous value of a retain property is released before being set. So no, there is no leak in the code you posted above.
The synthesized setter method should do the right thing. Here's an example of it's implementation:
- (void)setTestString:(NSString *)tempString
{
[tempString retain];
[testString release];
testString = tempString;
}
or:
- (void)setTestString:(NSString *)tempString
{
if (tempString != testString)
{
[testString release];
[tempString retain];
testString = tempString;
}
}
the dealloc is only called when the instance is destructed.
if you do :
[myTestClass setTestString:#"Hi"];
[myTestClass setTestString:#"Hello"];
in the same block, you're juste calling twice the setter. there is no memory leak.
When you use #synthesize on a property that specifies retain, the setter that's generated will handle the retain/release correctly for multiple assignments. As long as you use self. rather than going directly to the backing variable and do a final release in dealloc you should be fine.

Data going missing when passed between threads using a Singleton

Edit:
Thanks #BlackFrog. I think I'm nearer now, but the values are still not get getting through...
The values are set as shown by logs within [progressController updateProgressSummary:...] but are nil when I log them in progressUpdate initWithProgressUpdate:.... as shown below.
I'm slightly confused over which property is used the one set for progressUpdate or the ones set for each of the 3 components of progressUpdate. I have changed the 3 individual properties from assign to retain as suggested and have also tried doing the same with the overall progressUpdate property too (not shown here).
progressController.h
......
#property (nonatomic, assign) ProgressUpdate *progressUpdate;
progressController.m
// Ask delegate to update and display Progress text
-(void) updateProgressSummary:(NSString *)summary detail:(NSString *)detail percentComplete:(NSNumber *)complete {
// These report the proper values
DLog(#"Reporting Summary - %s", [summary UTF8String]);
DLog(#"Reporting Detail - %s", [detail UTF8String]);
DLog(#"Reporting Complete - %i", [complete intValue]);
if (summary != nil)
self.progressUpdate.summaryText = summary;
self.progressUpdate.detailText = detail;
self.progressUpdate.percentComplete = complete;
ProgressUpdate *progressUpdateForIssue = [[ProgressUpdate alloc] initWithProgressUpdate:progressUpdate];
[self.delegate performSelectorOnMainThread:#selector(displayProgress:) withObject:progressUpdateForIssue waitUntilDone:NO];
[progressUpdateForIssue release];
}
But then a few milliseconds later...., inside the object....they're nil.
progressUpdate.h
.....
#property (nonatomic, retain) NSString *summaryText;
#property (nonatomic, retain) NSString *detailText;
#property (nonatomic, retain) NSNumber *percentComplete;
progressUpdate.m
-(id) initWithProgressUpdate:(ProgressUpdate *)update {
if ((self = [super init])) {
summaryText = [update.summaryText copy];
detailText = [update.detailText copy];
percentComplete = [[NSNumber alloc] initWithFloat:[update.percentComplete floatValue]];
}
// These report nil values
DLog(#"Reporting in progUpdate summaryText - %s", [summaryText UTF8String]);
DLog(#"Reporting in progUpdate detailText - %s", [detailText UTF8String]);
DLog(#"Reporting in progUpdate percentComplete - %i", [percentComplete intValue]);
return self;
}
end of update
I need some help with passing data in a custom class from one thread to another. Its there before the pass but then disappears upon arrival. I've tried everything I know, but to no avail.
My background thread calls ProgressController and passes it details of the current progress. That in turn does performSelectorOnMainThread on ProgressController's delegate (the view controller) to display the details.
It was all working fine when I was passing through a single NSString, but I need to pass two strings and a number and as performSelectorOnMainThread can only pass one object, I have encapsulated these in a custom object - ProgressUpdate.
The data gets through to ProgressController correctly but is null by the time that it appears in the View Controller. I know this as I've put NSLogs in various places.
I wonder if its to do with:
multithreading and custom objects
the fact that ProgressController is a singleton, which is why I have then alloc'd a new ProgressUpdate each time its called, but that has not helped.
Any ideas welcome. For clarity, the code is below.
ProgressUpdate.h
#import <Foundation/Foundation.h>
#interface ProgressUpdate : NSObject {
NSString *summaryText;
NSString *detailText;
NSNumber *percentComplete;
}
#property (nonatomic, assign) NSString *summaryText;
#property (nonatomic, assign) NSString *detailText;
#property (nonatomic, assign) NSNumber *percentComplete;
-(id) initWith:(ProgressUpdate *)update;
#end
ProgressUpdate.m
#import "ProgressUpdate.h"
#implementation ProgressUpdate
#synthesize summaryText, detailText, percentComplete;
-(id) initWith:(ProgressUpdate *)update {
self = [super init];
self.summaryText = update.summaryText;
self.detailText = update.detailText;
self.percentComplete = update.percentComplete;
return self;
}
#end
ProgressController.m
static ProgressController *sharedInstance;
+ (ProgressController *)sharedInstance {
#synchronized(self) {
if (!sharedInstance)
[[ProgressController alloc] init];
}
return sharedInstance;
}
+(id)alloc {
#synchronized(self) {
NSAssert(sharedInstance == nil, NSLocalizedString(#"Attempted to allocate a second instance of a singleton ProgressController.", #"Attempted to allocate a second instance of a singleton ProgressController."));
sharedInstance = [super alloc];
}
return sharedInstance;
}
-(id) init {
if (self = [super init]) {
[self open];
}
return self;
}
.........
// Ask delegate to update and display Progress text
-(void) updateProgressSummary:(NSString *)summary detail:(NSString *)detail percentComplete:(NSNumber *)complete {
if (summary != nil)
self.progressUpdate.summaryText = summary;
self.progressUpdate.detailText = detail;
self.progressUpdate.percentComplete = complete;
ProgressUpdate *progressUpdateForIssue = [[ProgressUpdate alloc] initWith:progressUpdate];
[self.delegate performSelectorOnMainThread:#selector(displayProgress:) withObject:progressUpdateForIssue waitUntilDone:NO];
[progressUpdateForIssue release];
}
RootViewController.m
// Delegate method to display specific text in Progress label
- (void) displayProgress:(ProgressUpdate *)update {
[progressSummaryLabel setText:update.summaryText];
[progressDetailLabel setText:update.detailText];
[progressBar setProgress:[update.percentComplete intValue]];
[progressView setNeedsDisplay];
}
In the init method, you are only assigning the ivars and not retaining them in the new object.
Redo your init method as the following:
-(id) initWithProgressUpdate:(ProgressUpdate *)update {
if ((self = [super init])) {
summaryText = [update.summaryText copy];
detailText = [update.detailText copy];
percentComplete = [[NSNumber alloc] initWithFloat:[update.percentComplete floatValue];
}
return self;
}
Couple of points:
You should not use accessor in the init method
Rename your init method to be a lot clear
In the #property, change the assign to retain
Try removing the statement '[progressUpdateForIssue release];' in the method
'-(void) updateProgressSummary:(NSString *)summary detail:(NSString *)detail percentComplete:(NSNumber *)complete '.
Also change the property attribute from 'assign' to 'retain' in your class ProgressUpdate.
You could release those properties in the dealloc method .
Good luck.

Setting a object with "Assign" property to nil

If I am having a variable defined with "Assign" property then is it ok to setting them to nil in dealloc method?
#property (nonatomic, assign) id test;
- (void)dealloc {
self.test = nil;
}
It's better to release the ivar directly. If a subclass overrides the setter methods of a property, your object might leak because your setter is not called. Consider:
#interface ClassA
#property (readwrite, retain) id anObject;
#end
#interface ClassB : ClassA
#end
#implementation ClassA
#synthesize anObject;
- (void)dealloc {
self.anObject = nil;
[super dealloc];
}
#end
#implementation ClassB
- (void)setAnObject: (id)anObject {
// do nothing!
}
#end
Instances of ClassB will leak anObject!
Depends how you do it, if you do it via the property setter (not recommended), then yes.
If you do direct assignment, then no, because the retained object will leak.
So this is fine:
- (void) dealloc {
self.test = nil;
[super dealloc];
}
But this is a no-go:
- (void) dealloc {
test = nil;
[super dealloc];
}
My advice is to just send the release message to all of your retained ivars in -dealloc, this will work nicely because if test happens to be nil, then nothing will happen.
Trust me. Send release directly in -dealloc. That is all.
- (void) dealloc {
[test release];
[super dealloc];
}

IS this class Many part of memory Leak

I am much confuse about my class.
Specially about Memory Management.
Please Guide me about NSString Concept at here.
My Class is.
#import <Foundation/Foundation.h>
#interface itinerary_detail : NSObject {
NSString *itinerary_title;
NSString *itinerary_creator;
NSString *itinerary_identifiere;
NSString *itinerary_created;
NSString *itinerary_modified;
}
#property (retain) NSString *itinerary_title;
#property (retain) NSString *itinerary_creator;
#property (retain) NSString *itinerary_identifiere;
#property (retain) NSString *itinerary_created;
#property (retain) NSString *itinerary_modified;
-(void) itinerary_initialization;
-(void) itinerary_title:(NSString *) xml_value;
-(void) itinerary_creator:(NSString *) xml_value;
-(void) itinerary_identifiere:(NSString *) xml_value;
-(void) itinerary_created:(NSString *) xml_value;
-(void) itinerary_modified:(NSString *) xml_value;
#end
and My .m class is
#import "itinerary_detail.h"
#implementation itinerary_detail
#synthesize itinerary_title,itinerary_creator,itinerary_identifiere,itinerary_created,itinerary_modified;
-(void) itinerary_initialization
{
itinerary_title=#"null";
itinerary_creator=#"null";
itinerary_identifiere=#"null";
itinerary_created=#"null";
itinerary_modified=#"null";
}
-(void) itinerary_title:(NSString *) xml_value
{
itinerary_title=xml_value;
}
-(void) itinerary_creator:(NSString *) xml_value
{
itinerary_creator=xml_value;
}
-(void) itinerary_identifiere:(NSString *) xml_value
{
itinerary_identifiere=xml_value;
}
-(void) itinerary_created:(NSString *) xml_value
{
itinerary_created=xml_value;
}
-(void) itinerary_modified:(NSString *) xml_value
{
itinerary_modified=xml_value;
}
-(void) dealloc
{
[itinerary_title release];
[itinerary_creator release];
[itinerary_identifiere release];
[itinerary_created release];
[itinerary_modified release];
[super dealloc];
}
#end
My question about.
1- Is this type Deceleration of NSString in this class of Memory Leak Issue. If Yes Please How i Will change this.
2- I am Using This class into Other class
Like that
itinerary_detail *check=[[itinerary_detail alloc] init];
[check itinerary_initialization];
[check release];
my question is this right way . or this is also a Memory Leak Issue.
Please Guide Me How to Deceleration Of this class and How to handle all memory Leak Issues.
Please Help Me
The problem come from the fact that you don't use the property but directly access the member variable. replace itinerary_title=xml_valueby self.itinerary_title=xml_value
btw, string properties are usually (copy) and not (retain) and why do you create all those methods while the synthesize will do it for you.
remove the methods from the .h file and from the .m file and set the property as
#property (copy) NSString* myString;
Your code shows that you need to get the basics of Cocoa and Objective-C right, before writing an actual program. Read Cocoa Fundamentals, OOP with Objective-C, etc. Resist the urge to start writing programs right now; the time you'll spend to learn the basics will greatly reduce your headache later.
Your code should look like:
#interface ItineraryDetail : NSObject {
NSString *itineraryTitle;
...
}
#property (retain) NSString *itineraryTitle;
#end
and
#implementation ItineraryDetail
#synthesize itineraryTitle, ... ;
-(id)init{
self=[super init];
if(self){
itineraryTitle=nil;
}
return self;
}
-(void) dealloc
{
[itineraryTitle release];
[super dealloc];
}
#end
and
ItineraryDetail *check=[[ItineraryDetail alloc] init];
... use it ...
[check release];
A few points:
In Objective-C, you don't usually name_like_this. You NameLikeThis. This is not an absolute rule, but it's customary, and you should follow it in general.
You don't write a method like ...Initialize separately. Rather, it's implemented using init, with [super init] inside it.
When you synthesize a property named foo via #synthesize foo, the setter setFoo: and the getter foo: are automatically generated, so you don't have to provide them manually. And you mistakenly used the name foo: for the setter! That will totally confuse the system.
The nil value for NSString (or any object in Objective-C in general) is not #"null" but just nil. And the ivars are set to nil automatically by the system, so you don't really do that in the initialization method.