Ambiguous scenario for iPhone memory management - ios

I have some difficulties to understand this scenario.
I create an object
I set its retained property to something
I forget to release its property
I release the object
As I didn't release the property in the dealloc method, will the scenario result in a memory leak or will the property be released automatically?

The way Cocoa works is that memory management always looks locally balanced, within any one method*. This is kind of the point. You should be able to tell whether you have a leak or error in a method just by looking at that one method. No global program knowledge required.
It is your responsibility to release an object if you received the object from a -copy, -alloc, -retain, or -new method.
If you do this:
[obj setProp:foo];
is it your responsibility to release foo? No - see rules. If obj retains it (and you're saying you happen to know that it does), then it is the responsibility of obj to release it, in its dealloc method if not sooner.
So if you did this, it's balanced, no matter what kind of property -prop is.
id obj = [[MyObject alloc] init];
[obj setProp:foo];
[obj release];
*except for within the implementations of init, copy, dealloc, and accessor methods.

Yes, it's leak.
Retain, alloc will increase the counter by one.
Release will decrease the counter.
It will free the memory when the counter reaches zero.
Think of setter as this:
[newvalue retain];
[property release];
property = newvalue;
So..
create an object => 0+1=1
assign it to some object as a retain property => 1+1=2
release the object => 2-1=1
You will have to release that object again sometime.
And, trust me autorelease doesn't work quite well in the iphone environment.

Related

Can an object be deallocated during method execution?

Let's assume that we create an instance of class var foo: Foo? = Foo() on the main thread and we call some time consuming instance method bar of Foo on another thread, after a short time we set foo to nil on main thread. What happens with the execution of bar, in my understanding bar should still continue its execution since invoking instance method implicitly passes self as the first argument, so even those the last explicit ref to foo was broken we still have a ref inside of a method and it should be good. But then I found this stackoverflow post which completely breaks my understanding. So, can somebody confirm/deny the fact that object cannot be deallocated during its method execution
Short answer is that your belief is correct, and you're looking at a question that's not relevant to Swift.
Your link is to non-ARC Objective-C. Swift always uses ARC, and ARC is very conservative about retains. Consider the following Objective-C call:
[target runMethod: parameter];
Under ARC, this is (conceptually) transformed into:
[target retain];
[parameter retain];
[target runMethod: parameter];
[parameter release];
[target release];
retain and release are atomic, thread-safe calls.
A similar behavior exists in Swift. Because of this, as a general rule (in the absence of Unsafe), a variable cannot "disappear" while you'll holding onto it.
This is the implementation detail. The better way to think about it is that by default variables and parameters are strong, and an object cannot be destroyed while there is a strong reference. This matches your understanding.
Prior to ARC, though, you needed to insert extra retains and releases yourself to protect against this kind of situation, and it was very common not to. (Prior to 10.6, most ObjC was single-threaded.)
Even without threads, there are ways this can go astray without ARC. Since callers often didn't immediately retain returned values if they only needed them temporarily, it was possible to get dangling pointers even without multiple threads. For example, with a trivial accessor with no memory management, this can crash:
NSString *name = [person name];
[person release];
[self doSomethingWithName: name];
This is why you often see old ObjC getters written in the form:
- (NSString*) title {
return [[title retain] autorelease];
}
This made sure that the returned value would survive until the end of the event loop even if self released it or self was deallocated.
Swift does similar things via ARC, but as the name suggests, it's all automatic.

Why __weak variable not registered in autorelease pool?

id obj = [[NSObject alloc] init];
#autoreleasepool{
id __weak weakObj = obj;
_objc_autoreleasePoolPrint();
NSLog(#"%#",[weakObj class]);
_objc_autoreleasePoolPrint();
}
After running the code above, I get unexpected results when printing the pool:
objc[22671]: [0x7ff544817858] ################ POOL 0x7ff544817858
objc[22671]: ##############
I can't find the object registered in autoreleasepool. Why?
I think you've misunderstood what the autorelease pool is. It's a collection of objects that will receive a release messages to when the pool drains (most commonly at the end of an event loop). It's not a list of objects that will be "automatically released by some means." It's specifically the objects that will be sent a release message by this autorelease pool (and there may be multiple pools at any given time).
It has nothing at all to do with weak. "weak" is an attribute of a variable (pointer). "autoreleased" is something that has happened to an object. Objects may be autoreleased multiple times (and this is normal).
In manual memory management, this was done very commonly by sending -autorelease to the object. That means "don't release it now; I still need it, but when the current autorelease pool drains, release it." Note that this doesn't mean "destroy it." It just means "reduce the retain count by one." This is how you say "I only care about this object until the end of the event loop" (which is a very, very common thing to want to say).
In ARC you can't directly call -autorelease, but ARC still uses the autorelease pool in some cases. A very common way is by calling objc_autoreleaseReturnValue() on something before returning it. (This isn't something you call directly. It's something ARC injects automatically when needed.) In some cases, objc_autoreleaseReturnValue() still may not actually put the object on the autorelease pool. The compiler is smart enough to detect many cases where it can avoid the pool and improve performance. There are other cases where ARC may inject autorelease, and those cases also have optimizations where it may bypass the pool.
Note that there is generally no situation where this is something your app should rely on. _objc_autoreleasePoolPrint() is an Apple-internal function, and exists for low-level debugging. Whether something is in the autorelease pool or not is highly dependent on ARC implementation details and current compiler optimizations.
obj is never autoreleased, so it isn't placed in an autorelease pool. If you'd like obj to be autoreleased, you must call -autorelease on it, e.g.
#autoreleasepool {
id obj = [[[NSObject alloc] init] autorelease];
// ...
}
Note that -autorelease isn't available in ARC code.
I get the answer from this link .
The new implmenetation of __weak of Apple LLVM version 8.0.0 (clang-800.0.42.1) do not postpond the release to autoreleasepool, but use objc_release directly.

use __weak to local variable in ARC

When you write code like below in ARC
__weak NSMutableArray* array = [[NSMutableArray alloc] init];
The compiler will show you a warning or error and say "Assigning retained object to weak variable. object will be released after assignment".
But if you write like this:
__weak NSMutableArray* array = [NSMutableArray array];
There is no error.
I'm wondering if the second usage is reasonable in some situations? What's the difference between these two codes from memory management perspective? How does it work?
There can be very subtle differences that the compiler cannot know.
Let's take an immutable version: [NSArray array] could return the very same static object every time. So your weak variable will point to a valid object, that has a strong reference somewhere else. Or think of the singleton pattern. On the other hand, when calling alloc/init, convention dictates that you're the only owner of that object, and that will typically leave you with nothing.
Also, the factory method certainly looks more like a (functional) method. In any case, it doesn't communicate ownership of what it returns very well. For an autoreleased object, it's not clear whether you're the the only owner or a shared owner.
They are the same because you lose the object instantly. Compiler cannot know probably, except alloc init, that the object will be lost.
In the first form, the method returns a retained object. ARC ensures, that the object is released when there is no strong reference on the call-site. This is immediately true, with the weak reference - thus, the compiler emits a warning or error.
In the second form, the method returns an unretained object. In this case, the compiler must ensure that the object is still valid across the return boundary. When returning from such a function or method, ARC retains the value at the point of evaluation of the return statement, then leaves all local scopes, and then balances out the retain while ensuring that the value lives across the call boundary. That is, there is a strong reference created by the compiler. This strong reference will be automatically released by the compiler generated code.
Thus, in this case there's no error or warning.
In the worst case, holding that object may require to use an autorelease pool. However the compiler can apply certain optimisations which avoids this. Thus we should not assume that the returned object lives in an auto release pool.
See specification: http://clang.llvm.org/docs/AutomaticReferenceCounting.html#id14
See also this question on SO: Difference between [NSMutableArray array] vs [[NSMutableArray alloc] init]

Mark an object un-AutoRelease in ARC

As we all know, object will not dealloc immediately in ARC when no variable refer it. eg,
NSObject* obj = [[NSObject alloc] init];
obj = nil;
obj will dealloc after a time.(auto release pool drain).
Now, I want the obj dealloc right after it's been set to nil, which means the obj is not in auto-release-pool. But all other obj should work well as before, which means the program is still in ARC mode.
Is there a way, maybe macro or compiler flag, to do this?
First of all: You should not care about early deallocation. This is a strong code smell.
Second: Are you really, really sure, because -init does not put an object into ARP. Maybe the expression causes a retain autorelease combination, but compiling in release mode should optimize that away.
However, if it is in ARP you can close the ARP as mentioned by Hermann Klecker or – I think this is better – find the reason for being that object in ARP. There is no need for that.
Amin is right: the object is not in an autorelease pool. alloc, which created the object, does not engage a pool. On the other hand, you're right: ARC may not release the object immediately.
There is indeed an annotation you can use to force the release: objc_precise_lifetime. Adding that to the variable declaration will cause ARC to send release as soon as the object is no longer valid in the current scope.
However, Amin is also right that this is not very likely to be what you want. ARC knows what it's doing -- there are optimizations it can't make when you use this annotation -- and unless you know what it's doing too, you should strongly consider just letting it do its job.

Objective-C memory management: when do you use `[variable release]` vs `variable = nil` to clean up memory?

I've people who use [variable release] and some other times variable = nil to clean up memory?
When do you use each one? and what are the differences?
variable = nil; will not release memory. self.property = nil; will release memory if [self setProperty:nil]; would, for example a synthesized property with the retain attribute. Calling [variable release]; will always release one reference of an object.
Depends on what you mean by "clean up memory".
release is the only thing that frees dynamically allocated memory allocated by alloc. alloc should always be paired with a call to release or autorelease somewhere.
Setting a varible to nil does not necessarily free any memory (see drawnonward's answer), and can be a source of memory leaks.
When you see a variable set to nil, it's about preventing it from accidentally being used later after its memory has been freed (this can cause crashes). While you can always set a variable to nil after a call to release, it's somewhat a matter of style when it's actually necessary. For example, you don't often see variables set to nil in the dealloc method of a class, since by that point an object won't be able to accidentally misuse such a variable anymore, since it's being nuked.
If a property is set to retain, then these 3 are equivalent:
[self setProperty:nil];
self.property = nil;
[property release]; property = nil;
In each case, the object will be released, and then set to nil so that all access to the object from then on will not be allowed. "nilling" the instance variable is handy since it ensures you can only ever release the object once in this context because calling self.property = nil twice will do nothing the second time, but calling [property release] will release the object twice even though you likely only retain it once.
Most of the time I find it least bug prone to let retain properties do their thing and try to stay away from explicit retain and release calls most of the time.

Resources