CGPDFDocumentRef and autorelease - autorelease

Is there an autorelease analogous method for CGPDFDocumentRef instances? I'd like to apply this before returning an instance I created. Or can I only do CGPDFDocumentRelease(...) before returning (which is surely wrong)?
Since I created the CGPDFDocumentRef I'd like to take care with its release.

The best thing you can do is to write an Obj-C wrapper around CGPDFDocumentRef and release the CGPDFDocumentRef on your wrapper's dealloc method so the rest of your code will retain/release your wrapper as with ay other NSObject derivate and once the wrapper's retain count reaches zero the CGPDFDocumentRef will be released on the wrapper's dealloc method and consequently freed from memory as it's retain count never got past 1.

Related

Cocoa example - Why there is NO need to retain or release messages

I'm new to Objective-C and cocoa. In the guide provided by Apple for Cocoa, there is a confusing example in memory management:
Suppose you want to implement a method to reset the counter. You have a couple of choices. The first implementation creates the NSNumber instance with alloc, so you balance that with a release.
- (void)reset {
NSNumber *zero = [[NSNumber alloc] initWithInteger:0];
[self setCount:zero];
[zero release];
}
The second uses a convenience constructor to create a new NSNumber object. There is therefore no need for retain or release messages
- (void)reset {
NSNumber *zero = [NSNumber numberWithInteger:0];
[self setCount:zero];
}
I am not sure why the object is created with 'new' instead of 'alloc & init' does not need to be retained/released. My understanding is that both are doing the same thing, except that with 'alloc & init' we can use custom checks and initialisation.
Many thanks.
The second example returns an auto released object. The code for the convenience constructor probably looks like this, at least when it comes to replicate the functionality.
+ (NSNumber *)numberWithInteger:(NSInteger)integer
{
NSNumber *number = [[NSNumber alloc] initWithInteger:integer];
return [number autorelease];
}
Autorelease is a way to defer sending a release method to an object while not delegating ownership of the object to the caller of the constructor. This is an important concept, because the naming conventions require you to not return ownership of an object unless your method starts with copy new alloc or retain. However, since you can't return an owned object, you would have to call release on it in your convenience constructor, which would then lead to you returning a deallocated object. So, autorelease allows you to return an un-owned object to the caller which will receive an actual release method later (when the current autorelease pool gets drained).
Autorelease methods are collected in so called autorelease pools, which are thread local quasi linked lists (they are not implemented as linked lists, but they do work like they were) and that just collect autoreleased objects. Objects can be added to them multiple times by calling, once for each autorelease method they receive. When the pools is drained or destroyed, all objects it contains will receive a release message. By default, the system will provide you with an auto release pool, at least on the main thread, but you can create your own ones using this code (which is also used in every main method, if you take a look):
#autoreleaspool
{
[foo autorelease]; // foo will receive a `release` method at the closing brace
}
By convention, all methods who's name start with "alloc" or "copy" or "new" increase the retain count by 1.
All other methods do not change the retain count. Since "numberWithInteger" doesn't start with "alloc" or "copy" or "new" it returns an object with a retain count of 0. But instead of setting it to 0 immediately (which would never work), it sets the retain count to 1 and then schedules it to be dropped down to 0 at some point in the future (usually when the event loop is idle, but you can manually make it happen sooner), using an "autorelease pool".
The only exception to the alloc/copy/new naming convention is, of course, the actual "retain" and "release" and "autorelease" methods, which increase/decrease the retain count or schedule it to be decreased later.
It is not a language feature, it's just a coding practice. Every method starting with "alloc" and "copy" and "new" sets retain to 1, everything else sets it to 1 but schedules it to be dropped to 0 later.
Of course, if you are using ARC, and you should absolutely be using ARC, then you don't have to worry about any of this because the compiler will find the last line of code that uses the object, and will insert a line of code after it to free up the memory. This leads to faster code, because the autorelease mechanism is a bit slow and sometimes uses too much RAM.
When ARC is enabled, none of those rules apply. The compiler ignores all your memory management code (or tells you to delete it), and writes it's own code. It's not actual garbage collection, it's just manual memory management that is generated by Xcode instead of written by hand.
Objects that are created with +alloc -init are returned with a retain count of +1, meaning that you have to call -release when you are done with this object. This is the same with +new , which is just a simple combination of [[ alloc] init], eg.
NSDate *date = [NSDate new]; // I will have to send -release at some point
As a convention, methods that contains init, new, create and copy will transfer ownership to you, meaning that you need to send -release at some point. Other methods will not transfer ownership, meaning that the object is autoreleased, ie. it has a short lifetime and is scheduled to be dealloced in the future. If you want this object to stick around, you will need to explicitly take ownership by sending -retain.
NSDate *date = [NSDate date]; // I won't have to send -release
// But this object will be dealloced soon
// so if I want it to stick around, I will need to retain it
This convention is not enforced by the language.
It is also useful to remember that this convention expands beyond the Objective-C part of the SDK, it is also the case in CoreGraphics and all C frameworks provided by Apple, and most third-party frameworks make use of this convention.
CGContextRef context = UIGraphicsGetCurrentContext(); // I won't have to release this context
CGImageRef result = CGBitmapContextCreateImage(context); // I will have to release this image
/* ... */
CGRelease(result);
As for your example : -numberWithInteger: does not contain either init, new, create or copy. So you don't need to -release it when done.

ARC, non-ARC, and inheritance

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.

Which increases the retain count: alloc or init?

When we need create an object and take ownership of it we write
NSObject *someObject = [[NSObject alloc] init];
After that someObject's retain count will be equal to 1. Which method increases the count, alloc or init, and where in Apple's docs is this behavior described?
After that someObject's retainCounter will be equal 1. Question is
which method increases retainCounter alloc or init and there in Apple
docs this behavior is described?
"Neither", "Both", or "One or the Other" would all be correct answers. A better answer would be "it is an implementation detail and you need to focus on the general, non implementation dependent rule".
First, ditch the notion of absolute retain counts. It is a useless way to think of this.
+alloc returns an object with a +1 retain count. Whatever is returned by +alloc must be -released somewhere. Wether or not the actual retain count is 1 or not is entirely an implementation detail and it often is not 1 for many of Apple's classes.
-init consumes the retain count of the messaged object and produces an object of retain count +1 (not 1, but "plus 1"); the result returned from init must be released to be managed correctly.
More often than not, init simply calls return self; without internally manipulating the retain count. This preserves the above rule.
Sometimes it doesn't, though, which is why you always have to have self = [super init] (checking the return value, of course) in your initializers and why you should never do something like Foo *f = [Foo alloc]; [f init];.
The alloc method does the actual allocation therefore will generally* increase the retain count. The init is responsible for initializing the object after the allocation.
*There are exceptions to this in several foundation classes as well as 3rd party code (class clusters for example) but you are always responsible for calling release/autorelease after a call to alloc in manual memory management
Well, so it's kinda complicated. For almost all cases, +alloc increments the retain count, and -init does nothing to the retain count.
But occasionally, -init will want to return a pre-existing object rather than initializing the blank one alloc passed it. (NSNumber does this, for example.) In that case, -init would release self, then return a new object with a +1 retain count.
In the ARC documentation, they say that -init is a method which "consumes" its recipient, and returns a retained object. Often, that just means init does nothing to the retain count. But sometimes, -init is actually doing some retaining.
If this is confusing to you, don't worry about it.
As I said, +alloc is the one doing the retaining. -init is guaranteed to return a retained object, but doesn't itself do any retaining in most cases.

Objective-C retain counts in dealloc

I'm seeing something fairly strange here, I've got breakpoints set in various dealloc methods in my app, and on inspection, the retain counts of the object self varies from 1 to 0. When dealloc is called, will the retain count of the object be set to 0 already?
I'm using print (int) [self retainCount] in the console to test this.
The 0's seem to only appear in the dealloc of my NSOperation's that are being run in an NSOperationQueue.
Any idea why this is?
The retain count of your object doesn’t matter in -dealloc. For practical purposes, it’s undefined.
The normal implementation of reference counting uses an external reference count for values greater than zero – see NSIncrementExtraRefCount() and NSDecrementExtraRefCountWasZero(). When the extraRefCount count is zero, the refCount is one. When NSDecrementExtraRefCountWasZero() is called and the extraRefCount is already zero, it returns YES and -dealloc is called. Except when dealing with the return value of NSDecrementExtraRefCountWasZero() there is no way to distinguish a refCount of one from a refCount of zero.
That NSOperation gets a zero refCount suggests it’s not using the normal mechanism.
I'm not quite sure how objective-c handles this but if the dealloc method is being called, it means the retain count has hit 0 so object should be released from memory. There's no other way around it, if your object has a retainCount of 2 and you call [obj release] once, your dealloc method will never be called - so if your breakpoints are being hit and written to the Log then you can be sure that the object is on its way to being destroyed
Remember that your object will subclass NSObject so you should be putting a [super dealloc] call in your dealloc method too.

difference between drain, release,dealloc and retain in Objective-C/

Hi i want to know the difference between drain, release,dealloc and retain in Objective-C.
retain increase the reference count on an object
release decreases the reference on an object
drain is used in place of release on ONLY for NSAutoreleasePool objects due to some arcana related to the Objective C garbage collection
dealloc is called by the system once the retainCount of an object hits 0. It is where you clean up various things your object has (like a deconstructor or finalizer). You should NEVER call it directly, except for calling [super dealloc] at the end of your dealloc routines.
You really should just read through Apple's memory management documentation.