override retain/release under ARC - ios

I have an ARC enabled application that using a MRC(non-ARC) static library. In the static library, retain/release are overridden to provide some custom weak ref/cache behavior ([super retain/release] is called of course). The problem is that since retain/release are not allowed in ARC-enabled code, is it OK to use classes that override retain/release in ARC-enabled code? For now it seems to be working well, but I am not sure if this relies on undefined behavior which may break in the future.
Also what is the reason to forbid overriding retain/release? Is it because some special optimization was done by the compiler that bypasses the message binding process to speed up the method call? I know that _objc_storeStrong calls are generated by the compiler that do the reference counting, so does this mean that the overridden retain/release are not guaranteed to be called under ARC?

As long as the classes are compiled without ARC (which you can control on a file by file basis; go to Build Phases and add -fno-objc-arc as a flag to any file that should be compiled MRR in an otherwise ARC'd project), then the MRR compiled classes can override retain/release/autorelease to their heart's content.
Retain/release/autorelease are verboten under ARC because ARC is designed to handle all of the memory management for you at compile time while also forcing you to separate memory management from other roles that seemingly can be piled onto memory management, but really don't belong there.
For example, the most typical override of release involves checking the retainCount and, if it is 2, then the transition to 1 means "put this object back into a cache for later retrieval" whereas the cache is responsible for the final retained reference to the object.
It works, but it is horribly fragile and there are better solutions that do not involve colluding caching with memory management.

overriding of retain/release is incorrect. But if you need it:
-(id)retain
{
NSIncrementExtraRefCount(self);
return self;
}
-(void)release
{
if(NSDecrementExtraRefCountWasZero(self))
{
NSDeallocateObject(self);
}
}
-(id)autorelease
{ // Add the object to the autorelease pool
[NSAutoreleasePool addObject:self];
return self;
}
I haven't tested them for ARC. And an original article:
link

Related

obejective c - Portential leak of an object stored into

I am trying to Run the code but its reporting the memory leaks when using static analyzer. on this line as Potential leak of an object stored into 'encodedData'
return encodedData;
use __bridge_transfer
Using __bridge_transfer ensures that ARC will release the object for you. Without __bridge_transfer, you must release the returned object manually.
__bridge,__bridge_transfer keywords are used to tell to ARC system how to handle your non-objective-c pointers. In essence, if you use __bridge, you are telling to ARC not to deal with the ownership of the converted pointer because you will free it from non-objective-c code, most likely with a free() or a CFRelease... type function. __bridge_transfer, on the other hand, transfers the ownership to ARC and ARC will free your objective-c (and thus also the original non-objective-c) object via the standard release mechanism when the references to that object hits zero.
Reference
The problem is that you create your string using CoreFoundation methods. And by default ARC doesn't know what to do with it. So, you're responsible for either manually managing the memory for the created object (using CFRelease for example), or handing it over to ARC.
The later is, I believe, the way to go in your case. You can do it, as others have already noted, using __bridge_transfer.

convert non-ARC to ARC

I was working on non-ARC based project which was very old, and added some new UIViewControllers which are based on ARC (can do it by setting -fobjc-arc flag in build phase).
As being mixed use of ARC and non-ARC, sometimes memory leak occurs because forgotten to release somewhere in non-ARC code, and switching from here to there can cause this.
Thus, I have decided to convert non-ARC project to ARC project and do it by following;
Convert non-ARC to ARC project without recreate it
And just removed dealloc, viewDidUnload function contents by removing release or autorelease related things.
After successfully done it, it seems okay to working on but sometimes crashes like message sent to deallocated instance.
I could find what is the reason of that crashes and can be fixed.
What I want to know from here is;
When converting, is there any specific guide or rules to do this rather than simple remove of release, autorelease related statements?
Any input will be very appreciated!
Automatic Reference Counting (ARC) is a compiler feature that provides automatic memory management of Objective-C objects.
Refer this url :-
https://developer.apple.com/library/ios/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html
As mentioned above, in ARC, we need not add release and retain methods since that will be taken care by the compiler. Actually, the underlying process of Objective-C is still the same. It uses the retain and release operations internally making it easier for the developer to code without worrying about these operations, which will reduce both the amount of code written and the possibility of memory leaks.
There was another principle called garbage collection, which is used in Mac OS-X along with MRR, but since its deprecation in OS-X Mountain Lion, it has not been discussed along with MRR. Also, iOS objects never had garbage collection feature. And with ARC, there is no use of garbage collection in OS-X too.
Here is a simple ARC example. Note this won't work on online compiler since it does not support ARC.
#import <Foundation/Foundation.h>
#interface SampleClass:NSObject
- (void)sampleMethod;
#end
#implementation SampleClass
- (void)sampleMethod
{
NSLog(#"Hello, World! \n");
}
- (void)dealloc
{
NSLog(#"Object deallocated");
}
#end
int main()
{
/* my first program in Objective-C */
#autoreleasepool{
SampleClass *sampleClass = [[SampleClass alloc]init];
[sampleClass sampleMethod];
sampleClass = nil;
}
return 0;
}
get the following output...
demo :- Hello, World!
demo :- Object deallocated
xcode could do the most of the conversion alone. in most cases its enough to remove this statements. you need to check the property declarations #property(nonatomic, weak/strong/copy).
Here is a litte tutorial:
https://objectpartners.com/2013/07/17/converting-an-ios-project-to-use-arc-automatic-reference-counting/
Just follow the things
STEP 1: Go to Project Target and click Build Phases
STEP 2: Click Compile Sources.Where you can see the all the .m files
STEP 3: Double click that,white box will appear with cursor.
STEP 4: give -fno-objc-arc in where the non arc files are.

__autoreleasing for return value in ARC Objective-C

According to Cocoa's "Create Rule" a method that returns a newly instantiated object must begin with either new, create, or copy if ownership is transferred to the caller.
Let's say I have a class that implements a factory method called (NSObject *)getCorrectObject.
This method will return a new instance of the correct subclass of the callee (determined by some internal state of the callee). Technically this method does not follow the "Create Rule" and could lead to memory leaks in non-ARC environments.
Would it be possible to instead use (NSObject *__autoreleasing)getCorrectObject to avoid using new or create in this case?
In non-ARC I would return an autoreleased object, but I'm not entirely sure if __autoreleasing works for anything other than In/Out parameters.
According to Cocoa's "Create Rule" a method that returns a newly instantiated object must begin with either new, create, or copy if ownership is transferred to the caller.
This isn't called the Create Rule (and isn't correct). The Create Rule is a Core Foundation rule related to the words Create and Copy. Cocoa has a different rule related to “alloc”, “new”, “copy”, or “mutableCopy”.
Let's say I have a class that implements a factory method called (NSObject *)getCorrectObject.
Then it would be incorrectly named. Starting a method with get indicates that it returns a value by reference. The correct signature would be:
+ (BOOL)getCorrectObject(NSObject**)result;
This method will return a new instance of the correct subclass of the callee (determined by some internal state of the callee). Technically this method does not follow the "Create Rule" and could lead to memory leaks in non-ARC environments.
That is not based on whether it is a new instance. It's based on whether it includes an unbalanced retain.
Methods that begin with “alloc”, “new”, “copy”, or “mutableCopy” should return an object with one unbalanced retain. Other methods should return an object that has an equal number of retain and autorelease attached to it.
If for some reason you have to violate these naming rules (and you really don't want to violate these rules), the correct way to indicate it to ARC is by using NS_RETURNS_RETAINED (see Foundation/NSObjCRuntime.h for all the macros). This only assists ARC in correctly fixing your memory management when dealing with mixed ARC/Retain code in cases where it is impossible to fix your incorrect naming. Pure ARC code doesn't need this; it'll balance out either way. Pure Retain code won't be helped by this. The caller has to do the right thing (and so has to just know that you did it wrong and compensate).
Note that as long as you're using ARC throughout the project (and you really, really should be), most of this won't matter a lot in practice. ARC will balance everything out for you pretty much no matter what you name things, since you're not in charge of adding the retains, releases, and autoreleases anyway.

XCode - Writing static analysis friendly code

I'm starting to make use of static code analysis to find memory management problems in my code. I've found it very useful, but there are a couple of bits of code I've written that I'm sure aren't causing memory leaks (instruments doesn't report any) but are being reported by the analyser. I think it's a question of me writing the code in a non-friendly manner. Here's an example
for (glyphUnit *ellipsisDot in ellipsisArray) {
CGPathRef newDot = CGPathCreateCopyByTransformingPath(ellipsisDot.glyphPath, &ellipsisTransform);
CGPathRelease(ellipsisDot.glyphPath); // Incorrect decrement of the reference count of an object that is not owned at this point by the caller
ellipsisDot.glyphPath = newDot;
}
where glyphUnit is a simple custom class that has a GCPathRef as a property, which the custom class releases in its dealloc method. So in this loop I'm transforming the path and storing it in anewDot then releasing the original glyphPath so I can assign the newly created one to it. I can see how this is getting the code analyser confused, with it giving a message I'm decrementing an object I don't own. Is there another way swap in the new path without confusing it?
It should be,
for (glyphUnit *ellipsisDot in ellipsisArray) {
CGPathRef newDot = CGPathCreateCopyByTransformingPath(ellipsisDot.glyphPath, &ellipsisTransform);
ellipsisDot.glyphPath = newDot;
CGPathRelease(newDot);
}
You are creating newDot by doing CG CreateCopy operation and you need to do release on that variable. So the analyser is warning that you dont own ellipsisDot.glyphPath param to release it. You are trying to release the wrong param here. When you put that release statement in the second line as in question, ellipsisDot.glyphPath and newDot are pointing to two separate instances. Only on the third line, you were assigning newDot to ellipsisDot.glyphPath.
It turns out that I forgot about defining setters in my custom glyphUnit class. Being in the ARC world for objects and used to synthesizing my methods I had forgotten the need to manage my retain counts for core foundation references. I had been releasing glyphPath in my dealloc, but was not using a setter method. As #Sven suspected, I was simply using a synthesized assign and making up for my lack of setter method by doing some less than intuitive releases in my code snippet above. I've now added a setter method as below to glyphUnit
- (void)setGlyphPath:(CGPathRef)newPath
{
if (_glyphPath != newPath)
{
CGPathRelease(_glyphPath);
_glyphPath = CGPathRetain(newPath);
}
}
After adding this, I now had the necessary retain in place to change my code snippet to the one #ACB described and my code ran nicely (without it, it obviously caused an EXC_BAD_ACCESS).
Kudos to #Sven for inferring my mistake and setting me in the right direction... no pun intended.

Is there a way to use the ARC migration tool on a per-file basis only?

I've discovered some inconsistencies when using the ARC migration tool multiple times on the whole project.
For example:
- (void)dealloc {
[ivar release], ivar = nil;
}
The first iteration convertis this to:
- (void)dealloc {
ivar = nil;
}
The second iteration gets rid of -dealloc alltogether. Assuming that it makes no sense to set ivars to nil in -dealloc since ARC does that anyways automatically, it's strange that ARC leaves the ivar = nil in the first place.
To prevent possibly strange bugs, is there a way to use the ARC migration tool only for one special file rather than the whole project?
When you choose Edit > Refactor > Convert to Objective-C ARC, a sheet opens with a list of your project's targets. Click the disclosure triangle next to a target to show a list of source files. From there you can choose the files to convert to ARC.
I don't believe so.
You don't have to do much to "convert" a project to use ARC support.
Remove all dealloc, release, and nil (where needed) calls.
No strange bugs should occur after the conversion, since the compiler takes care of everything for you and not buggy XCode.

Resources