Swizzling methods, that implicitly return a retained object under ARC - objective-c

For example, lets consider following code under ARC:
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#implementation NSDate (MyEvilHack)
+ (void)load {
Method originalMethod = class_getInstanceMethod(self, #selector(copyWithZone:));
Method newMethod = class_getInstanceMethod(self, #selector(myCopyWithZone:));
method_exchangeImplementations(originalMethod, newMethod);
}
- (id)myCopyWithZone:(NSZone *)zone {
id result = [self myCopyWithZone:zone];
// do customization
return result;
}
#end
In this code, original copyWithZone: method is implicitly returns a retained object, because it belongs to copy method family. But my myCopyWithZone: is not.
I expect crash, but looks like this code works normally. Of course, I can rename my method to avoid confusion. But I am curious what exactly happens under the hood?

As you know, ARC examines the method name, applies the Cocoa memory management naming conventions, and determines how a method should behave. For a method that it's compiling, it makes the method obey those conventions. For a method that it's calling, it assumes the method obeys those conventions.
(One can override the conventions using function attributes, but ignore that for now.)
When ARC is compiling your -myCopyWithZone:, it determines that such a method should return a +0 reference. When it encounters the call to (apparently) -myCopyWithZone:, it assumes that method returns a +0 reference. Since those match, it should neither retain or release anything. (Well, it may temporarily retain the result, but it must balance that with an autorelease.) As a result, the actual +1 reference returned by the original -copyWithZone: survives to the caller and the caller was expecting a +1 reference, so that's all good.
You could probably cause ARC to screw up by calling a different method (which would not be effectively renamed by swizzling) that returns a +1 reference. If it were to return that and since the current method is expected to return a +0 reference, it would autorelease it. The caller would not retain it because it was expecting a +1 reference. So the object would be prematurely deallocated, likely leading to a crash.

Related

Not expected strange behaviour of ARC during deallocating instances

I'm refreshing my knowledge in Objective-C world and now I'm testing some ARC with __weak local variables.
I have very simple code with such files GAObject.h
#import <Foundation/Foundation.h>
#interface GAObject : NSObject
+ (instancetype)create;
#end
Implementation of this interface GAObject.h
#import "GAObject.h"
#implementation GAObject
+ (instancetype)create {
return [[GAObject alloc] init];
}
- (void)dealloc {
NSLog(#"GAObject is being deallocated");
}
#end
So there is simple factory method create and I override dealloc method to watch if objects was deallocated when I expecting this. Now the funny part main.m:
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "Learning/GAObject.h"
int main(int argc, char * argv[]) {
#autoreleasepool {
NSLog(#"1");
NSObject *o1 = [[GAObject alloc] init];
NSObject * __weak weakObject = o1; // Line 1
o1 = nil; // o1 should be deallocated because there is no strong references pointing to o1.
NSLog(#"2");
NSObject *o2 = [GAObject create]; // Line 2
o2 = nil; // o2 should be deallocated here too but it is not deallocated. Why?
NSLog(#"3");
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
In the output I see this:
1
GAObject is being deallocated
2
3
But My expecting results should be:
1
GAObject is being deallocated
2
GAObject is being deallocated
3
If I create o2 using factory method then I have this behaviour. If I create o2 like this: [[GAObject alloc] init] then I get expected output. Also I noticed that when I remove line with weakObject I also get expected results. Can somebody explain it?
It's because ARC still respects the Cocoa memory-management naming conventions.
Under those conventions, a method named +create returns a +0 reference. So, in the implementation of the method, ARC has to balance the +1 reference of the alloc/init pair by autoreleasing the reference.
Then, in main(), ARC has to assume it has received a +0 reference from the call to +create. If it needed the reference to survive the current scope, it would retain it, but it doesn't so it doesn't. The second GAObject instance would be deallocated when the autorelease pool is drained, but that will never happen because UIApplicationMain() never returns. If you use two separate autorelease pools, one for the code dealing with GAObjects and another for the call to UIApplicationMain(), I expect you'll get the result you expect.
If ARC did need the reference to survive, it would retain at the assignment to the strong variable and release when that variable is assigned a new value (including nil) or goes out of scope. ARC has a run-time optimization that an autorelease-return in a callee and a retain of the returned value in the caller cancel each other out, such that the object is never put in the autorelease pool. If this were happening, you would get your expected results.
In fact, my expectation is that the compiler initially would emit that retain and release even in your case, but a subsequent pass removes redundant retains and releases. Your example has the release immediately follow the retain, which makes it even more obvious to the compiler that the pair are redundant. Because the retain gets removed, that autorelease optimization doesn't kick in, and a reference to your object really does get put into the autorelease pool.
If your method were named +newGAObject, then the naming conventions would mean it returns a +1 reference and this all changes. (Of course, as it stands, your +create method is just doing the same thing as the built-in +new method, except for the autorelease that ARC has to add. So, you could just change the calling code to use +new and that would also sidestep this issue.)
I don't know why the line with weakObject matters. But, since the behavior you're seeing depends on certain optimizations, anything that could tweak the optimizations can change the outcome.

Accessing NSObject's (superclass) version of allocWithZone while bypassing overriding (subclass) version of allocWithZone

In iOS Programming Book from Big Nerd Ranch (3rd ed) they say on pg.194
..a knowledgeable programmer could still create an instance of BNRItemStore via allocWithZone:, which would bypass our sneaky alloc trap.To prevent this possibility, override allocWithZone: in BNRItemStore.m to return the single BNRItemStore instance.
+(id) allocWithZone:(NSZone *)zone
{
return [self sharedStore];
}
This statement seems confusing to me. Doesn't this following code not prove this wrong in a way-
#import <Foundation/Foundation.h>
#interface BNRItemStore : NSObject
+(BNRItemStore *)sharedStore;
+(id)retrieveObject;
#end
#implementation BNRItemStore
+(BNRItemStore *)sharedStore{
static BNRItemStore *sharedStore=nil;
if (!sharedStore){
NSLog(#"Test2");
sharedStore= [[super allocWithZone:nil] init];
}
NSLog(#"sharedStore-> %#",sharedStore);
return sharedStore;
}
+(id)allocWithZone:(NSZone *)zone{
NSLog(#"Test1");
return [self sharedStore];
}
+(id)alloc{
NSLog(#"Retrieving super object");
NSLog(#"%#", [super allocWithZone:nil]);//Bypassing the subclass version of allocWithZone.
return [super allocWithZone:nil];
}
#end
int main(){
[[BNRItemStore alloc] init]; //the alloc message triggers a call to the subclass (overriding) version of +(id)alloc method
}
The output is:
2013-10-18 18:24:40.132 BNRItemStore[381:707] Retrieving super object
2013-10-18 18:24:40.134 BNRItemStore[381:707] BNRItemStore:0x7f8c72c091e0
If the call [super allocWithZone:nil] inside of subclass 'alloc' method would have triggered a call to subclass allocWithZone,the console would be logging "Test1" and "Test2" and finally would lead to static pointer getting allocated. But this did not happen.
This means that if we directly call [NSObject allocWithZone:nil] or [super allocWithZone:nil], the message would not redirect to the overriding version (subclass version) of allocWithZone but will give direct access to NSAllocateObject() function which does the actual allocation.
The code of +(id)allocWithZone in NSObject must look somewhat like this-
+(id)allocWithZone:(NSZone *)zone{
return NSAllocateObject();
}
Had this implementation(NSObject's allocWithZone:) included something like [self allocWithZone], the message dispatch mechanism would have included the subclass version of allocWithZone which would then make us go through the "sneaky" trap involving a call to sharedStore method.Following is the case that I'm talking about. Now if this were the case the code would definitely have infinite-looped.Clearly this isn't the case.
+(id)allocWithZone:(NSZone *)zone{
if([self allocWithZone:zone]) //this would trigger a call to subclass ver. which would call sharedStore method which would then have [super allocWithZone:nil].Infinite Loop
return NSAllocateObject();
}
So can someone clear up this query about this so called "sneaky" trap. Was the trap meant for blocking anyone from instantiating separately .i.e not being able to use NSObject's allocWithZone except when inside of sharedStore method ? Pls clarify..
The first, most important lesson here is that you should not override +allocWithZone:. I know the BNR book describes it (and the BNR book is generally very good). You shouldn't do it. I know that Apple includes some example code that does it. You shouldn't do it. (And Apple notes in the explanation that it is rare to need this.) Singletons should be created with the dispatch_once pattern.
You don't give the initial code, but I suspect that their example code overrides alloc, but not allocWithZone:. They're simply saying that if the caller uses allocWithZone:, it won't go through alloc, so they've also overridden alloc to catch that. (Of course the right answer would be just to override allocWithZone: and not alloc. But you shouldn't be overriding these methods in any case.)
EDIT:
I believe you are misunderstanding what "our sneaky alloc trap" means here. The author is assuming the following code at this point in the text:
#interface BNRItemStore : NSObject
+(BNRItemStore *)sharedStore;
#end
#implementation BNRItemStore
+(BNRItemStore *)sharedStore{
static BNRItemStore *sharedStore=nil;
if (!sharedStore){
sharedStore = [[super allocWithZone:nil] init];
}
return sharedStore;
}
#end
That's it; no +alloc overrides at all. It then points out "to enforce the singleton status…you must ensure that another instance of BNRItemStore cannot be allocated." (*)
The author goes on to suggest that we might enforce the singleton status by overriding +alloc, but immediately notes that this is insufficient, since the caller can use +allocWithZone: instead. Since it is documented that [NSObject alloc] calls [self allocWithZone:], it is necessary and sufficient to override +allocWithZone: and unnecessary and insufficient to override +alloc.
What you've done in your code is demonstrate that you can modify BNRItemStore to call [super allocWithZone:] in +alloc. That is not the point. If you can modify BNRItemStore, you could also make it a non-singleton. The point is whether an outside caller (main() in your case) can bypass the singleton instantiation, which she cannot. (**)
(*) The point it doesn't make at this point, and probably should, is that it is generally a bad idea to "enforce the singleton status" by quietly returning a singleton when the callers asked you to allocate a new object. If you need to enforce the singleton status, it is better IMO to do so with an assertion in init, since the request for a second allocation represents a programming error. That said, there are times when "transparent" singletons of immutable objects can be useful for performance reasons, such as the special singletons NSNumber provides for certain common integers, and this technique is appropriate in those cases. (By "transparent," I mean that the singleton-ness is an implementation detail that the caller should never worry about. This presumes at a minimum that the object is immutable.)
(**) Actually she can if she is determined to do so. She could always call NSAllocateObject() herself, bypassing +alloc entirely, and then call -init. This would of course be insane, and there is no reason to "protect" her from herself in doing this. It is not the job of an SDK to protect itself from the caller. It is only the job of an SDK to protect a caller from likely mistakes. The caller is never the enemy.
i'm not sure if this quite answers your question or not, but "allocWithZone:" was used back in the day to be able to partition the memory allocated. apple has since moved away from this concept and expects everything to be allocated in the same heap space. "allocWithZone:" does not even function the way it used to, and apple specifically says not to use it.

Can anyone explain the synthesize process when using Objective-C?

I realize that it automatically creates a setter & getter for you but I'm uncertain how the setter actually "looks".
Also, why is it recommended that we say #synthesize someObject = _someObject; instead of just #synthesize someObject;?
Easy bit first: you don't need to #synthesize at all any more. If you have an #property and you don't synthesise it then one is implied, of the form #synthesize someObject = _someObject;. If you left off the = _someObject then you would have the same thing as #synthesize someObject = someObject;. The underscore version is therefore preferred because Apple has swung back to advocating underscores for instance variables and because it's consistent with the implicit type of synthesise.
The exact form of setter and getter will depend on the atomic, strong, unsafe_unretained, etc flags but sample nonatomic strong setter, pre-ARC is:
- (void)setProperty:(NSString *)newPropertyValue
{
[newPropertyValue retain];
[_property release];
_property = newPropertyValue;
}
Note the retain always occurs before the release. Otherwise the following (which you would arrive at in a roundabout fashion rather than ever writing directly):
self.property = _property;
Would lead to _property potentially being deallocated before it was retained.
A sample getter (also pre-ARC) is:
- (NSString *)property
{
return [[property retain] autorelease];
}
The retain ensures that the return value will persist even if the object it was queried from is deallocated. The autorelease ensures you return a non-owning reference (ie, the receiver doesn't explicitly have to dispose of the thing, it can just forget about it when it's done). If the thing being returned is immutable but the instance variable is mutable then it's proper form to copy rather than retain to ensure that what you return doesn't mutate while someone else is holding onto it.
Check leture 3 of iPad and iPhone Application itunes
_someObj replace a memory location for store your object(a pointer).
Xcode 4 auto #synthesize anyObject = _anyObject; -> So you don't need to write #synthesize anymore.
If you have some other object or _anyMemoryLocation write before in your.m file, you can use #synthesize yourObj = _anyMemeryLocation if you don't want rewrite all name in your.m file.
Setter and getter 2 methods use to set or get your object's value outside or inside your class:
-(void)setObject:(ObjectType *) object;
-(void)getObject:(ObjectType *) object;
The key nonatomic auto generate setter and getter for you.
If you want to implement more method went setObject, you can rewrite it in your.m file
-(void)setObject:(ObjectType *) object{
_object = object; //rewrite setter can done anywhere in your.m file
//Add more method
}

In ARC, why is self in init methods a consumed parameter?

I want to understand ARC, and I'm reading this:
http://clang.llvm.org/docs/AutomaticReferenceCounting.html#consumed-parameters
It says that a consumed parameter is retained before the call, and released at the end of the function (inside the function body). It then says that init... methods are effectively marked with ns_consumes_self. I don't see the point.
Foo *foo = [[Foo alloc] initWithWhatever: x];
So alloc returns an object with a retain count of 1, right? Now it is retained again before going into init, and then released at the end of init, so we're back at 1. Why is it designed like this? When I think about what the typical init looks like, I get more confused.
self = [super init];
if (self) { ... }
return self;
So alloc returns an object with a retain count of 1, right? Now it is
retained again before going into init, and then released at the end of
init, so we're back at 1. Why is it designed like this?
Probably because initializers are free to return a pointer to a different object than the one that self points to initially. An -init method can say: I don't like this object, I think I'll substitute a different one and that's perfectly OK. Before ARC, such an initializer would explicitly release self (even though it never retained it) and then assign some other pointer to it. Presumably, the ns_consumes_self directive will take care of releasing the object that was passed into the initializer even if self is changed to point to some other object inside the method.
When I think about what the typical init looks like, I get more confused.
It's a good bet that the behavior is there to cover cases that don't look like a typical -init method. Modifying self isn't exactly typical, it's just permissible.
Why shouldn't it be that way? Calls to -init are meant to return a given object with a +1 retain count, and doing a "temporary retain" is the safest way of guaranteeing that self remains alive throughout the entirety of a given init method. Consider what happens if we peel back the layer of Objective-C abstraction and turn -init into the function pointer it's IMP resolves to:
id init(id self, SEL _cmd) {
//+0 self given requires explicit retain to guarantee lifetime
//...
//(if retained) +1 self is returned; (if not retained) +0 self is deallocated
}
If given a self with a +0 retain count (as is common in most methods that retain their arguments i.e. setters), then you would have to guarantee that somewhere up the inheritance chain someone was nice enough to retain self away from whatever happened to allocate it (ending in self having a rather ambiguous retain count of +1). But, if you receive a self with a +1 retain count, and you do a retain-release it yourself,you can be certain that it remains alive through your -init method, and that you and you alone have ownership of self. And if the given self was not "alive", then you're guaranteed to return nil rather than an object in the middle of deallocation. Thus, the above becomes (in pseudo-C):
id init(__attribute((ns_consumed))id self, SEL _cmd) {
//implicit retain of +1 self returns self with +2
//...
//implicit release of +2 self returns self with +1
}
I like to call this pattern "old-school atomic access", and it's used in Apple frameworks designed before #synchronized {} atomic getters were invented. When you use a getter backed with a public iVar. You'll often see methods that follow that pattern written like:
- (NSView *)view {
//explicit retain-autorelease of +1 variable is +2 -> +1, guaranteed access or nil.
return [[_view retain]autorelease];
}
But all of this doesn't touch the ownership rules of the exception that is -init and family. -init methods return objects +1, but who exactly owns them? Well, the allocator* still has a hand in the reference to the variable, and self = [super init] doesn't actually retain anything (and it also has to obey the whole "returns +1" rule). Well, again I have to turn to pseudo-code, but this time it'll be in Objective-C:
- (id)init {
//self is +1 because -init must return +1
self = [super init];
//implicit [self retain]; leaves self with a +2 reference count
//...
//implicit [self autorelease]; leaves self with a +1 reference count
return self;
}
OK, so now you've got a +1 object floating around claimed by the allocator, so how do you "claim" it? Assignment, of course! The point of implicitly __strong locals and __strong properties is to reclaim the object from the allocator entity.
- (void)f {
//Freestanding +1 variable is not owned by the caller, will be deallocated when the method
//passes out of scope.
[[NSObject alloc]init];
//Implicitly __strong local captures reference away from allocator entity,
//which "autoreleases" it's ownership
//We now "own" the returned object.
NSObject *obj = [[NSObject alloc]init];
//Strong property captures reference away from local, saves the object from being deallocated
//when the method passes out of scope
self.object = obj;
}
*Allocator, in the context of this answer, refers to the functions that eventually call malloc() to allocate space for the object.

Objective-C Why use init?

I'm reading my first book on Objective-C [Programming in Objective-C 4th Edition], I'm midway through the book but one thing that bugs me, is that it didn't explain WHY we initialize objects.
I tried playing around with the with objects, for example allocating their memory but not initiating them and everything in the program works the same as before.
I'd appreciate some example explaining this, also.
The code within an init method is class specific - it performs whatever initialisation is required for that specific class. There are cases where a class does not need to perform any initialisation and thus removing this method call would have no effect.
However, by convention, you should always use init - what if someone were to add some required initialisation code to a class in the future?
See also:
alloc and init what do they actually do
To address you point of "everything works", the interesting thing about Objective-C is that alloc sets all instance variables to nil, and sending messages to nil doesn't do anything, it just returns nil, so in most of the cases you will not see a problem until you would try to do something illegal, consider a class like this
#interface MyObject : NSObject
#property (nonatomic, strong) NSString *string;
#end
#implementation MyObject
#end
Now if we'd just alloc it as:
MyObject *m = [MyObject alloc];
the instance variable _string, or property string would be nil, we could send different messages to it, like [string length] without any harm, since message to nil equals nil.
But say we then want to add this string to array, like
#[m.string]
Now you would get a exception, because NSArray cannot contain nil, only full blown objects. You can easily fix this by initializing your value inside MyObject.init.
Pretty contrived example, but hopefully shows the point of why everything doesn't break when you don't init :)
One of the main reasons why you should never use alloc's return value directly instead of using [[Class alloc] init]'s return value is that init might return a different object than alloc.
Apple's documentation mentions this:
Note: It’s possible for init to return a different object than was
created by alloc, so it’s best practice to nest the calls as shown.
Never initialize an object without reassigning any pointer to that
object. As an example, don’t do this:
NSObject *someObject = [NSObject alloc];
[someObject init];
If the call to init returns some other object, you’ll be left with a
pointer to the object that was originally allocated but never
initialized.
Source: http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/ProgrammingWithObjectiveC/WorkingwithObjects/WorkingwithObjects.html