Using #autoreleasepool in ARC inside a class - objective-c

I have understood how #autoreleasepool works, I have the newest version of xcode where ARC is supported.So I can use it, but I failt to understand how it works inside a class.
Let's suppose that I have this interface:
#interface AppDelegate : NSObject <NSApplicationDelegate>
{
#private
NSMutableDictionary* dictionary;
}
And that I allocate and initialize the dictionary in init method:
- (id) init
{
self= [super init];
if(self)
{
dictionary=[[NSMutableDictionary alloc]init];
}
return self;
}
In the dealloc method I can't send to dictionary the release message, because I am under ARC.So when I usually allocate memory I do something like that:
#autoreleasepool
{
NSMutableDictionary* dict=[[NSMutableDictionary alloc]init];
< use it>
}
PS: Pardon syntax errors, I have written it directly without compiling.
But in the class, where do I put the "#autoreleasepool" block?

You can place an #autoreleasepool block around any section of code, however you really shouldn't do what I think you're doing.
Autorelease is much less efficient than allowing ARC to add in retain and release calls for you, and it's potentially unsafe. Autorelease puts all of your objects in a "pool" and then when you're out of scope and/or whenever it decides to dump the pool, it "drains" the pool and the objects' retain counts get decremented by one.
The short answer: Leave out the #autorelease blocks completely unless Apple says otherwise in the documentation or the template (for example, main.m will have an #autoreleasepool in it).
This means that your objects could potentially get released before you really wanted them to. #autoreleasepool blocks are more useful for when you have a very tight loop of code that's going to instantiate and then discard a massive amount of objects. For example, a for loop that processes a huge database and allocates string objects and then uses those string objects to fill the properties of instances of a class you've created. In this case, ARC may not release those objects reliably while you're inside the for loop and you may need to create an autorelease pool.
However, ARC not doing the right thing in a tight loop isn't very common. It's really more of a non-ARC concept, where you use an NSAutoreleasePool and you manually drain it.

Related

Not expected strange behaviour of ARC during deallocating instances

I'm refreshing my knowledge in Objective-C world and now I'm testing some ARC with __weak local variables.
I have very simple code with such files GAObject.h
#import <Foundation/Foundation.h>
#interface GAObject : NSObject
+ (instancetype)create;
#end
Implementation of this interface GAObject.h
#import "GAObject.h"
#implementation GAObject
+ (instancetype)create {
return [[GAObject alloc] init];
}
- (void)dealloc {
NSLog(#"GAObject is being deallocated");
}
#end
So there is simple factory method create and I override dealloc method to watch if objects was deallocated when I expecting this. Now the funny part main.m:
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "Learning/GAObject.h"
int main(int argc, char * argv[]) {
#autoreleasepool {
NSLog(#"1");
NSObject *o1 = [[GAObject alloc] init];
NSObject * __weak weakObject = o1; // Line 1
o1 = nil; // o1 should be deallocated because there is no strong references pointing to o1.
NSLog(#"2");
NSObject *o2 = [GAObject create]; // Line 2
o2 = nil; // o2 should be deallocated here too but it is not deallocated. Why?
NSLog(#"3");
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
In the output I see this:
1
GAObject is being deallocated
2
3
But My expecting results should be:
1
GAObject is being deallocated
2
GAObject is being deallocated
3
If I create o2 using factory method then I have this behaviour. If I create o2 like this: [[GAObject alloc] init] then I get expected output. Also I noticed that when I remove line with weakObject I also get expected results. Can somebody explain it?
It's because ARC still respects the Cocoa memory-management naming conventions.
Under those conventions, a method named +create returns a +0 reference. So, in the implementation of the method, ARC has to balance the +1 reference of the alloc/init pair by autoreleasing the reference.
Then, in main(), ARC has to assume it has received a +0 reference from the call to +create. If it needed the reference to survive the current scope, it would retain it, but it doesn't so it doesn't. The second GAObject instance would be deallocated when the autorelease pool is drained, but that will never happen because UIApplicationMain() never returns. If you use two separate autorelease pools, one for the code dealing with GAObjects and another for the call to UIApplicationMain(), I expect you'll get the result you expect.
If ARC did need the reference to survive, it would retain at the assignment to the strong variable and release when that variable is assigned a new value (including nil) or goes out of scope. ARC has a run-time optimization that an autorelease-return in a callee and a retain of the returned value in the caller cancel each other out, such that the object is never put in the autorelease pool. If this were happening, you would get your expected results.
In fact, my expectation is that the compiler initially would emit that retain and release even in your case, but a subsequent pass removes redundant retains and releases. Your example has the release immediately follow the retain, which makes it even more obvious to the compiler that the pair are redundant. Because the retain gets removed, that autorelease optimization doesn't kick in, and a reference to your object really does get put into the autorelease pool.
If your method were named +newGAObject, then the naming conventions would mean it returns a +1 reference and this all changes. (Of course, as it stands, your +create method is just doing the same thing as the built-in +new method, except for the autorelease that ARC has to add. So, you could just change the calling code to use +new and that would also sidestep this issue.)
I don't know why the line with weakObject matters. But, since the behavior you're seeing depends on certain optimizations, anything that could tweak the optimizations can change the outcome.

Why do these ARC objects behave inconsistently?

Here's an Objective-C program for OS X that uses ARC - you can build it with cc -fobjc-arc -o objc_arc_test objc_arc_test.m or something. It creates two pairs of two objects, one using alloc/init and one using a factory function (the sort of thing you'd use autorelease for in pre-ARC code), all outside any autorelease pool, printing init and dealloc messages as it goes.
#import <Foundation/NSObject.h>
#include <stdio.h>
#if !__has_feature(objc_arc)
#error
#endif
#interface TestClass:NSObject {
int value;
}
-(TestClass *)initWithValue:(int)value;
-(void)dealloc;
+(TestClass *)testClassWithValue:(int)value;
#end
#implementation TestClass
-(TestClass *)initWithValue:(int)value_ {
if((self=[super init]))
self->value=value_;
printf("init: self=%p value=%d\n",self,self->value);
return self;
}
-(void)dealloc {
printf("dealloc: self=%p value=%d\n",self,self->value);
}
+(TestClass *)testClassWithValue:(int)value {
return [[TestClass alloc] initWithValue:value];
}
#end
static void f() {
TestClass *c5=[TestClass testClassWithValue:5];
TestClass *c6=[[TestClass alloc] initWithValue:6];
}
static void f2() {
TestClass *c7=[TestClass testClassWithValue:7];
TestClass *c8=[[TestClass alloc] initWithValue:8];
}
int main() {
f();
f2();
}
I'd expected to get init messages for 4 objects, and dealloc messages for 2, since ARC will ensure the alloc+init'd objects are destroyed and, on account of the lack of autorelease pool, will leave the other ones alone.
But what I get instead is init messages for 4 objects, and dealloc messages for 3:
init: self=0x7fea20500690 value=5
init: self=0x7fea205006f0 value=6
dealloc: self=0x7fea205006f0 value=6
init: self=0x7fea205006f0 value=7
init: self=0x7fea20500700 value=8
dealloc: self=0x7fea20500700 value=8
dealloc: self=0x7fea205006f0 value=7
I don't understand this behaviour! I'd expect the value=5 and value=7 objects to behave the same.
Why is it doing this?
(OS X 10.11.6; Xcode 8 - Apple LLVM version 8.0.0 (clang-800.0.38), Target: x86_64-apple-darwin15.6.0, Thread model: posix)
Since I believe OS X 10.9, there is an autorelease pool automatically created at the top level, even if you don't make one (this got rid of the historic "object autoreleased without an autorelease pool, just leaking" warning).
That said, that's not particularly relevant to this situation. ARC doesn't promise that anything will ever be autoreleased. It's free to use explicit releases when it can prove you won't use the object later. ARC is only obligated to ensure that objects with strong references are not destroyed, and that objects with no strong references are destroyed. Autoreleasepool is an implementation detail that ARC is free to use or not use at its discretion. As an optimization, ARC often avoids the autorelease pool in places that we would have used it manually in the past.
It's worth also noting that dealloc is never actually promised. The program is free to terminate without running it (this is a massive optimization which is why ObjC programs can terminate dramatically faster than C++ programs). In this case it happens to, but if you're relying on dealloc to run or not run, you're probably misusing it.

Objective C - ARC, memory management and performSelectorInBackground?

Does ARC no longer require #autoreleasepool on methods invoked in a background thread? The following code suppose to cause a memory leak unless doStuff is wrapped with an #autorelease pool, but when I run instruments it shows that User gets allocated and it gets deallocated at the end of the runloop.
- (IBAction)buttonClicked:(id)sender {
[self performSelectorInBackground:#selector(doStuff) withObject:nil];
}
- (void)doStuff {
User *user = [[User alloc] init];
NSLog(#"%#", user);
}
While there might be hints to an existing autorelease pool in NSThread's implementation there is no such guarantee the documentation. In contrary, the documentation explicitly states otherwise:
performSelectorInBackground:withObject:
The method represented by aSelector must set up the thread environment just as you would for any other new thread in your program.
Threading Programming Guide
If your application uses the managed memory model [MRC and ARC, as opposed to Garbage Collection], creating an autorelease pool should be the first thing you do in your thread entry routine.
Conclusion: While in some specific scenarios there might be an autorelease pool in place it's not advisable to rely on this fact. It's undocumented behavior and can change with every release of the OS or other circumstances. It should generally be avoided in shipping code.
I used the following test app:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#end
#import "ViewController.h"
#implementation ViewController
- (void)viewDidLoad{
[super viewDidLoad];
[self performSelectorInBackground:#selector(doStuff) withObject:nil];
}
- (void)doStuff {
NSMutableArray *ar = [NSMutableArray array];
for (int i=0; i<1000000; i++) {
ar[i] = [NSString stringWithFormat:#"%i", i];
}
}
#end
Profiling it with the Allocation instrument, I get the following result:
In the 8th line of the call tree, an autorelease pool is used, although I did not set up one in my code. Also, the memory allocated by the background thread seems to be released.
It thus looks as if the background thread has an autorelease pool installed.
EDIT (see comment below):
This does not mean, however, that it is not necessary to install autorelease pools for threads, since the behavior shown above is not documented, as far as I know.
Actually, that code is supposed to leak memory (under MRC) if you don't add an autorelease (which is pretty much just asking for trouble). But I'm going to answer your question as you asked it anyways.
ARC is supposed to eliminate the need for any sort of memory management (except for blocks and a lot of other gotchas, but whatever). But there are still autoreleased objects. #autoreleasepool is particularly useful in tight loops, etc. There are still pools to drain, you just don't have to add autorelease to objects yourself.

Use autorelease when setting a retain property using dot syntax?

I see in some sample code that autorelease is used. I am not familiar with the instances when this is required. For example, if I create an annotation object
Header file
#interface someViewController: UIViewController
{
Annotation *annotation;
}
#property (nonatomic, retain) Annotation *annotation;
#end
Implementation file
#implementation someViewController
#synthesize annotation
#end
Question: Is it the correct approach if I initialize my annotation object in the implementation file like this?
self.annotation = [[Annotation alloc] initWithCoordinate:location];
Do I need to set autorelease for this? Or can I just do it the normal way and add the release in the dealloc method?
this is correct:
self.annotation = [[[Annotation alloc] initWithCoordinate:location] autorelease];
because annotation property is declared as a retain property, so assigning to it will increment its retain count.
you will also need, all the same, to release self.annotation in -dealloc.
in short:
init will set retain count to 1;
assigning to self.annotation, will set it to 2;
autorelease will set it back to 1 when the main loop is executed again;
release in dealloc will set the retain count to 0, so that the object will be deallocated);
the best way to think of autorelease is the following, in my opinion: autorelease will "schedule" an "automatic" release for your object at some (near) point in future (typically when the control flow goes back to the main loop, but details are hidden in the hands of Apple).
autorelease is mostly useful in conjunction with init, specifically in the following cases:
when you init a local variable, so that you don't have to release it explicitly before it goes out of scope (the main loop will do that for you);
when you return a pointer to an object you have just created without keeping ownership of it (typical case of the create/make* kind of selectors, the receiver is required to retain it to get ownership);
with properties that retain, when you assign to them an object that they should own uniquely;
with data structures that increment the retain count (NSMutableArray, NSMutableDictionary, etc): you should generally autorelease a newly inited object when you add it to such data structure.
apart from case 2, it is evident that the use of autorelease is meant to improve readability of the code and reduce the potential for errors (meaning that in all of the other cases, you could simply release explicitly your object after the assignment or at the end of the scope).
when using properties, you have always to check whether they are of the retain or assign/copy case; in the first case, assigning a newly inited object to a property generally requires autorelease.
Anyway, I would suggest at least skimming one of the many tutorial on memory management for iOS.
Autorelease is telling the object to release itself before leaving the scope.
Sometimes when you code, you'll encounter something like this
- (void)doSomething
{
if(true)
{
NSString *foo = [[NSString alloc] initWithString:#"foo"];
//Some execution here
[foo release];
}
}
- (void)doSomething
{
if(true)
{
//By doing this is telling to to release foo object before getting out of the scope
//which is similar with above practice
NSString *foo = [[[NSString alloc] initWithString:#"foo"] autorelease];
//Or you can do it this way
NSString *foo = [[NSString alloc] initWithString:#"foo"];
[foo autorelease];
//Some execution carry on, it'll release foo before entering next scope
}
//This is out of the scope
}
Of course, releasing an object doesn't mean deallocating the object.
Sometimes you retain the object so you can still use it outside of its scope.
Judging from your question, if your the object is located within your header file/interface.
You should release it in dealloc method. CMIIW.

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