We know about the complete pattern of alloc/init that alloc and init must be combined.
NSObject *myObj = [[NSObject alloc] init];
1- init method receives the object from another source(not from a alloc,new,copy or alike or retained) so according to the fundamental memory management rule its not the owner and it must not release it. However, "Allocating and Initializing Objects / The Returned Object" article says that init could free the receiver.
How could this be possible when its against the fundamental rule?
2- Also, from the same article, init could return another object or nil. So, in this case, when we use the complete pattern of alloc/init, we could not release the object returned by alloc but we could only release the object returned from init and, init releases the object it received from alloc instead of us.
But init is not a alloc,new,copy or alike method so we must not release the object returned from it as it does not give us the ownership of object.
How could we release the object returned from init although this is against the fundamental rule?
3- Or, to adhere to the last paragraph of the same article, must we accept init method as a special case and use alloc/init pattern as an exception to the fundamental rule?
Memory Management Fundamental Rule:
You only release or autorelease objects you own.
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 use release or autorelease to relinquish ownership of an object. autorelease just means “send a release message in the future” (to understand when this will be, see “Autorelease Pools”).
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html
Allocating and Initializing Objects / The Returned Object:
However, in some cases, this responsibility can mean returning a different object than the receiver. For example, if a class keeps a list of named objects, it might provide an initWithName: method to initialize new instances. If there can be no more than one object per name, initWithName: might refuse to assign the same name to two objects. When asked to assign a new instance a name that’s already being used by another object, it might free the newly allocated instance and return the other object—thus ensuring the uniqueness of the name while at the same time providing what was asked for, an instance with the requested name.
In a few cases, it might be impossible for an init... method to do what it’s asked to do. For example, an initFromFile: method might get the data it needs from a file passed as an argument. If the file name it’s passed doesn’t correspond to an actual file, it won’t be able to complete the initialization. In such a case, the init... method could free the receiver and return nil, indicating that the requested object can’t be created.
Because an init... method might return an object other than the newly allocated receiver, or even return nil, it’s important that programs use the value returned by the initialization method, not just that returned by alloc or allocWithZone:. The following code is very dangerous, since it ignores the return of init.
id anObject = [SomeClass alloc];
[anObject init];
[anObject someOtherMessage];
Instead, to safely initialize an object, you should combine allocation and initialization messages in one line of code.
id anObject = [[SomeClass alloc] init];
[anObject someOtherMessage];
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocAllocInit.html
The init method doesn't receive the object; the object receives the init message. The object does not possess itself; rather, it always knows about itself (through the implicit self argument in every message).
You're right that the object does not own itself, though. If alloc and init were fused in a single new method, that method would be its own (super) caller, so it would own the object (until it returns) and so be unquestionably right in releasing it. Since they are separate, and init is not the caller of alloc, you're right that it does not own the object, so you are right to question this practice.
This is one of the few cases where it's OK for one object to release an object (in this case, itself) on behalf of another. The alternative is not to release it, which, if you're going to either return nil or throw an exception, will be a leak.
In general, anytime you have an object retain or release itself, you should feel dirty. In this specific case, it's OK, because you are preventing a bug (a leak) rather than probably creating one.
2- Also, from the same article, init could return another object or nil. So, in this case, when we use the complete pattern of alloc/init, we could not release the object returned by alloc but we could only release the object returned from init and, init releases the object it received from alloc instead of us.
But init is not a alloc,new,copy or alike method so we must not release the object returned from it as it does not give us the ownership of object.
As init releases the old object on behalf of its caller, if it creates a new object, it does that on behalf of its caller. The caller does own the substitute object that init creates or retrieves for it.
As a corollary to this, if init retrieves a previously existing object, it must retain that, so that the caller will own it.
Again examining the hypothetical* new method, it would also need to both release the old object and create (owningly) or retain the substitute.
In all of these cases, it's init acting on behalf of its caller. It's normally dodgy for one method to do another's memory management, but for these cases, init doing it on behalf of its caller is necessary.
*The new method does exist, but simply sends alloc and init, so there's no need to implement it separately.
If initialization fails for some reason and must return null, then you must release the object in order to avoid leaking memory.
Similarly, init may decide to swap in a different object and return it - in that case you must also release the object in order to avoid leaking memory.
In both cases it's necessary because the original object isn't being returned by init, and will be orphaned after the method returns. Alloc has automatically retained the object, so if you don't release it its retain count will be stuck at 1 forever.
[Would another perspective help?]
The init method (and its siblings initWith... and similar) is a bit of an odd case but is not a special case of memory allocation rules. Init is odd because it has a name that sounds like it is going to change the internals of the instance but in fact it may do more than that (it may substitute some other object and initialize that object, for example). The tip-off is in the declaration of init:
- (id) init // the way it is
vs
- (void) init // in some other universe
The init method returns an object, so it might have been better named something like 'return an object that is (class-wise) an equivalent object and that has been initialized'. Most methods do not perform this kind of switcheroo, which makes init a bit different/odd.
There is nothing 'magic' about the alloc / init nesting -- it's just the simplest way to handle the fact that the object that you get back from alloc may not be the same object you get back from init. This works perfectly fine:
NSSomeClass* s = [NSSomeClass alloc];
s = [s init]; // that 's =' part is really important ;-)
and is exactly equivalent to the 'standard' idiom:
NSSomeClass* s = [[NSSomeClass alloc] init];
This is potentially problematic:
NSSomeClass* s = [NSSomeClass alloc]
[s init]; // bad! you ignored the result of init
The implementation of an init method must be done particularly carefully when the implementation returns a different object than the one it receives as the incoming 'self'. In such a case the init method takes on the responsibility of memory management of the 'self' object (because it's not going to return that object - so who else could be expected to do the management?)
It's possible to do some pretty ugly trickery, BTW. Don't try this at home!
// don't do this!
S* s = [S alloc]
[s retain]; // needs to survive 2 init's
S* ss = [s init......]; // s.retain goes 2-->1
S* sss = [s init.....]; // ... goes 1-->0;
Doing this is extremely poor practice because it depends on the init..... method always returning a new object (instead of the one it receives). That's an obviously bad assumption!
NOTE that by "a method receiving an object in 'self'" I mean that the method was invoked upon/by an object, and that object is made available by convention through the 'self' pointer.
The fundamental rule just doesn't apply in this special situation.
In fact, don't worry about it - unless you plan to do Posing, you won't need to write code that does this, and it will have no impact at all on the code you write.
You should continue to follow the fundamental rule in all your code.
And thirdly, the code is more what you'd call "guidelines" than actual rules.
(Captain Barbosa)
alloc/init is a bit of a special case. You have to do the retain/release stuff inside init in such a way that whatever object the caller gets back is owned by the caller and there are no leaks.
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 can't seem to find the answer anywhere. I'm using Manual Memory Management in Objective-C developing for iOS.
I wrote a convenience function for getting UIColor from a hex string. In it, it returns
[[UIColor alloc] initWithRed:... alpha:alpha]
Apparently on certain platforms (we have a few devices, ranging iOS 8-9) the object would be destroyed on exiting the function, so that its returned UIColor* cannot be used. So now, we changed it to
[[[UIColor alloc] initWithRed:... alpha:alpha] retain]
My question is when I'm done using this object, do I have to release it twice? Once for the alloc, once for the retain? It seems very strange to me, and I can't find this online anywhere.
If I don't retain, it gets dealloc'd on exiting the function (on some platforms) making the function useless. If I do retain, I need to release twice when done?
EDIT:
https://developer.apple.com/library/ios/documentation/General/Conceptual/DevPedia-CocoaCore/MemoryManagement.html
"..., it is normally guaranteed to remain valid within the method or function it was received in. If you want it to remain valid beyond that scope, you should retain or copy it. "
So I'm not doing anything out of the ordinary. The docs say I "should retain it" if "I want it to remain valid beyond" the scope of a function. I will try what #FreeNickname suggested. That makes the most sense.
You said:
I wrote a convenience function for getting UIColor from a hex string. In it, it returns
[[UIColor alloc] initWithRed:... alpha:alpha]
According to the Basic Memory Management Rules, the proper memory management is dictated by the name of your method:
if your method name does not start with “alloc”, “new”, “copy”, or “mutableCopy”, then you should return an autorelease object:
- (UIColor *)colorWithHexString:(NSString *)hexString {
...
return [[[UIColor alloc] initWithRed:... alpha:alpha] autorelease];
}
if your method name does start with “alloc”, “new”, “copy”, or “mutableCopy”, then you can return an object like you have above:
- (UIColor *)newColorWithHexString:(NSString *)hexString {
...
return [[UIColor alloc] initWithRed:... alpha:alpha];
}
Note, this pattern is less common than the above convention of colorWithHexString.
(Note, this memory management dictated by the method name prefix was historically merely best practice, but now, for interoperability with ARC code, it's critical. Always follow the above rules in manual reference counting code.)
Now, if the code that is calling your convenience initializer is allowing the object to be deallocated, the problem rests with that code, not your convenience initializer. Do not start adding extra retain statements to your initializer because something that calls it doesn't manage its memory properly.
Instead, make sure that the calling code does the proper retain (and eventual release) of the result of colorWithHexString, itself.
By the way, Xcode's static analyzer (shift+command+B) is remarkably good at analyzing manual reference counting code and identifying the issues.
In an edit to your question, you quoted the documentation:
If you receive an object from elsewhere in your program, it is normally guaranteed to remain valid within the method or function it was received in. If you want it to remain valid beyond that scope, you should retain or copy it. If you try to release an object that has already been deallocated, your program crashes.
This is not saying that your convenience initializer should issue a retain or copy. It is saying that the code that calls colorWithHexString is responsible for establishing its own claim of ownership of the UIColor object that was returned via retain or copy, as discussed above.
I think you are looking for the concept of autorelease which is used in situations like yours. It is essentially a way to send a deferred release message to the newly created object so the caller has the chance to retain it if necessary, otherwise it is destroyed when the autoreleasepool is processed.
You "misunderstood" Apple's documentation, because it is simply wrong for this topic. You really should read clang's documentation about ARC instead of Apple's, because clang's ARC documentation explains MRC correctly to interact with it.
Let's have a closer look on it:
You own any object you create by allocating memory for it or copying it.
Related methods: alloc, allocWithZone:, copy, copyWithZone:, mutableCopy, mutableCopyWithZone:
…
Conversely, if you are not the creator of an object and have not expressed an ownership interest, you must not release it.
…
If you receive an object from elsewhere in your program, it is normally guaranteed to remain valid within the method or function it was received in.
Taking this documentation for serious, you are not an owner of the object:
[[UIColor alloc] initWithRed:... alpha:alpha]
This is, because you do not receive the object reference from +alloc et al., but from -init…. Following Apple's documentation you are not an owner and have to retain it. (So it is "elsewhere".)
In clang's documentation it is described differently and correctly:
Methods in the init family implicitly consume their self parameter and return a retained object. (5.2.1)
Therefore there is a special method family for -init… along with the others mentioned in Apple's documentation as correctly described in clang's documentation:
The families and their added restrictions are:
alloc methods must return a retainable object pointer type. [Apple: alloc, allocWithZone:)
copy methods must return a retainable object pointer type. [Apple: copy, copyWithZone:)
mutableCopy methods must return a retainable object pointer type.(Apple: mutableCopy, mutableCopyWithZone:)
new methods must return a retainable object pointer type. (Apple: Ooops, I forgot something)
init methods must be instance methods and must return an Objective-C pointer type. … (Apple: Oooops, I forgot something)
(5.)
So, what you get from -init is already retained, you have the ownership and there is definitely no reason to retain it.
According to Rob's answer there might be a reason to autorelease it.
I understand the whole business around reference counting and "owning an object" and that if you allocate an object in Objective-c, it's your responsibility to release it
However when exactly would you need to call alloc on a newly created object? Would it only be to retain the reference after the end of the scope or is there some other reason
You need to call alloc in order to allocate the memory for the object.
The typical setup of an object is something like:
Object *obj = [[Object alloc] init];
The alloc call allocates memory for the object, and the init call initialises it (gives it sensible default values for all attributes/properties).
Some object types come with factory methods, eg
NSArray *arr = [NSArray array];
In this case, the object is initialised and allocated by the single array call.
None of this has anything (directly) to do with reference counting, except that different ownership rules normally apply to the two methods.
I think you are misunderstanding a basic concept. sending alloc to a class will result in creating a new object of that class (not initialized yet) which you own (retain count will be 1).
from your question "when exactly would you need to call alloc on a newly created object?" -
if the object is newly created it means that someone already allocated it..
if you meant: when do you need to call retain on a newly created object? the answer is if you want to hold it yourself and not rely on whomever allocated it, and might release it sometime.. remember that alloc/new syntax raises the retain count by one, where as other creating methods (like [NSArray array]) return autorelease objects..
in general i would recommend using ARC and not be bothered by these issues..
I'm not exactly a objective-c guy, but I don't think you call alloc on any object, you call it on a class to allocate the object and call init on the newly allocated object.
You may want to retain to retain the reference after the release is performed by autorelease pool, if this is your setup. That often happens to the object created using [NSThing thingWithStuff:stuff] or some such.
As i was reading through the book on Objective-C, i came across an example that initialized a class as follows:
ClassName *p = [[ClassName alloc] init];
While it makes sense that first we need to allocate memory to store data ClassName has before initializing, the following works just as well:
ClassName *p = [ClassName alloc];
Is init always needed?
In theory, it's not technically required. That's because NSObject's init method is effectively just return self;. However, in practice, it's absolutely essential. Objects perform internal setup inside the init method - creating internal state, allocating private members, and generally getting ready for action. The init method may not even return the same object as you allocated.
Think of it in two phases: alloc allocates memory, but that's it - it's analogous to Java's new. init configures the state of the memory so that the object can perform it's tasks - analogous to Java calling the constructor. Don't leave it out!
Good question. And you're right. Strictly speacking "init" is not required.
"alloc" does three important things to create an object:
- allocate enough memory to hold all instance variables
- initialize the "isa" instance variable
- all other instances are set to 0
Consider that the "root" Cocoa object, NSObject, simply returns "self" in its init method.
But, if you want to be a good Obj-C citizen, you must use "init". It is part of the "contract" between you, the developer, and the environment.
You should always call one of the initializer methods especially when the class isn't your own. The pointer returned from init isn't necessarily the same as returned by alloc.
Read the documentation:
http://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/Reference/Reference.html#//apple_ref/doc/uid/20000050-init
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