I have been reading different sources for automatic reference counting but haven't found any great article or documentation which clarify my understanding. My understanding about ARC(Automatic Reference Counting) is, it completely takes over developer control on memory management and assign it to compiler to do memory management.
Am I thinking right?
So does that mean retain,release and autorelease is no more for iOS 5 SDK?
Example:
Lets say I use to make object like this,
UIView *message = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, cell.frame.size.width, cell.frame.size.height)];
message.tag = 0;
[message addSubview:balloonView];
[message addSubview:label];
[cell.contentView addSubview:message];
[balloonView release];
[label release];
[message release];
will become like this IF ARC is ON,
UIView *message = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, cell.frame.size.width, cell.frame.size.height)];
message.tag = 0;
[message addSubview:balloonView];
[message addSubview:label];
[cell.contentView addSubview:message];
Any input will be helpful thank you
Cheers!
Yes and no:
Yes, ARC rids you of manually calling retain, release, autorelease, possibly lets you delete quite a few of your dealloc implementations and — on the new runtimes — even introduces zeroing weak references (w00t!), but it does not prevent you from leaking, per se.
It is automated retain/release and not a garbage-collector, so it "allows you" to still leak memory by creating retain-cycles.
Furthermore, it changes the reference semantics of the __block attribute from weak to strong:
Every bit of code where you avoided the capture of self by using __block id blockSelf = self; is now a potential leak — luckily, Clang has become even better warning you about issues like this.
An area, where ARC actually makes you write more code than before, most of the time, is when you are using toll-free-bridging between CFTypeRefs and id <NSObject>s:
The casts have to be annotated to tell ARC what to do or you'll get a compiler error.
If you're working with plain CF APIs, nothing changes: everything stays manual.
One of the best resources on ARC I found, is Chris Parker's WWDC talk on ARC Internals. If you haven't seen it yet, you should definitely check it out — the general part on ARC starts around the 8 minute mark, while the details start about 29 minutes in.
Your example code is correct. ARC makes those calls for you.
It ARC doesn't, however, "completely takes over" a newbie would still need to understand memory management. But like apple says it lets you concentrate on object ownership instead of retain counts.
For example if you don't modify your NSObject <Protocol> *_delegate; with __weak or __unsafe_unretained you will still create a retain cycle.
Yes, you're right. ARC pretty much takes the hassle of doing memory management out of your hands and has the compiler deal with all that stuff. Sit back, relax, and worry more about writing the code you want rather than causing trivial memory management issues :)
Related
New to ios and trying to return an NSString from an function. As I understand, I need to [NSString... alloc] init] in order to create the string for return. Also, since I called alloc, I guess I have to autorelease the object myself however I'm getting the message "ARC forbids explicit message send of 'autorelease'" so.. how do I tell ios when I'm done with that allocated NSString?
- (NSString *) generateUID
{
char foo[32];
// create buffer of all capital psuedo-random letters
for (int i = 0; i < sizeof(foo); i++)
foo[i] = (random() % 25) + 65; // 0-25 + CAPITAL_A
NSString *uid = [[NSString alloc] initWithBytes:foo length:sizeof(foo) encoding:NSASCIIStringEncoding];
NSLog (#"uid: %#", uid);
return (uid);
}
ARC = automatic reference counting = the compiler adds the necessary releases and autorelases based on its analysis of your code. You don't see this of course because it happens behind the scenes. As mentioned by sosbom in his comment, you really should read the applicable documentation on the Apple website.
You don't.
autorelease is just there for compatibilities sake, prior to iOS 5, you'd have to do:
Thing *myThing = [[Thing alloc] init]; // Retain count: 1
[myArray addObject:myThing]; // Retain count: 2
[myThing release]; // Retain count: 1
With the above code, the responsability of holding the object is given to the array, when the array gets deleted, it will release its objects.
Or in the case of autorelease.
- (MyThing*)myMethod
{
return [[[MyThing alloc] init] autorelease];
}
Then it would release the object once it gets to a NSAutoReleasePool and get removed once drained.
ARC takes care of that now, it pretty much inserts the missing pieces for you, so you don't have to worry about it, and the beauty of it, is that you get the advantages of reference counting (vs garbage collector), at the cost of an increased compile-time checking to do the ARC step, but your end users don't care about compile-time.
Add to that, that you now have strong and weak (vs their non-ARC siblings retain and assign, the later one still useful for non-retained things), and you get a nice programming experience without tracing the code with your eyes and counting the retain count on your left hand.
Short answer is you don't! ARC will handle the memory management for you.
When ARC is turned on, the compiler will insert the appropriate memory management statements such as retain and release messages.
It is best to use ARC as the compiler has a better idea of an object's life cycle and is less prone to human error.
One other important thing to note about ARC. ARC is not the same as traditional garbage collection. There is no separate process or thread running in the background, like java's GC, which deletes objects when there is no longer a reference to them. One could view ARC as compile time garbage collection :).
The only other thing to be aware of is reference cycles and bridging pointers/objects between Objective-C and Obj-C++/C. You might want to look-up http://en.wikipedia.org/wiki/Weak_reference
Hope this helps
In general, you should define a constructor method in your class and put the alloc logic in that method. Then, it is much harder to make a type casting error as the alloc/init approach always return (id) and it is not very type safe. This what built-in classes like NSString do, like [NSString stringWithString:#"foo"], for example. Here is a nice little block you can use to write code that works both with older non-arc compilation and with arc enabled.
+ (AVOfflineComposition*) aVOfflineComposition
{
AVOfflineComposition *obj = [[AVOfflineComposition alloc] init];
#if __has_feature(objc_arc)
return obj;
#else
return [obj autorelease];
#endif // objc_arc
}
You then declare the method and create an instance of the object like so:
AVOfflineComposition *obj = [AVOfflineComposition aVOfflineComposition];
Using the above approach is best, as it is type safe and the same code with with arc vs non-arc. The compiler will complain if you attempt to assign the returned object to a variable of another type.
With obj-c on the iPhone, is there any harm in autoreleasing everything instead of releasing?
Eg, this code:
NSString *recipe = [[NSString alloc] initWithUTF8String:sqlite3_column_text(dbps,0)];
[arr addObject:recipe];
[recipe release];
Can be shortened to two lines by autoreleasing the recipe nsstring when i create it:
NSString *recipe = [[[NSString alloc] initWithUTF8String:sqlite3_column_text(dbps,0)] autorelease];
[arr addObject:recipe];
Are there any drawbacks to this? I find it suits my coding style better. Thanks all.
The drawback is that the objects get released later. In most cases this won't be a problem but if you allocate and autorelease thousands of objects in a tight loop this overhead can add up to a point where it impacts performance or even causes your app to run out of memory.
In any case, you might want to use:
[NSString stringWithUTF8String:sqlite3_column_text(dbps,0)];
instead of
[[[NSString alloc] initWithUTF8String:sqlite3_column_text(dbps,0)] autorelease];
If the object does not have a scope outside the function it is used, you should always release it in order to minimize the amount of memory consumed by your application.
If you let the object stick around until the autorelease pool kicks in, a lot of unneeded memory may need to be allocated. This is especially important with iOS 4 and fast app switching, where memory is also allocated to apps in the background.
The lower your own memory footprint is, the bigger a chance there is that your application will not be terminated when in the background in case memory gets tight.
Here is my understanding on the subject, I'm sure I'll get downvoted to death if I say anything wrong ;)
Generally speaking, in tight loops, init + release will be faster than autorelease. Most of the time performance is not an issue
You may not actually want to autorelease at all times. If you want an object to stick around, you'll need to manually release or stick your autoreleased obj in a property with a retain so that you can get at it later otherwise your obj will be released as soon as it goes out of scope
With manual init + release you have more fine grained control over what is happening, this may be useful for advanced multi-threaded scenarios (especially now that GCD is pervasive)
autorelease is probably fine most of the time so long as you understand how reference counting works, but do not treat it like a silver bullet. You can still leak plenty of memory using autorelease incorrectly.
I'll turn the question around: The main disadvantage with release is that it's very easy to forget. Assignment to a local or to an instance variable look pretty much identical (they're entirely identical if you don't assign in an initializer):
Foo * a = [[Foo alloc] init];
myFoo = [[Foo alloc] init];
This, and similar issues, leads to a bunch of potential problems:
When you copy-and-paste code, will you forget a release?
When you change between local and instance variables, will you remember to add/remove the release?
If an exception is thrown, does the code leak? (This is almost always true, but it is traditional to not care about exceptions in Obj-C.)
Personally, the overhead of a memory leak when you refactor code is worse than the overhead of a few autoreleased objects. I occasionally refactor code so it looks like this:
FooView * v = [[[FooView alloc] initWithFrame:CGRectZero] autorelease];
// set up v...
myFoo = [v retain];
Local variables are marginally more efficient.
If you decide that you don't need the instance variable anymore, you just need to comment out one line.
Views are pretty heavyweight, so the autorelease overhead isn't going to matter much
For completeness, if you're doing a bunch of things in a loop (e.g. test code), you can autorelease at the end of every iteration with something like this:
for (size_t n = 100000; n--; ) {
NSAutoreleasePool * pool = [NSAutoreleasePool new];
// ... allocate and autorelease some stuff ...
[pool release]; pool = nil;
}
If you're worried about efficiency, you can gain significant speedups using (e.g.) CFString functions — the Objective-C overhead is pretty significant for small strings.
Problem is when you do autorelease you're not actually releasing the object but adding it to the current autorelease pool. Object will be effectively released when you release that pool which is done every time through the main loop .
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, nil);
[pool release];
You can create you're own autorelease pool but I'm not sure it would be better than simply use release.
Given the two scenarios, which code is best practice and why?
Autorelease
loginButton = [[[UIBarButtonItem alloc] initWithTitle:#"Login"
style:UIBarButtonItemStylePlain
target:self
action:#selector(loginButtonClicked:)]
autorelease];
self.navigationItem.rightBarButtonItem = loginButton;
or
Release
loginButton = [[UIBarButtonItem alloc] initWithTitle:#"Login"
style:UIBarButtonItemStylePlain
target:self
action:#selector(loginButtonClicked:)];
self.navigationItem.rightBarButtonItem = loginButton;
[loginButton release];
For your example, it doesn't really matter. Personally, I would probably use the first case. That would let you add modifications or debugging code later without having to worry about moving the [loginButton release] line around.
There seems to be a stigma against using autorelease (i.e. prefer to release whenever possible), which is why I typically go the second route. But since you're not in a loop here, releasing now vs. autoreleasing later will have exactly the same effect (since another object has retained loginButton, it won't be dealloc()ed).
But I should point out that most of my memory leaks are caused by forgetting to add the release line, so it would probably be better to just tack on the autorelease right away.
Either will be just fine in your case, as Carl says. It is because the UIBarButtunItem object stays in the memory because one reference to it is kept inside self.navigationItem (assuming you declared that property with #property (retain).). Therefore, the usual diatribe against using the autorelease pool, that it keeps unnecessary objects in memory until the end of the current event loop, doesn't apply here.
Since you're on a very tight memory budget on the iPhone, the preferred way should be through explicit release. This way objects don't stick around until the autorelease pool gets emptied during the runloop and you are able to keep your memory footprint as small as possible.
Since the navigationItem retains it, the two end up being identical. Style-wise, autorelease is preferred for returns from methods that don't say alloc or copy in their name, but otherwise it is up to you. If the object wasn't separately retained, release would free up the memory faster.
The code-style issue of setting a reference to nil after release is a related question.
When you send an -autorelease message to an object, you're adding it to a list, and it will get a -release message when the autorelease pool is released. The entire purpose of -autorelease is to provide a way for you to balance your retains and releases when something else might still want the object you're releasing, but you don't. In the situation you describe, the second example you gave is better.
Though in the presented scenario the two cases are identical but there is a slight speed advantage to using release (reference )over autorelease.So when there are strict performance requirements go with release
There are a lot of cases in which one would alloc an instance, and release it right after it's being assigned to something else, which retains it internally.
For example,
UIView *view = [[UIView alloc] initWithFrame...];
[self addSubView:view];
[view release];
I have heard people suggesting that we go with autorelease rather than release right after.
So the above becomes:
UIView *view = [[[UIView alloc] initWithFrame...] autorelease];
[self addSubView:view];
What's the best practice here? Pros and cons?
In most cases, it wont really matter either way. Since -autorelease simply means that the object will be released at the end of the current iteration of the run loop, the object will get released either way.
The biggest benefit of using -autorelease is that you don't have to worry about the lifetime of the object in the context of your method. So, if you decide later that you want to do something with an object several lines after it was last used, you don't need to worry about moving your call to -release.
The main instance when using -release will make a noticeable difference vs. using -autorelease is if you're creating a lot of temporary objects in your method. For example, consider the following method:
- (void)someMethod {
NSUInteger i = 0;
while (i < 100000) {
id tempObject = [[[SomeClass alloc] init] autorelease];
// Do something with tempObject
i++;
}
}
By the time this method ends, you've got 100,000 objects sitting in the autorelease pool waiting to be released. Depending on the class of tempObject, this may or may not be a major problem on the desktop, but it most certainly would be on the memory-constrained iPhone. Thus, you should really use -release over -autorelease if you're allocating many temporary objects. But, for many/most uses, you wont see any major differences between the two.
I agree with Matt Ball. Let me just add that, if you find yourself using this pattern frequently, it can be handy to write a quick category:
#interface UIView (MyCategories)
- (UIView *)addNewSubviewOfType:(Class)viewType inFrame:(NSRect)frame;
#end
#implementation UIView (MyCategories)
- (UIView *)addNewSubviewOfType:(Class)viewType inFrame:(NSRect)frame
{
UIView * newView = [[viewType alloc] initWithFrame:frame];
[self addSubView:newView];
return [newView autorelease];
}
#end
Which can be used as follows:
UIView * view = [someView addNewSubviewOfType:[UIView class]
inFrame:someFrame];
And it even works with other types, as long as they are derived from UIView:
UIButton * button = [mainView addNewSubviewOfType:[UIButton class]
inFrame:buttonFrame];
I usually go for -release rather than -autorelease whenever possible. This comes from years of experience debugging and enhancing other people's Objective-C code. Code that uses autorelease everywhere makes it harder to debug when an object gets over-released, since the extra release happens far away from the incorrect code.
It's also the case that many folks use autorelease when they just don't understand how cocoa memory management works. Learn the rules, learn the API, and you'll almost never need to autorelease an object.
A last minor point is that if you don't need the autorelease behavior, then using autorelease just needlessly adds extra work for your program to do.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Where are the best explanations of memory management for iPhone?
I come from a web development background. I'm good at XHTML, CSS, JavaScript, PHP and MySQL, because I use all of those technologies at my day job.
Recently I've been tinkering with Obj-C in Xcode in the evenings and on weekends. I've written code for both the iPhone and Mac OS X, but I can't wrap my head around the practicalities of memory management. I understand the high-level concepts but am unclear how that plays out in implementation. Web developers typically don't have to worry about these sorts of things, so it is pretty new to me.
I've tried adding memory management to my projects, but things usually end up crashing. Any suggestions of how to learn? Any suggestions are appreciated.
On top of the official Apple resources listed in the post arul linked to, here are some other good reads on the topic:
Hold me, use me, free me
CocoaDev.com 's Memory Management Section
And for help debugging memory management problems:
NSZombieEnabled
Rules of thumb
Autorelease
Every time you have [[NSObject alloc] init] you wrap it into an autorelease:
// make sure it gets properly released
// autorelease releases the object at a later time.
NSObject *instance = [[[NSObject alloc] init] autorelease];
Things like this (can't remember the term) are always autoreleased, you should create your classes to correspond to this rule too:
NSString *test = [NSString stringWithFormat:#"%i", 4];
Retain / Release
If you need to store an object for longer than the current method retain it:
[instance retain];
If you don't need it anymore or exchanged it with another object:
[instance release];
You should always have the same amount of retains as releases in your code.
Accessors
Objective-C 2.0 let's you declare properties and writes your accessors for you. For example #property(retain, readwrite) NSString *text; looks something like this:
- (NSString *)text {
return text; // I don't like calling variables _test
}
- (void)setText:(NSString *)newText {
[newText retain];
[text release];
text = newText;
}
init / dealloc
In those methods you should always use [self setVariable:…] like this:
- (id)init {
if (self = [super init]) {
[self setText:#"Lorem ipsum dolor sit amet."];
// …
}
return self;
}
- (void)dealloc {
// make sure text is set to nil and the old value gets released.
[self setText:nil];
}
Garbage Collector
Use the Garbage Collector built into Objective-C 2.0, there's little gain from not using it if you can.
How does this retain / release work anyway?
Every time you allocate an object1, [NSObject alloc], the retain count is set to 1. If this count reaches 0 the object is deleted. [instance retain] increases the count by 1 and [instance release] decreases the count by 1.
1 [instance copy] does allocate a new instance too, and therefore also has a retain count of 1.
Memory management in Cocoa is actually pretty easy thanks to the retain / release paradigm. Start by learning the concept of pointers-- while you don't need to be an expert in C to learn objective-c, understanding pointers is essential. Then read this (or another) guide. Write down the rules if you need to on when you should and shouldn't retain an object, and with a little practice you should "get it" in no time.
Keep in mind you could turn on garbage collection and not worry so much about memory management, but I wouldn't recommend this; even with GC enabled there are still times when you have to understand what's going on behind the scenes.
Read the link that arul provided. Now that you're using a language that has no garbage collection (if you're developing for the iPhone) it's time to start thinking about object life times. Every object you instantiate will now have to be deallocated by someone, probably (possibly) you. Memory management is not an easy subject and the only way to get a handle on this is to practice. Play around with allocating an object and deallocating it. Watch the retain counts grow as you add an object to a collection. Look into Autorelease pools. Essentially, you should know where and when an object gets allocated AND deallocated. On systems with limited memory (such as iphone) you'd want an object to disappear as soon as possible.
My suggestion would be to spend a few days playing around with memory management before you start working on the bulk of your application. Debugging memory issues and struggling with application logic is a bit of a hassle.
One mistake I see often is the use of the autorelease convenience calls when a regular release will do. This only makes life difficult for you because this removes the problem from the call site, while making it very difficult to isolate problems in large codebases.
This also forces you to learn memory management from the outset, which is not fun, but worthwhile because you can generally salvage more of the code you've written.
I used the Memory Management video training course from the Mac Developer Network. Gave me exactly what I needed when I was starting out. It immediately paid benefits when I started having my own memory management problems.