What's the equivalent of [[something retain] autorelease] in ARC?
I have a problem where a class DBRequest calls my delegate to signify completion. My delegate then sets the DBRequest instance to nil, which dealloc's it. But then when the stack pops out of my delegate and jumps back to the DBRequest, it of course then crashes.
If I wasn't in ARC, in my delegate I'd simply do [[theDbRequest retain] autorelease] before releasing my reference to it, so that it'd survive long enough until the next run loop autoreleased it.
What should I do in ARC?
How about adding something like
__strong DBRequest * myself = self;
[delegate reportDone];
I think that'll increment the self object until the end of the function preventing it from dying early.
My delegate then sets the DBRequest instance to nil, which dealloc's it. But then when the stack pops out of my delegate and jumps back to the DBRequest, it of course then crashes.
Surely this was always a bad strategy, and your [[theDbRequest retain] autorelease] was always just covering up the problem, yes?
Simply do nothing. So your instance variable sticks around; so what? You know that ARC will release it for you when you are dealloced.
The important thing is not to release theDbRequest, but to set theDbRequest's reference to you (the delegate) to nil, so it doesn't try to call you back when you no longer exist. Your own dealloc would be a good place to do that.
Hope I'm understanding the issue correctly. If not, post some code!
As #matt says if you simply do nothing ARC should clean up when your object is deallocated - assigning the DBRequest you create to an instance variable handles that (provided of course your object outlasts the object you are creating).
If you need to deallocate the DBRequest before your object dies then you need an ARC-compatible "trick" equivalent to [[theDbRequest retain] autorelease]. Now unless you are constructing your own auto release pools your previous approach would trigger at the end of the current event. Following that logic try:
Add a method to your class which simply sets theDbRequest to nil, let's call this cleanUpTheDbRequest.
Change your delegate callback to invoke [self performSelectorOnMainThread:#selector(cleanUpTheDbRequest) withObject:nil waitUntilDone:NO] instead of directly assigning nil to theDbRequest
This should delay the assigning of nil till after the end of the current event, just as your autorelease "trick" did. It also works if your DBRequest lives across multiple events - the previous method kicks in at the end of the event the autorelease is called in, this method at the end of the event the delegate method is called in.
Related
I need to download some images from server. So I created a seperate class to handle NSURLConnection delegates.
At the end of didFinishDownloadingData, I called a delegate method like [(id)delegate performSelectorselector(finished:) withObject:receivedData]
I have a view controller called ListImages.
I created the above connection class from ListImages class and assigned connection.delegate = self. After image loaded from server the method -(void)didFinishDownloadingData:(NSData *)data; was called successfully, and I could display that image.
My problem starts now. To handle some common tasks, I created a new class called SharedMethods which is a subclass of NSObject. I allocated connection class as
Connection *conn = [[Connection alloc]init];
conn.delegate = self;
[conn startDownload]; //called a method which starts nsurlconnection.
I am using ARC so not released that object. My applicaion got exception in method, (In Connection class)
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[(id)delegate performSelectorselector(finished:) withObject:receivedData]; //Got an exception in this line
}
The exception was [SharedMethods retain] message send to deallocated object. I dont think I have released anything because I am using ARC.
There was also a problem while callingUIAlerView delegates inside a Class which is a subclass of NSobject. It is not called any how. My doubt is, is there any problem with using a NSObject sublass? Is there anything to consider when using NSObject sublass ?
Thanks in advance.
Using ARC doesn't mean than objects never receive the release method, or that they never get deallocated. It just means that you don't have to make explicit calls to retain and release, and that happens automatically.
The problem here is that your objects are getting deallocated because no one is owning them. Your specific problem is that SharedMethods is being deallocated because it's not getting retained, but I can't show you how exactly that's happening because you didn't post the relevant code.
I can, however, show you that you're not managing your Connection properly, and hopefully that can help you figure out what you're doing wrong with SharedMethods.
So you create Connection with alloc init, which with retain-release code would give it a retain count of 1, but since you're not using ARC anymore that's not really relevant. Unless some other object asserts ownership of the Connection, ARC will automatically insert a call to release to bring the retain count back to 0 (it's kind of like if ARC automatically inserted an autorelease).
Since you don't assign Connection to a strong or retain property, or put it in a collection, no other object is asserting ownership to it. So once execution reaches the end of the scope where the variable conn is defined, it will get released and deallocated.
So in ARC, much like in manual retain-and-release code, you still need to make sure objects are owned by some other object in order for them to stick around. The only difference is that you don't need to manually call retain and release, you just have to think about the object ownership graph—which object is owned by which other object—and make sure that any object you want to stick around is owned by some other object.
So to reiterate, you need make sure that SharedMethods is owned by some other object.
With ARC sometimes I still need to write a -dealloc method to do some cleanup. In some rare cases I need to refer to properties of the instance to properly do cleanup. Such as unregistering from NSNotificationCenter with a given sender object, which is owned and referenced by a property.
Does ARC insert it's property release code at the end of after my own code, or does it insert this at the beginning of -dealloc, before my own code?
If ARC would be inserting code before any custom -dealloc code, then this would be very dangerous since you can't access properties anymore if needed.
This question is about where ARC inserts the property release code in a synthesized -dealloc, and not about wether or not to implement -dealloc.
I think, that everything is said here: http://clang.llvm.org/docs/AutomaticReferenceCounting.html#misc.special_methods.dealloc
7.1.2. dealloc
A program is ill-formed if it contains a message send or #selector expression for the selector dealloc.
Rationale: there are no legitimate reasons to call dealloc directly.
A class may provide a method definition for an instance method named dealloc. This method will be called after the final release of the object but before it is deallocated or any of its instance variables are destroyed. The superclass's implementation of dealloc will be called automatically when the method returns.
Rationale: even though ARC destroys instance variables automatically, there are still legitimate reasons to write a dealloc method, such as freeing non-retainable resources. Failing to call [super dealloc] in such a method is nearly always a bug. Sometimes, the object is simply trying to prevent itself from being destroyed, but dealloc is really far too late for the object to be raising such objections. Somewhat more legitimately, an object may have been pool-allocated and should not be deallocated with free; for now, this can only be supported with a dealloc implementation outside of ARC. Such an implementation must be very careful to do all the other work that NSObject's dealloc would, which is outside the scope of this document to describe.
ARC releases instance variables at the end of the dealloc chain. In other words, all the dealloc methods in the inheritance chain are run, and then any ARC-managed instance variables will be deallocated. You could think of it as happening in -[NSObject dealloc], though it's really even later than that.
So rest assured; ARC won't release your properties out from under you in your -dealloc method. ARC won't release them until you have no way to reference them anymore.
I am testing the following code below. ffv is declared in the interface file.
ffv = [[FullFunctionView alloc] initWithFrame:self.view.bounds];
NSLog(#"%i", [ffv retainCount]); // prints 1
[self.view insertSubview:ffv belowSubview:switchViewsBtn];
NSLog(#"%i", [ffv retainCount]); // prints 2
[ffv release]; // you can release it now since the view has ownership of ffv
NSLog(#"%i", [ffv retainCount]); // prints 1
if (ffv == nil)
NSLog(#"ffv is nil");
// "ffv is nil" is not printed
[ffv testMethod]; // "test method called" is printed
this is my [ffv testMethod] implementation
- (void)testMethod
{
NSLog(#"test method called");
}
What I deduce in this case is that even if you release an object with retain count 2, you lose ownership of that object however, the reference is still kept.
Now, my question are:
Is my deduction correct?
Is there anything else important that can be deduced from this?
What are the complications caused by still keeping (using) ffv and calling methods from ffv? (My opinion is that this is ok since the view will always own ffv and won't release it until someone calls viewDidUnload. And as long as I don't pass ffv's reference to other objects.)
There are a couple of problems with using ffv after you have released it and it's only retained by your view controller's view.
1) It introduces a potential for future bugs, because later you might not remember that ffv is otherwise not retained. When you release the view (e.g. by replacing it with another view), you have a dangling pointer that you still hold a reference to.
2) In the special case of a UIViewController the view could be released at any time (you usually never call viewDidUnload yourself). The default behavior of UIViewController, when receiving a memory warning and the view is currently not visible, is to release the view, so unless you set the reference to nil in viewDidUnload, you have a dangling pointer again, even though you never explicitly released the view yourself.
1) Is my deduction correct?
Your deduction is correct. The Memory Management Programming Guide explains that each object has one or many owners. You own any object you create using any method starting with alloc, new, copy, or mutableCopy. You can also take ownership of an object using retain. When you're done with an object, you must relinquish ownership using release or autorelease.
Releasing the object doesn't change the value of any variables that reference that object. Your variable contains the object's memory address until you reassign it, no matter what retain count the object has. Even if the object's retain count goes to zero, causing the object to get deallocated, your variable will still point at that same address. If you try to access the object after it's been deallocated, your app will normally crash with EXC_BAD_ACCESS. This is a common memory management bug.
2) Is there anything else important that can be deduced from this?
Nothing comes to mind.
3) What are the complications caused by still keeping (using) ffv and calling methods from ffv? (My opinion is that this is ok since the view will always own ffv and won't release it until someone calls viewDidUnload. And as long as I don't pass ffv's reference to other objects.)
When you call release, you are telling the Objective C runtime that you no longer require access to the object. While there may be many cases like this one in which you know the object will still exist, in practice you really shouldn't access an object after calling release. You'd just be tempting fate and setting yourself up for future bugs.
I personally don't like peppering my code with release statements, because I don't trust myself to remember them 100% of the time. Instead, I prefer to autorelease my variables as soon as I allocate them like this:
ffv = [[[FullFunctionView alloc] initWithFrame:self.view.bounds] autorelease];
This guarantees that ffv will exist at least until the end of the method. It will get released shortly thereafter, typically before the next iteration of the run loop. (In theory this could consume excessive memory if you're allocating a large number of temporary objects in a tight loop, but in practice I've never encountered this case. If I ever do, it will be easy to optimize.)
The object is not deallocated until the retain count goes to 0. As long as it's not deallocated, you can keep using it without trouble. By retaining it you ensure that it won't be deallocated under your feet; however, if you retain another object that you know retains the first object, you can get away with this form of "indirect retaining". Don't complain when you move things around later and things start breaking, though.
if (ffv == nil)
NSLog(#"ffv is nil");
// "ffv is nil" is not printed
That's correct, releasing an object does not set the pointer to nil even if it is dealloced at that time. Good practice is to always set your pointer to nil after you release it.
You are correct to say that after you released it, it wasn't dealloced because the view still had a retain on it. But that's not how you should be thinking about it. If you want to use that object and you want it to be alive, retain it. Doesn't matter who else is retaining it. Your object has nothing to do with those other objects. You want it, retain it. You're done with it, release it and set your pointers to nil. If you don't set it to nil and everyone else also released it, you will have a dangling pointer to an object that was dealloced, and that will cause you a crash and much grievance.
so this:
[ffv release]; // you can release it now since the view has ownership of ffv
ffv = nil; // you released it, so that means you don't want it anymore, so set the pointer to nil
if you still want to use it, don't release it until you're done with it.
Well, I'm not sure 'losing' ownership is the right term. In Objective-C you have to carefully marshal your ownership of the object. If you create or retain an object, you are responsible for releasing it (either directly or via an autorelease pool). When you call release however, you don't lose a reference to the object, if something else has retained it, it will still be in memory, and your pointer will still potentially point to it.
You have a pointer ffv which is just a pointer to some memory, and you have the object which is created in the first line that ffv points to.
By calling release, you are stating that you no longer require the ponter ffv to point to a valid object, that in this context you would be happy for the object to be deallocated. The pointer still points to that bit of memory, and it is still there because its retain count was increased by assigning it to the view.
The line [ffv testMethod] is in danger of not working, as it follows the release and may not point to a valid object. It only works because something else is keeping it alive. ffv still has the same address value that it had when it was first assigned.
So in order:
Your deduction is correct.
Not really.
You shouldn't use ffv after the release call. You have no guarantee that the object is going to be there for you.
These are pointers we are using here, not references like you find in Java or C#. You have to marshal your ownership of the object, you create it, have some pointers to it and by careful management of retain and release calls you keep it in memory for as long as you need it.
I am trying to make a program that dynamically creates a button using the command:
[UIButton buttonWithType:UIButtonTypeRoundedRect]
But when I use these commands the delete the button I create:
[currentButton removeFromSuperview];
[currentButton dealloc];
[currentButton release];
I receive an error. How would I go about removing and deallocating the memory from a uibutton?
I got this problem long time ago, please notice that
[UIButton buttonWithType:UIButtonTypeRoundedRect]
has autorelease inside, so in your initialisation you need to do retain, like this:
_mybutton = [[UIButton buttonWithType:UIButtonTypeRoundedRect] retain];
and later point, you can do:
[_mybutton release];
Hope helps
:)
In the Objective-C/Cocoa framework, you encounter two different ways to receive objects: ones which you have explicitly allocated memory for (via a constructor) and ones that you have received memory reference to (via a class method).
FooBar *fone = [[FooBar alloc] initWithText:#"Hello, World!"];
In this example, memory is explicitly being allocated for the object by your call, using the alloc method, and then it is being initialized with data using the initWithText method that would have a method header like this:
- (id)initWithText:(NSString *)text;
On the other hand, you also will encounter objects that are created by classes automatically for you. An example of this would be below:
FooBar *ftwo = [FooBar fooBarWithWelcomeText];
In this example, a FooBar object is being returned even though we are not calling alloc to allocate memory for it. There are many different reasons to implement the method like this, but its mainly done to abstract certain details from the code that is using the object. The above example would have a corresponding method header like this:
+ (FooBar *)fooBarWithWelcomeText;
Depending on which approach is used, it changes how you interact with the memory of the object. So for the first example, after allocating the memory for the object you receive it back with a retain count of 1. If you are done using the object, you need to explictly release it with
[fone release];
In the second example, you are receiving an autoreleased object, which will be deallocated once the autoreleasepool is drained. If you want to keep it, you must explicitly retain with:
[ftwo retain];
If you do not wish to retain it, you can just leave it as is and it will be deallocated automatically. You can tell a method uses autorelease by two characteristics: 1) you will not utilize alloc when you receive the object; and 2) there will be a "+" next to the method heading. This means that the method is declared as a class method (similar to Java static methods).
So to finally answer your specific situation, you only need to make sure that the retain count is lowered to 1 (The only object having a reference to it was the autorelease pool). In your example, it would be done like this:
UIButton *currentButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[someView addSubView:currentButton];
// some code later
[currentButton removeFromSuperview];
You do not need the release statements because you never explicitly retained it. When you added the UIButton to another view, it retained the object so it incremented the reference count to 2. By removing it from the view, it is lowered back down to 1 so that when the autorelease pool is flushed, your UIButton will be deallocated. Btw, never call the dealloc method directly. When the retain count of an object is decremented to 0, the dealloc method will automatically be called.
You can't not dealloced the UIButton which you get through buttonWithType from system,if you don't alloced any instance then you are not entitled to call release on that.
In your case, you can use removeFromSuperview but not either dealloc or release .
You can't call dealloc directly on object, this is invoked by the system when you say release on object.
EDITED:
you could create you button using initWithFrame function of UIView. But you will get only the button type UIButtonTypeCustom which is by default, and also can't not change the button type because it's readonly property. So you would get the rounded button by using your some images.
You're not supposed to call dealloc directly. Try removing the dealloc line and see how that works.
I have an instance of a UITableView, and a separate class that adheres to the delegate and datasource protocols. I'm doing this like so:
SubjectTableViewHandler *handler = [[[SubjectTableViewHandler alloc] init] retain];
tv.delegate = handler;
tv.dataSource = handler;
[handler autorelease];
I don't want to maintain the handler as an ivar, and if I take off the retain call at the end, when the autorelease happens, it is sent release, then added to the pool, which causes an EXC_BAD_ACCESS. So currently, the retain count is:
(1) At init: 1
(2) At retain: 2
(3) delegate/datasource properties are 'assign', still 2
(4) At autorelease: 1, now in autorelease pool.
But then since the properties are 'assign', they will never be released, the retain count will never hit 0, and the handler will never be deallocated anyway. Is there any more efficient way to accomplish this than maintaining the handler as an ivar and releasing it in the dealloc method?
When you initialize the object using init, you are claiming ownership of it and there is no reason to call retain. You also don't want to call autorelease since that will cause the object to be released at the of the run loop.
Since you need to keep the handler (so that your tableView can call the delegate/dataSource methods) and a reference to the handler after the method returns (so you can release it when you are done showing the tableView), the cleanest approach would be to make it an ivar.
The only solution that I can see is, as you mentioned, to make it an ivar and store, allocate, and deallocate it in parallel with the table.
It all depends on your use of table view.
Common practice is you create a view controller which is a delegate to table and table may be a controller's member.
As another alternative you can inherit from UITableView and make it delegate of itself.
Sometimes it's better to use a singleton delegate.
Also, in table delegate methods first argument is tableview, so one delegate object can service multiple tables.