how to create an autorelease object - ios

Is this method create an autorelease object?
- (instancetype)autoreleasePerson {
return [[Person alloc] init];
}
I created an Command Line Tool Project to test this:
int main(int argc, const char * argv[]) {
#autoreleasepool {
{
[Person autoreleasePerson];
}
NSLog(#"did out scope");
NSLog(#"will out autoreleasepool");
}
NSLog(#"did out autoreleasepool");
return 0;
}
And the output is:
2022-02-04 23:22:23.224298+0800 MyTest[8921:4007144] did out scope
2022-02-04 23:22:23.224771+0800 MyTest[8921:4007144] will out autoreleasepool
2022-02-04 23:22:23.224876+0800 MyTest[8921:4007144] -[Person dealloc]
2022-02-04 23:22:23.224948+0800 MyTest[8921:4007144] did out autoreleasepool
The person instance will dealloc when the autoreleasepool drains!
But when I use the same Person class in my iOS APP project:
- (void)viewDidLoad {
[super viewDidLoad];
{
[Person autoreleasePerson];
}
NSLog(#"out scope");
}
The output is:
2022-02-04 23:28:13.992969+0800 MyAppTest[9023:4011490] -[Person dealloc] <Person: 0x600001fe8ff0>
2022-02-04 23:28:13.993075+0800 MyAppTest[9023:4011490] out scope
The person instance released once out of scope!
Why is this so?

It looks like on macOS the default behaviour is to autorelease return values, except for cases where the method name starts with "new", "init" or "copy":
+ (Person *)createPerson {
return [Person new]; // autorelease & return
}
+ (Person *)newPerson {
return [Person new]; // direct return
}
To control this behaviour apply a compiler attribute:
+ (Person *)createPerson __attribute__((ns_returns_retained)) {
return [Person new]; // direct return
}
+ (Person *)newPerson __attribute__((ns_returns_not_retained)) {
return [Person new]; // autorelease & return
}
To check whether a call to objc_autoreleaseReturnValue was added by the compiler, enable Debug -> Debug Workflow -> Always Show Disassembly,
and put a breakpoint inside these methods on return lines. A call to objc_autoreleaseReturnValue should be visible then:
See ARC reference - Retained return values

Both of the results are valid. You should never assume that there is an autorelease in ARC. See the section "Unretained return values" in the ARC specification:
A method or function which returns a retainable object type but does
not return a retained value 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. In the worst case, this may
involve an autorelease, but callers must not assume that the value is
actually in the autorelease pool.
So maybe it's autoreleased, and maybe not (i.e. maybe ARC optimizes it out).
Here, ARC will call objc_autoreleaseReturnValue() when returning from autoreleasePerson, because +alloc returns a retained reference, but autoreleasePerson returns a non-retained reference. What objc_autoreleaseReturnValue() does is check to see if the result of the return will be passed to objc_retainAutoreleasedReturnValue() in the calling function frame. If so, it can skip both the autorelease in the called function, and the retain in the calling function (since they "cancel out"), and hand off ownership directly into a retained reference in the calling function.
objc_retainAutoreleasedReturnValue() is called when ARC will retain the result of a function call. Now, I don't know why in this case calling [Person autoreleasePerson]; will involve a retain of the result, since the result is unused. Perhaps the compiler is treating it as Person temp = [Person autoreleasePerson];, and thus retains and then releases it. This may seem unnecessary, but it is valid for ARC to do it this way. And if ARC does happen to treat it this way internally, then the optimization described above can skip both the autorelease and retain, and it will be simply released in the calling function. Maybe it's doing this in one of your cases and not the other. Who knows why? But my point is that both are valid.
See this article for a more detailed explanation.

Related

Passing an object around increases retain count

iOS, transitioning to ARC. I've observed a curious behavior regarding CF/NS bridging. In the following scenario:
CFStringRef cfs = ComesFromSomewhere();
NSString *ns = (__bridge NSString*)cfs;
the retain count of the string object is 2 at the end. However, in the following:
NSString *ToNS(CFStringRef cfs)
{
return (__bridge NSString*)cfs;
}
CFStringRef cfs = ComesFromSomewhere();
NSString *ns = ToNS(cfs);
the retain count is 3 at the end. What's going on, please? Who holds the extra reference? Is the object being added to the autorelease pool by the mere act of passing it around?
Preemptive response to "don't worry, ARC just works": I'm mixing Core Foundation with Cocoa here, no way around it. This is leak prone. Without the ability to account for the retain counts explicitly, I'm flying blind.
EDIT: it's an artifact of the debug build. In the release build, the retain count under the latter scenario is still 2.
There's a tangible difference between a fragment that leaves large autoreleased objects around and one that doesn't; you don't want the former in a big loop without a pool in the loop body. Helps to know it's an artifact of zero optimization, but still, not cool.
CFStringRef cfs = ComesFromSomewhere();
// retainCount -> 1
NSString *ns = ToNS(cfs);
// ToNS(cfs)
//
// ToNS is not object creating method,
// thus the returned object was automatically autoreleased
// retainCount += 1
// NSString *ns
//
// It's __strong variable, ns variable has an ownership of the object
// retainCount += 1
// retainCount -> 3
The definition of object creating method is a method whose name begins with “alloc”, “new”, “copy”, or “mutableCopy”, of a Objective-C class. See Basic Memory Management Rules - You own any object you create.
In the release build, the retain count under the latter scenario is still 2.
Also compiler can omit to send autorelease message to object if it's eligible.
EDITED
You can use C++ reference to avoid autorelease.
void ToNS(CFStringRef cfs, NSString __strong *& ns)
{
ns = (__bridge NSString*)cfs;
}
NSString *nsstr;
ToNS(cfstr, nsstr);
// retainCount -> 2
EDITTED
NS_RETURNS_RETAINED NSString *ToNS(CFStringRef cfs)
{
return (__bridge NSString*)cfs;
}
NS_RETURNS_RETAINED makes the framework treat the function as an object creating one (which it really is). Cocoa has a name convention that lets you designate a method as an object creator, but the convention only applies to Objective C class methods, not to C style functions and not to C++ class member functions.

Will returning nil in init cause a memory leak?

Will returning nil under ARC in init lead to memory leak, when [super init] was already called, but then returned nil? Is this a legit usage?
- (id)init {
self = [super init];
if (self) {
...
return nil;
...
}
return self;
}
First of all: For Qs referring to ARC never read Apple's documentation, but clang's.
Apple's documentation simply conceals (concealed?) the execution of -init and have wrong examples like that:
id ref = [[Class alloc] init]
You will find there a statement like "+alloc transfers ownership". This is at least misleading, because the return value auf -init and not the return value of +alloc is stored.
clang's documentation is better and more precise by far. Basically they say, that +alloc is an ownership transfer and that -init is ownership consuming and ownership transferring.
http://clang.llvm.org/docs/AutomaticReferenceCounting.html#semantics-of-init
Methods in the init family implicitly consume their self parameter and return a retained object.
So let's have a look to the usual code:
id ref = [Class alloc];
// ref is strong: RC is +1;
id ref = [ref init];
// Three things happen her:
// 1. -init is executed
// 2. The new value is stored
// 3. The old value of ref is lost
// 1. -init is executed
// self is (silently) passed to the receiver
- (id)init
{
// Since self is strong (+1), RC is +2 now
// Since -init is ownership consuming (-1), RC is +1 now
…
return self;
// Since -init is ownership transferring (+1), RC is +2 now
}
// 2. The new value is stored
// The value comes from an ownership transfer method, so the assignment to strong ref is neutral (0), RC is still +2
// 3. The old value is lost (-1), RC is +1
The result is that the object has an RC of +1 and you have one strong reference to it in that code area. Everything is fine. (Of course there is a high potential for optimization, because in most cases neither self nor ref is changed, but let's keep on the regular track.)
Let's change self inside -init:
id ref = [Class alloc]; // Ownership transfer. RC is +1;
id ref = [ref init];
// Three things happen her:
// 1. -init is executed
// 2. The new value is stored
// 3. The old value of ref is lost
// 1. -init is executed
// self is (silently) passed to the receiver
- (id)init
{
// Since self is strong (+1), RC is +2 now
// Since -init is ownership consuming (-1), RC is +1 now
// Let's return nil as in your example
return nil;
// Because nil is returned, virtually the RC of nil is increased. self's RC == +1 is unchanged.
}
// 2. The new value is stored
// The new value is nil.
// However the value comes from an ownership transfer method, so the assignment to strong ref is neutral (0), RC is still +1
// 3. The old value is lost (your old ref and the self while executing -init) (-1), RC is 0
// The old object is dealloced, if you do not have another ref to it. Nothing leaks.
I just checked that in the Instruments - no memory leaks

Shouldn't I use self->iVar = something; instead of iVar = something in my init

In ObjectiveC, recommended idiom of an init method is :
- (id)init {
if (self = [super init]) {
myInstanceVariable = someConstant;
}
return self;
}
This is because, superClass's init might return a different object than the current object, freeing the current object using [self release];
If that happens :
1) After the call to [super init] finishes, won't control return to original object's init method ?
2) And, won't the next line set myInstanceVariable of the original object ( on which, super-class called release) ?
And if this is the case, would changing the line to :
self->myInstanceVariable = someConstant;
help (so that, myInstanceVariable of the object returned by [super init] is set, instead of the original object) ?
1) It will, to do the assignment in the if condition.
2) By the time the myInstanceVariable is set, self already points to the new object, because the assignment in the if condition is done first. In fact the myInstanceVariable assignment is never processed if the assignment in the if condition is not successful.
Btw. as far as I can tell, all the direct calls to myInstanceVariable are resolved to:
self->myInstanceVariable anyway.
EDIT:
Just to address your question in the comments, take a look at this answer:
https://stackoverflow.com/a/1341801/703809

How to release instance variable in ARC - Objective-C

I know the instance variable in ARC are by default __strong. How can I release an instance variable when the containing class is still retained. In the following example v is __strong
and c is allocated when object of A is created some where and retained. I want to release the
c instance variable. How to should I do that?, What should be in releaseC method that will release the c instance variable.
#interface A {
Obj *c;
}
#implementation A {
- (id)init {
if((self = [super init])){
c = [[Obj alloc] init];
}
return self;
}
- (void)releaseC {
//what should be here?
}
}
Obj *c; = [[Obj alloc] init];
- (void)releaseC {
c = nil;
}
You cannot directly control when an object is released BUT you can indirectly cause it to happen. How? Remember what ARC does EXACTLY. Unlike human coding convention, ARC parses your code and inserts release statements AS SOON AS OBJECTS CAN be released. This frees up the memory for new allocations straight away, which is awesome/necessary. Meaning, setting an object to nil, or simply allowing a variable to go out of scope ... something that CAUSES A 0 RETAIN COUNT forces ARC to place its release calls there. It must ... because it would leak otherwise.
- (void)releaseC {
c = nil;
}
c = nil;
But some would argue it isn't productive from an efficiency standpoint. And while the release will be immediate in the sense it isn't any longer usable, the memory may not be freed immediately.
there is no need to release the variable in ARC. it done automatically
You are probably miss understanding what you want to do. I suppose you want to release the variable for memory issues. All you have to do is nil it. Instance variables are pointers to objects. As long as an object is pointed by something it is kept alive. As soon as you dont need something you can "stop pointing at it" and it will be released automagically.
As for the design, I am not so sure why you would have a public method that releases an instance variable. (I'm assuming its public because if it was not you would just nil it without actually having to write a method). If you do indeed intend to be able to release an instance variable from outside the class, I would simply make the Instance variable public and release it from anywhere setting it as nil.

How to determine when the value pointed to by a pointer is nil

I have a situation where troops can attack buildings. Each troop keeps a pointer to its target.
#property (nonatomic, weak) Building *target;
In an update loop, the troops periodically cause damage to their target.
if (_target)
{
if (/*enough time has passed since last attack, attack again*/)
{
[_target attack];
if (_target.health <= 0)
{
[_target removeFromParentAndCleanup:YES]; //Cocos2d
_target = nil;
}
}
}
else /* Find new target */
The problem is:
troop1 deals the blow that fells building1 and moves on to building2
troop2 was attacking building1 but waits until its next attack to determine that building1 is now nil.
I realise the problem is that troop2's pointer has not been set to nil and instead I should be checking that the value of the pointer is nil.
I tried using if (*_target) but was met with the message
Statement requires expression of scalar type
If there a way to achieve this kind of comparison in Objective-C? What other options are there for determining when a value has changed? KVO? Some extensive delegate pattern?
It is the pointer itself that is set to nil when the object it points to is deallocated. if (objectPointer == nil) is always the way to check if an object is nil in Objective-C/Cocoa. If the pointer is not nil, it means the object in question has not in fact been deallocated. If you dereference a pointer to an object, you get a struct, hence the compiler error about needing a scalar value in the if expression.
So, in your case, if if(self.target != nil) is not giving you the result you expect, you should look for remaining strong references to the target (from other objects).
More broadly, as hinted at by trojanfoe's answer, you're relying on ARC's zeroing weak reference behavior for real program logic. In theory this is OK, as (contrary to his initial statement), ARC's zeroing weak behavior is reliable/deterministic. But, it does mean that you have to ensure that targets are always deallocated when they're no longer on the playing field (or whatever). This is a bit fragile. Zeroing weak references are intended as a way to avoid retain cycles (essentially a form of memory leak), rather than as a way to implement logic the way you're doing. The gist of trojanfoe's solution, where you explicitly register and unregister targets as necessary, is probably a more robust solution.
There may be something that I have overlooked here, but to check if the target2 property is nil, just do:
if ( self.target2 == nil ) {
// Something
}
I think you are relying too heavily on the implementation of ARC in that you only know if an object has been removed if the pointer is nil. This is non-portable and can you make any guarantee between the object being released and the pointer becoming nil?
Instead, use a central dictionary of objects, mapped against their unique ID and store just this unique ID rather than the object pointer itself. In this example I'm using a NSNumber for the key using an incrementing integer, but there are probably better keys that can be used. Also Object is the base class of any object you want to store in this dictionary:
// Probably ivars in a singleton class
unsigned _uniqueId = 1;
NSMutableDictionary *_objects;
- (NSNumber *)addObject:(Object *)object
{
NSNumber *key = [NSNumber numberWithUnsignedInt:_uniqueId++];
[_objects setObject:object forKey:key];
return key;
}
- (void)removeObjectForKey:(NSNumber *)key
{
[_objects removeObjectForKey:key];
}
- (Object *)getObjectForKey:(NSNumber *)key
{
return [_objects objectForKey:key];
}
And in your target, simply store the building key:
#property (strong) NSNumber *buildingKey;
and get the building via the methods provided:
Building *building = (Building *)[objectDictionary objectForKey:buildingKey];
if (building != nil)
{
// building exists
}
else
{
// building does not exist; throw away the key
buildingKey = nil;
}
Since target is a weak reference, your code should work "as-is", assuming that [_target removeFromParentAndCleanup:YES]; removes all strong references to the target.
When the last strong reference is removed, all of the weak properties pointing to it will automatically be set to nil. If they are not automatically set to nil, then there is still a strong reference to the target somewhere.
Find and remove that reference, and this will work fine.

Resources