Calling autorelease in a block - objective-c

There’s a memory management issue with the following code:
dispatch_after(someTime, dispatch_get_main_queue(), ^(void){
[objectA doSomething];
[self doSomethingDifferent];
});
//self’s dealloc:
- (void)dealloc
{
_objectA.delgate = nil; //objectA’s delegate is this object;
[super dealloc]
}
“self” has a reference to objectA but is not retaining objectA. In self’s dealloc it touches objectA. This is a problem if objectA has already been dealloced. I know that by referencing these objects in the block, they will be retained, but I’m not sure there’s anyway to determine in what order they will be released.
One thing that seems to work is this:
dispatch_after(someTime, dispatch_get_main_queue(), ^(void){
[[objectA retain] autorelease];
[objectA doSomething];
[self doSomethingDifferent];
});
It seems that the autorelease pool is then drained after the block releases the objects but I’m not sure that that’s a guarantee so I don’t know if this code is valid.

The class in which that -dealloc method is implemented should hold a zeroing weak reference to _objectA. In that case, you don't have to worry about it. If the object referenced by _objectA was deallocated first, then _objectA will be nil when you access it, which is safe.

Related

dispatch_async and retain (non-ARC)

In a non-ARC app, I have an NSOperation subclass which is enqueued by a delegate and looks like:
// note that the delegate and element properties are retained
-(id)initWithDelegate:(id<SomeDelegate>)inDelegate element:(SomeElement *)inElement
{
if (self = [super init])
{
[self setDelegate:inDelegate];
[self setElement:inElement];
}
}
-(void)dealloc
{
[_delegate release];
[_element release];
[super dealloc];
}
-(void)main
{
// do stuff
dispatch_async(dispatch_get_main_queue(), ^{
[[self delegate] doSomething:[self element]];
});
}
Since [[self delegate] doSomething:[self element]] will be called after my NSOperation object has likely been deallocated, do I need to make sure to retain "element" in the delegate before adding this operation to the queue? The element object is retained elsewhere in the app but it could potentially be released there. I need to make sure that when my delegate receives it back from the NSOperation, that it is still a valid object.
Just wondering if the act of invoking it in dispatch_async will retain the arguments passed to it. I could of course use an NSInvocation and performSelectorOnMainThread which would retain it.
The queue will retain the Block when it's enqueued, and the Block will retain objects that it captures, such as self. Since self here has a strong reference to its element, the element will be valid at least until after the Block runs.
Note that it's unusual for an object to have a strong reference to its delegate: make sure you don't have an unbroken retain cycle there.

objective-c broken pointer with callback woes

I'm having trouble with a broken pointer that's pointing to garbage after an object has been released. objectA is the delegate for a callback from another object, objectB.
objectA is being allocated and released quite often (in my application its a menu UI object). Every time objectA is being initialised it initialises objectB and begins an asynchronous operation and then calls back to objectA via the id delegate property.
How can I stop my pointer: id delegate from breaking ?
ObjA.m
-(void)dealloc{
[super dealloc];
}
+(id)init{
ObjA *objectA = [[ObjA alloc]init];
return objectA;
}
-(id)init{
if (self == [super init]){
ObjB *objectB = [ObjB initialiseWithDelegate:self];
}
return self;
}
-(void)callback:(id)arg{
//This callback is called from an asynchronous routine from objectB
}
-(void)terminate{
//This is called when I want to remove/release objectA
//Other logical termination code here
[self release];
}
ObjB.m
#synthesize delegate;
+(id)initialiseWithDelegate:(id)delegate{
ObjB *objectB = [[ObjB alloc]init];
[objectB setDelegate:delegate];
return objectB;
}
-(id)init{
if (self == [super init]){
[self beginAsynchronousOperation];
}
return self;
}
-(void)beginAsynchronousOperation{
//Do asynchronous stuff here
}
-(void)finishedAsynchronousOperation{
//Called when asynch operation is complete
if (self.delegate) [self.delegate callback:someargument]; //EXC error. Pointer broke
}
The short answer here is that you nil out objectB's delegate property when you dealloc objectA. Because delegates are assigned, and not retained (explicitly to prevent retain cycles), as you have seen, the delegate reference can be left hanging when the "owning" object goes away. Typically objectA will be holding a retained reference to objectB, and during objectA's dealloc, it will first set objectB's delegate to nil, and then release objectB. This will prevent the crash. Of course this assumes (as is typical) that you don't need to do anything with that async completion. It also assumes that objectB can safely be released by objectA when it is in the middle of an async operation. This is usually true of (say) animations, but if you're building your own tasks, you might need to be careful of the lifetimes here.
Some notes on this code snippet that might be helpful:
Your objectA isn't actually holding a reference to objectB once it's created. This means you can't nil out the delegate. You should keep the reference to objectB when it's created so you can do this.
You are leaking objectB. ObjectA creates it (alloc, init), but then drops the reference, so even when it's done, no one seems to be responsible for releasing it. Again, holding it so you can release it will fix this too.
Your -terminate on objectA is an anti-pattern-- an object should never (with only one exception: a failure inside init) be calling -release on self. An object should be released by its owner, which is whoever originally created it.
Your pattern of if (self == [super init]) is normally written with one equals sign, meaning that you're both assigning self to the result as well as checking it for nil. This is a Cocoa historical oddity, and probably makes no difference here, but worth pointing out.

Object release in Objective-C: Why release an object twice in viewDidUnload and dealloc method?

I have a question about object release in objective-c. I saw some sample codes in Chapter 9 of "Beginning iphone 4 Development"(Page 287). The sample code release an object twice: both in viewDidUnload and dealloc method. Here are the sample codes:
- (void)viewDidUnload {
self.list = nil;
[childController release], childController = nil;}
- (void)dealloc {
[list release];
[childController release];
[super dealloc];}
childController is declared as an instance of UIViewController subclass. Why is it released in both viewDidUnload and dealloc method? Since childController is already released in viewDidUnload, is it necessary to release it again in dealloc method? Based my understanding I will write the code like:
- (void)viewDidUnload {
self.list = nil;
childController = nil;}
- (void)dealloc {
[list release];
[childController release];
[super dealloc];}
Thanks,
Sam
The problem is viewDidUnload is not guaranteed to be called every time like dealloc method. (check this question).
The reason to release objects in viewDidUnload is to avoid memory leaks. Since viewDidUnload is called when there's a low memory warning, you do want to clean up to avoid troubles in that case.
And also calling release on nil will not cause any problem, so it is safe to call release on retained objects in your dealloc method assuming the pointers are set to nil after been released elsewhere (like in viewDidUnload in your example).
In order to optimize available memory, is a good practice to implement lazy getters (actually lazy initializers) in UIViewControllers and release easily reallocable objects in viewDidUnload.
A (simplified) lazy getter is something like:
- (UIView *)footerView {
if (_footerView) {
return _footerView;
}
UIView *view = [[UIView alloc] initWithFrame:A_FRAME];
return (_footerView = view);
}
so, in the viewDidUnload I will release _footerView, because I can retrieve it later without effort. The release of _footerView in dealloc method, is not an error, because:
1) in objective c is ok to send messages to nil objects, 2) dealloc won't be executed at the same time as viewDidUnload but later
I've investigated a little bit because I was not sure. And all you need to know is here: When should I release objects in -(void)viewDidUnload rather than in -dealloc?
Basically, in viewDidUnload you release objects that you've created in the beginning of view's life cycle (loadView, viewDid load and so on). So if your viewController receives memory warning it will unload a view and reload it again and then your objects will be released in viewDidUnload and initialized again in loadView/viewDidLoad/ect

Calling dealloc in init?

I am writing a framework and I have an object with a custom init method:
#implementation OSDatabase
#synthesize database;
// MEM
- (void)dealloc {
sqlite3_close(database);
[super dealloc];
}
// INIT
- (id)initWithDatabasePath:(NSString *)path error:(NSError **)error {
if (self = [super init]) {
if (!sqlite3_open_v2([path UTF8String], &database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL)) {
error = [NSError errorWithDomain:#"OSDatabaseErrorDomain" code:1 userInfo:nil];
[self dealloc];
return nil;
}
}
return self;
}
#end
Is it safe to call dealloc inside of an init method if an error occoured? I'm not sure about this and memory management is one of the most important things in my life.
Thanks.
Is it safe to call dealloc inside of an init method if an error occoured?
No. send -release like you would everywhere else. Even in -init you can't guarantee that the current retain count is 1.
Why must you never ever send -dealloc except [super dealloc] in -dealloc? The reason is that you cannot ever guarantee that something else also has a reference to your object, even in your object's -init because the [super init] might choose to retain the object.
If the object returned by [super init] has a retain count of 1, sending -release will have the same effect as sending -dealloc. If it has a retain count of more than 1, something else thinks it owns the object and deallocing it would leave it with an invalid pointer, so -release is still the right thing to do.
Also, this:
while([self retainCount] != 0){[self release];}
would result in an infinite loop and is a terrible idea for a number of reasons. The retain counts of objects never go down to 0. -release looks something like this:
- (id)release
{
if (retainCount == 1)
{
[self dealloc];
}
else
{
retainCount--;
}
}
so the loop will decrement the retain count to 1 and then continually call dealloc forever or until the heap corruption it has caused leads to a seg fault.
Apart from never reaching zero, the retain may be UINT_MAX (for example in string or numeric literals) which colloquially means "this object must never be deallocated". If the retain count is UINT_MAX, -release won't decrement it.
Per docs you should never call dealloc directly - only [super dealloc] method in your custom dealloc.
I think calling release instead should do what expected (at least if you use init method only in standard alloc-init pattern).
As Vladimir stated you should never call dealloc directly. when retain count of an object reaches 0, Cocoa automatically calls dealloc.

What is dealloc in objective C

I want to ask an general question about the objective C. When I write the program of the iPhone application, I always see a function called 'dealloc' in the .m. when will this method be called? do I need to put all the [release] in here good for the application? thank you very much.
// ------------------ updated content -------------------------
NSArray *arr;
NSString *str;
NSMutableArray *mutableArr;
// in the dealloc
// it should have to following
[arr release];
[str release];
[mutableArr release];
the function will be call 3 times?
The dealloc method is called on an object when it's retain count has reached zero. Retain counts are increased by one for each retain call, and reduced once for each release call. The autorelease schedules a future release call when the current NSAutoreleasePool is drained, typically at the end of an event cycle, but you can set up your own NSAutoreleasePools on memory intensive operations. (See the NSAutoreleasePool docs for details.)
What should you put into dealloc? You should put a release for each member object the object of that class retains.
A couple things make this easier. The nil object will quietly ignore any messages sent to it, so [foo release] when foo = nil is not a bug. However, releasing an object twice can cause serious issues. My (hardly unique) solution to this is to explicitly set whatever I just released to nil, whenever I release it. In fact, I put the nil assignment on the same line as the release so I can grep for "release" and find places I missed. Example:
#interface MyClass {
Foo *foo;
Bar *bar;
NSInteger baz;
}
-(void)dealloc;
#end
#implementation MyClass
-(void)dealloc {
[foo release]; foo = nil;
[bar release]; bar = nil;
[super dealloc];
}
#end
I'll assign nil to a variable even when that variable is about to go out of scope or the object is about to go away. Why? If another object of the same class is allocated in the same memory space after I've released this one, it guarantees there will be no dangling pointers the new object might accidentally use and make debugging a nightmare. (See also NSZombieEnabled for debugging help.)
when will this method be called?
It's called when the reference count for that object becomes 0 because all its pointers have been released. The memory taken up by it is deallocated (freed); the object itself is destroyed.
do I need to put all the [release] in here good for the application?
Yes, release all the properties of the object that are still retained.
EDIT: in response to your updated question, dealloc in your custom object is only called once. It will then send these three messages:
[arr release];
[str release];
[mutableArr release];
To each of the three objects. They are entirely different objects, but if you only have one instance of each, then their reference counts all go down to 0 and their dealloc methods are called automatically.
As you surmised, it's called when an object is destroyed. The object should release everything it owns.
In Other words, Dealloc frees/destroys/releases the memory you allocated to your objects.
Allocated objects to memory should be destroyed once not used to avoid memory leaks that might cause your application to crash.
ZaldzBugz