I have two classes, a class that handles db connectivity and an entity class. The db class has an instance method called GetEntityByID:(int)entity_id. This method does a simple select statement, and creates an Entity class instance using an init method.
This works fine, however whoever calls GetEntityByID must remember to release it. Since GetEntityByID is not an "init" method, this doesn't seem right. How do I best handle memory management in this situation?
You can call autorelease in your GetEntityID method on the class to autorelease the instance if it is not otherwise retained.
Since the instantiation of the class is done within your DB connectivity class's method, the object that is returned the instance does not "own" it - your DB connectivity class. As of this, according to convention, you need to memory manage the instance:
You take ownership of an object if you create it using a method whose name begins with “alloc” or “new” or contains “copy” (for example, alloc, newObject, or mutableCopy), or if you send it a retain message. You are responsible for relinquishing ownership of objects you own using release or autorelease. Any other time you receive an object, you must not release it.
If the object sending the GetEntityID method wants to keep the object around, for example if it is to be used as an instance variable, then the returned object can be retained, preventing it from being deallocated at the end of the current event. If it is only being used locally, and doesn't need to be kept around after the current event, then the class doesn't have to do anything; it will be released by the autorelease pool at the end of the current event.
This article explains more about autorelease pools.
To autorelease the object returned in GetEntityID do something like this in GetEntityID:
... // cool stuff in GetEntityID
return [[entity_id retain] autorelease];
}
Have a look at this really nice article explaining Objective-C memory mangement in more detail.
Related
Without using ARC, for objects initialized using instance method we do release it via release call.
example:
Sample *obj = [[Sample alloc]init] ;
// some code here
[obj release] ;
Now for objects allocated using class methods should release be called?
example:
TestSample *testobj = [TestSample initCustom] ;
// some code here
should there be [testobj release]?
Let's consider this standard function provided by apple.
endpointWithHostname is a class method.
NWHostEndpoint *pNetHost = [NWHostEndpoint endpointWithHostname:#"0.0.0.0" port:#"21"];
so, should there be a [pNetHost release] for above call?
You said:
for objects initialized using instance method we do release it via release call
The fact that you called an instance method isn’t relevant. You own any object returned by any method whose name starts with alloc, new, copy, or mutableCopy. In your example, you called alloc, and therefore ownership has been transferred to you. That’s why you are now responsible for calling release.
However, if you called some instance method that didn’t start with one of those four prefixes, though, ownership would not be transferred to you, and you would not call release.
This is all summarized in the Advance Memory Management Programming Guide, which says:
Basic Memory Management Rules
The memory management model is based on object ownership. Any object may have one or more owners. As long as an object has at least one owner, it continues to exist. If an object has no owners, the runtime system destroys it automatically. To make sure it is clear when you own an object and when you do not, Cocoa sets the following policy:
You own any object you create
You create an object using a method whose name begins with “alloc”, “new”, “copy”, or “mutableCopy” (for example, alloc, newObject, or mutableCopy).
You can take ownership of an object using retain
A received object is normally guaranteed to remain valid within the method it was received in, and that method may also safely return the object to its invoker. You use retain in two situations: (1) In the implementation of an accessor method or an init method, to take ownership of an object you want to store as a property value; and (2) To prevent an object from being invalidated as a side-effect of some other operation (as explained in Avoid Causing Deallocation of Objects You’re Using).
When you no longer need it, you must relinquish ownership of an object you own
You relinquish ownership of an object by sending it a release message or an autorelease message. In Cocoa terminology, relinquishing ownership of an object is therefore typically referred to as “releasing” an object.
You must not relinquish ownership of an object you do not own
This is just corollary of the previous policy rules, stated explicitly.
You go on to ask:
let's consider this standard function provided by apple. endpointWithHostname is a class method.
NWHostEndpoint *pNetHost = [NWHostEndpoint endpointWithHostname:#"0.0.0.0" port:#"21"];
so should there be a [pNetHost release] ; for above call
The fact that it is a class method isn’t relevant. The key is that the method name doesn’t start with alloc, new, copy, or mutableCopy. That means that ownership has not been transferred to you and therefore you don’t need to call release. In this case, it is returning an autorelease object, so it will be released for you when the autoreleasepool is drained.
Obviously, if you want to claim ownership of the pNetHost object, you would do so by calling retain (and of course, at that point you’d then be responsible for eventually calling release to offset that retain).
Now, let’s consider your example:
TestSample *testobj = [TestSample initCustom];
// some code here
should there be [testobj release]?
No. But let’s answer this question by looking at the implementation of the method you called initCustom. It might be implemented like so:
+ (instancetype)testSample {
TestSample *obj = [[self alloc] init];
// perhaps more customization of `obj` here
return [obj autorelease];
}
But, there are two key observations in the above:
I didn’t start the method name with init. That prefix should only be used with initialization methods, which this method isn’t.
The convention is to start the method name with the name of the object type, using camelCase (i.e. starting with a lowercase letter). Hence, this TestSample class method name might be called testSample, like above, not initCustom.
Because the method name doesn’t start with alloc, new, copy, or mutableCopy, it should return an autorelease object. And because it is an autorelease object, the caller would therefore would not call release (unless, of course, it claimed ownership by calling retain).
By the way, the static analyzer (shift+command+B; or “Product” » “Analyze”) is exceptionally good at analyzing manual reference counting code.
For example, let’s imagine that I forgot to add the autorelease in the above testSample example. If I let Xcode analyze the code, the compiler would tell me about the problem:
If I add the autorelease back in and re-analyze, this warning will go away.
When writing manual reference counting code, the static analyzer is an invaluable tool. Always make sure you have a clean bill of health from the analyzer.
I have created an object using alloc/init method, and after I release it -dealloc should be called immediately as per documentation. I set a breakpoint on -dealloc method but it isn't hit, and my -dealloc method is not called.
Please tell me what is the reason behind that, and what is use of dealloc method in objective c ?
The -dealloc method is not always called when you expect it to be called. The runtime might also have issued a -retain on your object for internal reasons.
It's also possible that you have (directly or indirectly) caused an extra -retain to be issued. If the retains/allocs and releases are not balanced, you'll never see -dealloc called. It helps to turn on the Static Analyzer, to make sure your calls balance.
Just follow the memory management rules, don't second guess the runtime, and let the memory management system do its job.
The answers to When does dealloc method call? may help you understand what you're seeing.
because it still has reference. that means its reference count not reached to zero. i don't know your code, where it is referencing. but it is not calling that means somehow still it has reference. it may be because of strong relationship or parent-child relationship
all Objective-C objects are allocated on the heap, so they must
therefore be deallocated somewhere if you are not to run out of
resources.
This gave way to the reference counting method, which is still used
today: each object keeps count of any references held to it. If you
receive an object and you want to keep it, you retain that object,
incrementing its reference count. When you are done with it, you
release it, which decrements its reference count. Once that count
reaches zero, it is inferred that no one is referencing the object and
it is automatically deallocated using the -dealloc method.
Additionally, an object could be told to “release at some point in the
(hopefully) near future” using autorelease pools. The idea is that
somewhere on the stack (typically at the start of a thread or while
responding to input events) an autorelease pool is created and pushed
onto a stack. Any object can then be sent an -autorelease message, and
it is assigned to that pool.
When the pool object is deallocated, it simply sends a -release
message to all its assigned objects. That way, any objects that are no
longer used (i.e. they haven’t been explicitly retained) are then
deallocated.
The dealloc is called (at more cases) whenever your object is released. You can't directly call this method.
#interface myViewController:UIViewController
{
NSString *myStr;
}
#end
Here the dealloc method in the #implementation of myViewController will be called (at most cases) when the myViewController object is released, not when myStr is released.
Although you don't have to use if you ARC.
First off, I'm a Objective-C newbie. :)
I've learned that anything that starts with alloc, new, and copy, gives the caller ownership of the returned object. Does this also apply to class methods? I'm guessing it does, and a recent crash in one of my unit tests seems to confirm it. Apple's Advanced Memory Management Programming Guide doesn't say anything whether there's a difference between class and instance methods.
Update
What I mean that it also applies to class methods is really the "inverse". For instance, NSDecimalNumber has a class method called +decimalNumberWithDecimal:. It seems to return an auto released object (if I release it explicitly, a crash occurs shortly after that). In hindsight, the answer to my question is obvious, as Apple's guide refers to new and alloc as ownership-giving methods, and they're all class methods. Sorry for taking up your valuable time. :)
Also alloc and release. init does not indicate ownership, you are likely mixing that up with alloc. You can memorise it easily with the mnemonic NARC.
If you are naming any class methods init, copy or retain, you should stop that. Those are methods that only make sense in the context of instances. alloc and new are class methods and should only be used in that context. Don't name instance methods alloc or new.
The reason why the guide doesn't say that it applies to both instance methods and class methods is that the methods in question are clearly a mixture of both, so it's obviously the case.
Yes this applies to class methods since alloc and new are class methods which return ownership to the caller. The prefix of copy or mutableCopy should be used for instance methods returning ownership.
Edit For The Update:
You are correct a method like +decimalNumberWithDecimal: is expected to return an autoreleased object, therefore there is no reason to release it. If however they decided to name the method +newNumberWithDecimal: then you would have ownership of the returned object and need to release it. Clang static analyzer will actually complain if you prefix a method with new and return an autoreleased object.
Actually, this is almost correct. alloc, new, and copy give you ownership of the returned object. These are class methods. Other class methods should return an autoreleased object. Instance methods should also return an autoreleased object.
init does not effect ownership and should be use in conjunction with alloc as follows.
[[SomeCoolClass alloc] init]
new is usually the same thing as the above and is sometimes described as "almost deprecated" because it is a throwback to the NeXT days when the allocation and initialization were done in the same step and could not be plot apart as we do today with alloc and init.
Release does not effect ownership, but should only be used on object you already own. Otherwise a crash is likely to occur.
Retain also does not affect ownership, but should only be used on an object you already own. Otherwise the object may not be deallocated when it should be. The result could be a crash, but it can also be very very strange behavior that is difficult to troubleshoot because messages may be sent to the original object that was supposed to have been deallocated instead of a new object pointed to at the same address.
I am new to cocoa-touch, and really unmanaged languages all together. While I have a firm grasp of the syntax, I am questioning whether I am releasing an object correctly.
I have a view that creates an object,
Communication *comm = [[Communication alloc] init];
[comm doSomething];
[comm release];
I understand that I have to destroy this object because I am allocating it and it will not auto release.
I call a method on the object that goes out to my server and grabs information. When the data returns it throws an event which my "message dispatcher" responds to. I do not want to destroy the object until it returns back from the server -- and this is where my confusion is at.
If I release this object directly after I make the call, will it destroy the object? (Which I don't want to do.)
How do I properly destroy this object after it throws the event with the data I am waiting for? This would occur within a DataFinishedLoading event on my comm object. Should it destroy itself, and is this the right way to do it?
The view calling my object essentially says, create this object, call this method, and go about your merry way. It doesn't care about what happens after it calls the method -- whether it brings back information or not. It simply listens on a method for any data that may come across at a later time. I have no reason to hang onto a reference of the object, as I will never use the same instance after I make the call -- that is besides cleaning up after myself.
A release only destroys the object if the last retainer released it.
For example, say you allocate your Communication object. It is implicitly retained once. Then you retain it five times. You need to release/autorelease the object six times until it gets destroyed (its dealloc method is called).
There is an internal counter, the retainCount. When you create an object, it is set to 1. Now every retain increases the counter, and every release decreases it. autorelease also decreases the counter, but not immediately. Once the counter drops to 0 Objective-C knows that the object is no longer needed and destroys it (by calling the object's dealloc). Warning: do not rely on the retainCount, do not even look at it. You should only care that your alloc/copy/new/retain calls are balanced with a corresponding release/autorelease later on.
In your above example, comm will likely be destroyed when you call release. It depends on something else retains it during doSomething.
If you want to hold onto an object while it does something asynchronously, put it in a retained property. When it informs you that it is done, set the property to nil which will release it.
I am still new to this Memory Management stuff (Garbage Collector took care of everything in Java), but as far as I understand if you allocate memory for an object then you have to release that memory back to the computer as soon as you are finished with your object.
myObject = [Object alloc];
and
[myObject release];
Right now I just have 3 parts in my Objective-C .m file: #Interface, #Implementation and main. I released my object at the end of the program next to these guys:
[pool drain];
return 0;
But what if this program were to be a lot more complicated, would it be okay to release myObject at the end of the program?
I guess a better question would be when do I release an object's allocated memory? How do I know where to place [myObject release];?
This is probably a little over-simplified, but in general, you are going to want to release it where you declared it.
If you declare an object INSIDE a particular method call, then by definition, you will be done with that object (or at least that handle to that object) at the end of that method call... release it then.
If you declare an object as an instance variable, then by definition you will be done with it when that instance is destroyed... release it in the dealloc method of that class.
Keep in mind that "release" does not equal "destroy." When passing objects around in your application, it may make sense to have more than one handle to that object stored in different places... in that case "release" means "I'm done with this object, but someone else may still be using it." Deallocation only occurs when the number of "handles" (retain count) reaches zero.
Apple has some fantastic documentation on memory management, I would check it out at developer.apple.com.
You essentially have three kinds of objects, each with a different pattern.
Transients Objects
In general, you should autorelease transient objects. These are objects that are allocated locally and do not need to exist beyond the method in which they are called. Or they are passed around from method to method.
Chain of Ownership
When one object exists as an instance field inside another, you should release the "owned" (or "child") object when the "owner" (or "parent") object goes out of existence. This is done in the dealloc method of the parent object:
- (void) dealloc {
[child release]; // child was declared as an instance variable
[super dealloc];
}
Lifetime of the Program
When an object is intended to exist for the lifetime of the program, it usually isn't necessary to call release at all, unless some kind of resource cleanup needs to occur. You can put this in applicationWillTerminate:, which you can look up in Apple's documentation.
(You should probably avoid having such objects, but that is a discussion for another question.)
You have to think in terms of ownership. When you take ownership of an object by calling alloc, new or retain, you're also responsible for releasing it, either by calling autorelease when you return an owned object to the caller, or by calling release.
A general rule is:
Local variable: release it within the same method. When you want to return it to the caller, use autorelease
Class member: release it in the dealloc method