ARC, non-ARC, and inheritance - objective-c

I haven't used ARC yet other than to deal with it when it forces it's way into a project via 3rd party code. I've read all the ARC docs but haven't seen an answer to this question:
If I have a class that's defined in a module compiled with -fobjc-arc, can I derive a new class from this in a module that is NOT ARC-enabled?
In my mind it should work fine as long as the derived class doesn't attempt to touch any ivars in the root class. It seems to me that even having a dealloc method that calls [super dealloc] would be fine in the derived class.
And, what about the other way around? Can I derive a ARC-enabled class from a non-ARC class? Should work fine too, right?
Bonus points: are there any gotcha's when mixing ARC and non-ARC code that I should make myself aware of?

There are no issues that I am aware of. You have to realize that ARC is something like a source code preprocessor, adding the memory management calls for you during the compilation. When you arrive at the linking phase, you can’t really tell ARC code from non-ARC code. (This is probably an over-simplification, but one that should work for your purposes.) If your derived class has correct memory management and the super class has correct memory management, the result will work fine.
About the only difference I can think of is handling of weak properties. But I don’t know enough about those to say if it’s possible to arrive at buggy code using some combination of ARC and MRC code with weak properties.

This was a comment, but having thought about it I want to expand what it said.
Have you tried inheriting an ARC class from a normal subclass? My thoughts (without having tried it either) is that this will not work. Firstly, if the ARC class has public properties or ivars using ARC keywords, like weak I think you will get errors during compilation from the header file. Secondly, I don't know how the dealloc would work. Do you need to call [super dealloc] or not? I don't know.
Anyway, if your superclass is ARC, why would you not use ARC in any subclasses? There's no advantage to doing that at all.
Can I derive a ARC-enabled class from a non-ARC class? Should work fine too, right?
I was going to say that won't work either, but I would have been wrong. Virtually everything has to inherit from NSObject which is manual reference counted.

Yes, you may both implement non-ARC ancestor from ARC parent class, and ARC ancestor from non-ARC parent class.
Actually, ARC is a syntax sugar, or you may say, is just preprocessor which analyzes your source code at compile step and inserts appropriate [release] and [retain] calls to your code. At runtime level nothing is changed (except for the weak properties).

ARC means the compiler takes care of memory management, non-ARC means you take care of it, but in both cases memory management works exactly the same way:
If an object must stay alive, its retain counter is increased (that's what retain does)
If an object is not needed anymore, its retain counter is decreased before the reference to it is lost (that's what release does)
If you are done with an object but it must not die yet, e.g. as you need to return it as a method result (and you don't want to return a dead object), it must be added to an autorelease pool that will decrease its retain count at a later time (that's what autorelease does, it's like saying "call release on that object at some future time.")
Newly created objects have a retain count of 1.
If the retain count reaches zero, the object is freed.
Whether you do all that yourself or the compiler does it for you, it plays no role. After compilation, these methods are being called, also with ARC, but with ARC the compiler has decided for you when which method is called. There is some extra magic, e.g. ARC doesn't always have to add objects to autorelease pools when returning them as method result, this can often be optimized away, but you don't have to care as this magic is only applied if the caller and the called method both are using ARC; if one of them isn't, then a normal autorelease is used (which still works in ARC exactly as it used to).
The only thing you must take care of is retain cycles. Whether you use ARC or not, reference counting can't deal with retain cycles. No difference here.
Pitfalls? Careful with Toll Free Bridging. A NSString * and a CFStringRef are in fact the same thing but ARC doesn't know about the CF-world, so while ARC takes care of the NSString, you must take care of the CFString. When using ARC, you need to tell ARC how to bridge.
CFStringRef cfstr = ...;
NSString * nsstr = (__bridge_transfer NSString *)cfstr;
// NSString * nsstr = [(NSString *)cfstr autorelease];
Code above means "ARC, please take ownership of that CFString object and take care of releasing it as soon as you are done with it". The code behaves like the code shown in the comment below; so careful, cfstr should have a retain count of at least one and ARC will release it at least once, just not yet. The other way round:
NSString * nsstr = ...;
CFStringRef cfstr = (__bridge_retained CFStringRef)cftr;
// CFStringRef cfstr = (CFStringRef)[nsstr retain];
Code above means "ARC, please give me ownership of that NSString, I'll take care of releasing it once I'm done with it". Of course, you must keep that promise! At some time you will have to call CFRelease(cfstr) otherwise you will leak memory.
Finally there's (__bridge ...) which is just a type cast, no ownership is transferred. This kind of cast is dangerous as it can create dangling pointers if you try to keep the cast result around. Usually you use it when just feeding an ARC object to a function expecting a CF-object as ARC will for sure keep the object alive till the function returns, e.g. this is always safe:
doSomethingWithString((__bridge CFStringRef)nsstr);
Even if ARC was allowed to release nsstr at any time as no code below that line ever accesses it anymore, it will certainly not release it before this function has returned and function arguments are by definition only guaranteed to stay alive until the function returns (in case the function wants to keep the string alive, it must retain it and then ARC won't deallocate it after releasing it as the retain count won't become zero).
The thing most people seem to struggle with is passing ARC objects as void * context, as you sometimes have to with older API, yet that is in fact dead simple:
- (void)doIt {
NSDictionary myCallbackContext = ...;
[obj doSomethingWithCallbackSelector:#selector(iAmDone:)
context:(__bridge_retained void *)myCallbackContext
];
// Bridge cast above makes sure that ARC won't kill
// myCallbackContext prior to returning from this method.
// Think of:
// [obj doSomethingWithCallbackSelector:#selector(iAmDone:)
// context:(void *)[myCallbackContext retain]
// ];
}
// ...
- (void)iAmDone:(void *)context {
NSDictionary * contextDict = (__bridge_transfer NSDictionary *)context;
// Use contextDict as you you like, ARC will release it
// prior to returning from this method. Think of:
// NSDictionary * contextDict = [(NSDictionary *)context autorelease];
}
And I have to real big gotcha for you that are not that obvious at first sight. Please consider this code:
#implementation SomeObject {
id _someIVAR;
}
- (void)someMethod {
id someValue = ...;
_someIVAR = someValue;
}
This code is not the same in ARC and non ARC. In ARC all variables are strong by default, so in ARC this code behaves just like this code would have:
#interface SomeObject
#property (retain,nonatomic) id someIVAR;
#end
#implementation SomeObject
- (void)someMethod {
id someValue = ...;
self.someIVAR = someValue;
}
Assigning someValue will retain it, the object stays alive! In non-ARC the code will behave like this one:
#interface SomeObject
#property (assign,nonatomic) id someIVAR;
#end
#implementation SomeObject
- (void)someMethod {
id someValue = ...;
self.someIVAR = someValue;
}
Note the property is different, as ivar's in non-ARC are neither strong or weak, they are nothing, they are just pointers (in ARC that is called __unsafe_unretained and the keyword here is unsafe).
So if you have code that uses ivars directly and doesn't use properties with setters/getters to access them, then switching from non-ARC to ARC can cause retain cycles in code that used to have sane memory management. On the other hand, moving from ARC to non-ARC, code like that can cause dangling pointers (pointers to former objects but since the object has already died, these point to nowhere and using them has unpredictable results), as objects that used to be kept alive before may now die unexpectedly.

Related

__bridge_transfer and performSelector:withObject:

I have a CFDictionaryRef that doesn't retain/release its objects. When I add an item in it, I take care of retaining it, and later :
NSMutableArray *array = (__bridge_transfer NSMutableArray *)CFDictionaryGetValue(...)
[self performSelector:someSelector withObject:array];
Where someSelector is a variable holding a selector I know about. Now, that second line makes Xcode tell the notorious warning:
PerformSelector may cause a leak because its selector is unknown
Does that mean I should worry about ARC not knowing how to manage memory for the array variable of which I just transferred ownership?
From a comment to the accepted answer of this question, it appears that somebody at Apple has confirmed this hypothesis (citing the answer itself):
In fact, there are times when memory management is tied to the name of the method by a specific convention. Specifically, I am thinking of convenience constructors versus make methods; the former return by convention an autoreleased object; the latter a retained object. The convention is based on the names of the selector, so if the compiler does not know the selector, then it cannot enforce the proper memory management rule.
Thus, it has nothing to do with a possible leak of arguments passed to the performSelector: call, but rather to its returned value, for which Objective-C has no way of knowing if it was autoreleased or not. This is also what Martin R from the comments was assuming.

Releasing an object from ARC method which calls a no-arc C function

I'm using a library that is not ARC compliant from an ARC based project. A function in that library returns a retained UIImage * object. Is there a way to use the __bridge attributes to let ARC know about this so it can manage the retain count of the returned object? I tried:
UIImage *returnedImage;
returnedImage = (__bridge_transfer UIImage *)functionThatReturnsAUIImage();
But it won't allow me to cast the UIImage * to a UIImage *). I also tried:
returnedImage = (UIImage *)(__bridge_transfer void *)functionThatReturnsAUIImage();
Which also didn't work. The compiler suggested __bridge_retained instead of __bridge_transfer, but that I believe would have done the opposite of what I was after (i.e. it would have increased the retain count on the returned UIImage object).
I believe the proper thing to do is to make the C function return an autoreleased object. As best as I can tell, ARC assumes any C function that returns an object will have returned an autoreleased object. I have access to the source for this library, so I can do this, but I was wondering if there was a solution I could employ from the calling side if I wasn't able to modify the library.
It's too bad that the logical bridge modifier isn't working for you.
Two possible approaches leap out at me.
First, while it's not elegant, you could just write your own image release function, for example:
// ImageManualMemoryManagement.h
#import <UIKit/UIKit.h>
int releaseImage(UIImage *img);
and
// ImageManualMemoryManagement.m
#import "ImageManualMemoryManagement.h"
int releaseImage(UIImage *img)
{
[img release];
return 0;
}
In your project's target settings, under Build Phases, double click on this one .m source file under "Compile Sources" and add the non-ARC flag, -fno-objc-arc (to allow you to use the release method).
You now have a function you can call that will reduce the retain count of your UIImage and then all is good in the world again.
Second, the more dramatic solution would be to write your own non-ARC wrapper class around the entire C interface that your image library presents, remedying those few methods that aren't returning items with the correct retain count. But it seems like a lot of work for just one retainCount transgression. But if the library has it's own weaknesses (e.g. you're dealing with a clumsy low-level library), you might kill two birds with one stone.
According to apple's Transitioning to ARC Release Notes, __unsafe_unretained should be used here.
__unsafe_unretained specifies a reference that does not keep the referenced object alive and is not set to nil when there are no strong references to the object. If the object it references is deallocated, the pointer is left dangling.
Because ARC and MRC (manual reference counting) has different memory management rules, no keyword that has memory management influence works. The only choice is the keyword __unsafe_unretained which has no memory management influence to both ARC and MRC.

Why does ARC retain method arguments?

When compiling with ARC, method arguments often appear to be retained at the beginning of the method and released at the end. This retain/release pair seems superfluous, and contradicts the idea that ARC "produces the code you would have written anyway". Nobody in those dark, pre-ARC days performed an extra retain/release on all method arguments just to be on the safe side, did they?
Consider:
#interface Test : NSObject
#end
#implementation Test
- (void)testARC:(NSString *)s
{
[s length]; // no extra retain/release here.
}
- (void)testARC2:(NSString *)s
{
// ARC inserts [s retain]
[s length];
[s length];
// ARC inserts [s release]
}
- (void)testARC3:(__unsafe_unretained NSString *)s
{
// no retain -- we used __unsafe_unretained
[s length];
[s length];
// no release -- we used __unsafe_unretained
}
#end
When compiled with Xcode 4.3.2 in release mode, the assembly (such that I'm able to understand it) contained calls to objc_retain and objc_release at the start and end of the second method. What's going on?
This is not a huge problem, but this extra retain/release traffic does show up when using Instruments to profile performance-sensitive code. It seems you can decorate method arguments with __unsafe_unretained to avoid this extra retain/release, as I've done in the third example, but doing so feels quite disgusting.
See this reply from the Objc-language mailing list:
When the compiler doesn't know anything about the
memory management behavior of a function or method (and this happens a
lot), then the compiler must assume:
1) That the function or method might completely rearrange or replace
the entire object graph of the application (it probably won't, but it
could). 2) That the caller might be manual reference counted code, and
therefore the lifetime of passed in parameters is not realistically
knowable.
Given #1 and #2; and given that ARC must never allow an object to be
prematurely deallocated, then these two assumptions force the compiler
to retain passed in objects more often than not.
I think that the main problem is that your method’s body might lead to the arguments being released, so that ARC has to act defensively and retain them:
- (void) processItems
{
[self setItems:[NSArray arrayWithObject:[NSNumber numberWithInt:0]]];
[self doSomethingSillyWith:[items lastObject]];
}
- (void) doSomethingSillyWith: (id) foo
{
[self setItems:nil];
NSLog(#"%#", foo); // if ARC did not retain foo, you could be in trouble
}
That might also be the reason that you don’t see the extra retain when there’s just a single call in your method.
Passing as a parameter does not, in general, increase the retain count. However, if you're passing it to something like NSThread, it is specifically documented that it will retain the parameter for the new thread.
So without an example of how you're intending to start this new thread, I can't give a definitive answer. In general, though, you should be fine.
Even the answer of soul is correct, it is a bit deeper than it should be:
It is retained, because the passed reference is assigned to a strong variable, the parameter variable. This and only this is the reason for the retain/release pair. (Set the parameter var to __weak and what happens?)
One could optimize it away? It would be like optimizing every retain/release pairs on local variables away, because parameters are local variables. This can be done, if the compiler understands the hole code inside the method including all messages sent and functions calls. This can be applied that rarely that clang even does not try to do it. (Imagine that the arg points to a person (only) belonging to a group and the group is dealloc'd: the person would be dealloc'd, too.)
And yes, not to retain args in MRC was a kind of dangerous, but typically developers know their code that good, that they optimized the retain/release away without thinking about it.
It will not increment behind the scenes. Under ARC if the object is Strong it will simply remain alive until there are no more strong pointers to it. But this really has nothing to do with the object being passed as a parameter or not.

Does stringWithFormat create a retain +1 instance?

I'm declaring an ivar of type NSString on a class. To initialize the value of this ivar I use the following code:
NSString *myVar;
-(void)inAnyMethod
{
myVar = [NSString stringWithFormat:#"%#",theValue];
}
Do I have to release this ivar? According to my understanding, it is not my responsibility. But in most cases, strings that I use in this manner cause leaks.
What am I missing?
You do not have to release it, because that is a convenience method that returns an autoreleased object.
The way to know if you are getting something with a retain count of 1 that you will need to release is using the Cocoa naming conventions which say that anything that starts with new, alloc or contains copy in the method name will return a retain 1 object, the others will return autoreleased objects like in this case.
In addition to Oscar Gomez answer, note that when you use class methods (those methods with plus sign that you can find in the documentation and are not included in Oscar Gomez list, e.g. stringWithFormat is one of them), you have not to worry about memory management. If you create your own class method, you should do the same: return an autorelease object.
Regarding your code, it cannot work if you simply assign your ivar to the NSString object (returned from that method). In fact, at some point of your application cycle, the object will be released (it has been put in a pool) and your ivar will not reference any object anymore.
The trick: create a #property with a copy policy or send a copy message like the following:
myVar = [[NSString stringWithFormat:#"%#",theValue] copy];
Copy is normally used when a class has subclasses of mutable type. Otherwise use retain. Once done, you have the possession for that object and you have to remember to release it. If you don't do it you cause a leak.
[myVar release];
P.S. Since Xcode 4.2 there is a new compiler feature called ARC.
Hope it helps.

How do you tell whether you need to release an object?

Can you describe the naming convention difference between a method that returns an object it has allocated for the caller (and that the caller should release), and a method that returns an autorelease object?
If you declare a property with a retain attribute, do you need to release the property before you set it to nil?
What does the #synthesize directive do?
From apple documentation
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”).
Your second two questions are related. All that #synthesize does is to generate additional methods for your implementation file. The arguments to #property (nonatomic, retain) NSString* myString; define the behavior of the generated methods. For example, if you declare a property as retain, the setMyString generated method will retain its argument.
Nonatomic is important because properties, by default, are threadsafe. If you don't need thread safety, you can remove a lot of overhead in your accessor methods.
Finally, the implementation of a retain property is
- (void) setMyString:(NSString*)newString {
[newString retain];
[myString release];
myString = newString;
}
So, saying self.myString = nil effectively releases myString for you. Many people advocate using self.property = nil for retained properties, as opposed to [property release], though I think it just comes down to personal preference.
A good source for memory allocation is listed below by Aaron.
Regarding #synthesize:
Say you have a property P, what you will have to do is write a getter and a setter for it. There are a few common approaches, one of which is that you retain that object when you set that property and release the old value. E.g:
- (void)setP:(PClass *)value
{
[value retain];
[_pInstanceVariable release];
_pInstanceVariable = value;
}
Since this is a very common piece of code, the compiler can automate it for you, if you specify the retain keyword in property declaration and then do the #synthesize in you implementation. The compiler will generate the above mentioned code which means your code will be a lot cleaner without tedious repeating parts.
Same holds true for getters, unless you want something more complex than:
- (PClass *)p
{
return _pInstanceVariable;
}
the #synthesize will do the job
memory allocation information and naming can be found here
http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/ObjectiveC/Articles/ocAllocInit.html
synthesize is documented here
http://developer.apple.com/library/ios/documentation/cocoa/Conceptual/ObjectiveC/Articles/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW17
The apple website has excellent documentation, I would recommend searching there first.