Check if a pointer is nil before instantiating - objective-c

I'm new to Objective-C and I got really confused when I saw the if check in the getter of a property:
- (XXX)name {
if (!_name) _name = [[XXX alloc] init];
return _name;
}
Why do you have to check if the pointer is nil when instantiating? Isn't that all objects starts with 0(nil)? Why can't you just have the pointer point to the newly instantiated object on the left?

You can see the point of this when you consider that name is called several times. The first call on a particular instance will allocate _name. In the subsequent calls _name wouldn't be nil, so the previously allocated item would be returned.
This is a lazy initialization pattern. This implementation is fine in single-threaded environments, and in environments where objects with this method are not shared among threads.
In concurrent environments you should use a thread-safe version of this pattern, which uses a lock, or the dispatch_once method.

Why do you have to check if the pointer is nil when instantiating?
The second time you call the getter method, it's already instantiated. This pattern is used when you only want to instantiate the property once. If it's nil you haven't done it yet. If it's non nil just return the value.
Isn't that all objects starts with 0(nil)?
Yep. If it's nil that means you need to instantiate it. So go ahead and do that, and from then on return that instance.
Why can't you just have the pointer point to the newly instantiated object on the left?
Huh? I have no idea what you are asking here.

This is a very common mini-pattern in Objective-C. You see it, for example, in custom property getters. The idea is to create an object, but only if you haven't created one before (and if you have, just return it). As #Nicholas Hart says in his comment, this also helps achieves lazy initialization (an object is created if and when it is referenced.
E.g.:
- (MyType *)myProperty
{
if(!_myProperty)
{
_myProperty = [[MyType alloc] init];
}
return _myProperty;
}
// somewhere else, you want to use the property:
[self.myProperty doSomething];
In the call to doSomething, the getter method myProperty will be called, and the _myProperty ivar (which is behind the myProperty property) will be initialized, if necessary.

Related

Send the message objc_msgSend(class,#selector(dealloc)) to release the object, why is it wrong to access the object pointer?

The code is under ARC. When I delete the code NSObject* objc = (NSObject*)object; the program runs fine, but I didn't have access to the pointer objc. When I keep the code NSObject* objc = (NSObject*)object; I am prompted EXC_BAD_ACCESS (code=1, address=0x20). Is the system accessing the objc pointer after the block function body ends?
-(void)resetDeallocMethodWithInstance:(NSObject*)obj
{
Class targetClass = obj.class;
#synchronized (swizzledClasses()) {
NSString *className = NSStringFromClass(obj.class);
if ([swizzledClasses() containsObject:className]) return;
SEL deallocSel = sel_registerName("dealloc");
__block void (*deallocBlock)(__unsafe_unretained id, SEL) = NULL;
id block = ^(__unsafe_unretained id object){
NSObject* objc = (NSObject*)object;
NSUInteger hash = ((NSObject*)object).hash;
[self removeAllTargetWitSuffixKey:[NSString stringWithFormat:#"%lu",(unsigned long)hash]];
if (deallocBlock == NULL) {
struct objc_super superInfo = {
.receiver = object,
.super_class = class_getSuperclass(targetClass)
};
void (*msgSend)(struct objc_super *, SEL) = (__typeof__(msgSend))objc_msgSendSuper;
msgSend(&superInfo, deallocSel);
} else {
deallocBlock(object, deallocSel);
}
};
IMP blockImp = imp_implementationWithBlock(block);
if (!class_addMethod(obj.class, deallocSel, blockImp, "v#:")) {
Method deallocMethod = class_getInstanceMethod(obj.class, deallocSel);
deallocBlock = (__typeof__(deallocBlock))method_getImplementation(deallocMethod);
deallocBlock = (__typeof__(deallocBlock))method_setImplementation(deallocMethod, blockImp);
}
[swizzledClasses() addObject:className];
}
return;
}
enter image description here
Note: This answer is being directly typed in, your code has not been tested, indeed no code has been tested. Therefore that the issues below are causing your issues is being inferred.
There area number of issues with your design:
Swizzling dealloc is not recommended. The dealloc method is called automatically by the system when it is in the process of destroying an object, as such using the partly destroyed object inappropriately (whatever that might be) could lead to issues - as you have found!
You are using ARC under which "an implementation of dealloc, [should] not invoke the superclass’s implementation". However your block does this.
The variable objc is unused. However by default a local variable has the attribute strong so you are creating a strong reference to an object in the process of destruction. Any strong reference made by the block in this way will be released by ARC when the block has finished, this is almost certainly not good as your error indicates.
You appear to be trying to call your removeAllTargetWithSuffixKey: method when a particular object is destroyed (appear as you swizzle [and can only swizzle] the class but are using the hash of a particular object). A better way to do this avoiding swizzling is to use associated objects.
The runtime function objc_setassociatedobject() allows you to attach an object to a particular instance of another object and have that object be destroyed automatically when its host is destroyed (use an objc_AssociationPolicy of OBJC_ASSOCIATION_RETAIN).
Design a class which has an instance property of your required hash value and a dealloc method which calls your removeAllTargetWithSuffixKey: then rather than swizzle the class simply create and associate an instance of your class with the target object.
HTH
Yes, it's accessing the pointer after the method ends. If this is being compiled under ARC, then the objc is a "strong" reference. However, you are fabricating the implementation of the dealloc method, and so are retaining the object when it's already going to be dealloced, so it's too late to have a strong reference to it. Your implementation is going to call super, which should actually deallocate the object, and then afterwards ARC is going to release the objc value, but it's already gone since it's the receiver, i.e. "self" if you were writing a normal dealloc method.
ARC will never retain self in a regular dealloc method, but that is what you are effectively doing. The "object" value is the same pointer, but is explicitly __unsafe_unretained, so you should just use that directly. You can type the block as NSObject* instead of id if that helps, but it shouldn't matter. Or you can make your objc value also __unsafe_unretained so ARC leaves it alone. You don't want ARC touching the "self" value inside the block in any way, since you are going around ARC's back in this case.
Whatever the case, once you are in an object's dealloc method, don't ever retain/release/autorelease the self pointer -- it will end up with crashes. Calling a method from dealloc and passing a reference to self is a no-no, for example. You need to be very careful about that, and understand exactly what ARC is doing if you are playing these types of runtime games.

Instance variable initialized without using "init" method?

Iam in the first phase of Objective-C learning curve, so please bear with me :).
Iam reading Apple documentation and doing exercises there also. Ive come to a problem with initialization of particular object, because I get unexpected (In my opinion) behavior in my Xcode.
To the point (lets make it simple):
STEP 1:
I have declared simple variable from a my custom class named XYZPerson. It looks like this:
XYZPerson *randomPerson;
"If" check for initialized object returned out "Not Initialized" (as expected).
if(randomPerson == nil) {
NSLog(#"Random person is not initialized");
} else {
NSLog(#"Random person is initialized");
}
STEP 2:
I have allocated the memory for this object using "alloc" word on this variable. As I understand in this phase, memory for this variable gets allocated. It also returns the pointer?
Line of code looks like this:
XYZPerson *randomPerson = [XYZPerson alloc];
Checking for "nil" surprised me: (It executes "else" statement).
if(randomPerson == nil) {
NSLog(#"Random person is not initialized");
} else {
NSLog(#"Random person is initialized");
}
I can also send messages to this object and they are executed just fine, without calling "init" method.
How can this be? Am I missing something? How can "randomPerson" variable be initialized before calling "init" method on this instance? Why is "init" there in the first place then?
Furthermore, the accepted answer here Difference between ! and nil check on Objective-C object , says that ALL object are set to nil in the alloc method!
Iam coming from Java and there is one way of declaring an object using "new" keyword. Without using "new" the instance of object will be always "null", and calling methods on that instance will result "NULLPOINTEREXPECTION Error".
P.S Is "nil" in objective C, same as "NULL" in Java?
Whole project looks like this:
main method:
XYZPerson *randomPerson = [XYZPerson alloc];
if(randomPerson == nil) {
NSLog(#"Random person is not initialized");
} else {
NSLog(#"Random person is initialized");
}
**XYZ Person Class:**
#import "XYZPerson.h"
#implementation XYZPerson
-(void)sayHello {
//[self saySomething];
}
-(void)saySomething:(NSString *) greeting {
NSLog(#"%#", greeting);
}
#end
I post an answer additional to that one linked in the comment for two reasons:
A. Your Q is slightly different.
B. I do not confirm with the linked answer in details.
First of all to your additional Qs: Yes, nil is Objectice-C's NULL. But there are some differences:
A. In most cases (using ARC) a reference to a pointer (not the object itself) is initialized with nil.
XYZPerson *person; // Usually automatically set to nil.
B. A message to nil is allowed in Objective-C, does not throw an exception and returns NO, 0, 0.0, nil, or whatever the representation of null resp. zero (if it does not have a null representation like integers) is for that type. Sometimes this is done intentionally and you can rely on that.
Two your main Q:
After creating an instance object with +alloc all instance variable (ivars) are set to NO, 0, 0.0, nil, or whatever the representation of null resp. zero is for that type. You should not set such ivars explicitly to that value.
For example, if the instances of the class XYZPerson has an ivar for the name typed NSString*, the ivar will be nil. So, one might think that an naked -init does not have any meaning, because it does not take parameters and therefore does nothing. But you simply do not know: Maybe something else is done in -init. And, that's probably a surprise for a Java developer, -init returns an object reference, so you cannot know, whether -init replaces the instance object, for example for twin toning. So even you do not see any meaning in it, the first message to an instance object has to be init. (Yes, in many case you would not see any difference, but you do not know, whether there is one or not or will be in future. It is a part of the API contract, so do it.)
In disagree with the linked answer in one point:
Sending +new… instead of +alloc -init is the better way to do it.
A. If you use a simple +new it is correct that it sends +alloc -init in many cases. Therefore it is obvious that this is not better or worse than sending +alloc -init. It is what it does. You always have to have a look at the documentation, whether a naked initialization, using +new or +alloc -init is allowed. But in such a case you likely do not want to do a naked initialization, because it is meaningless.
B. Sometimes it is for the implementor of a class easier to receive a new message to the class object.

What happens when one calls a setter/getter on a property that has not been alloc+init'ed?

I've got a simple question about objective-c.
I've been taught to lazily instantiate my properties by synthesizing them and then overriding the getter in the following manner.
-(SomeClass *)someProperty {
if ( !_someProperty )
_someProperty = [[SomeClass alloc] init ]
return _someProperty
}
What happens when I don't do this? I ask this because I have properties that are not allocated & instantiated in this manner and they seem (maybe not) to behave just fine.
My only guess is that if a property is unallocated & instantiated it will be left as nil; in which case messaging nil would do nothing. Is this correct?
Thanks in advance for your help!
Yes, messaging nil is just fine. You don't have to override any getters to lazily initialize your properties. See this: https://developer.apple.com/library/ios/documentation/cocoa/conceptual/objectivec/Chapters/ocObjectsClasses.html#//apple_ref/doc/uid/TP30001163-CH11-SW7
Instance variables are automatically set to nil (or 0 for primitive types) when the object is created, so you don't have to worry about sending messages to uninitialized properties.
Well yes, if you try to send a message to nil nothing is going to happen. That is the main point to allocate it and initialize it. Allocating just gives the property a place in memory.

Can I use self = nil in my methods?

Can I use
self = nil
in an instance method so that when the method execution ends, I can use an if statement in the main class:
if (myInstance)
to check if something went wrong ?
thanks
You can do that, but it does not have the effect you want.
consider your objc method's signature for -[NSArray count] to have the following C function signature:
NSUInteger NSArray_count(NSArray * self, SEL _cmd) {
self = nil; // ok - this is a variable, local to the function (method).
// now all messages to `self` will do nothing - in this method only.
...
}
since the pointer you assign to nil is a variable local to the method, it does not actually affect the instance externally. it changes the pointer variable in the method's scope. that variable is the argument passed. in effect, it means that you have set the local argument to nil, but the rest of the world does not acknowledge this change.
You can return nil in the constructor, yes. If you do this after calling the [super init] be sure you release the object it returned with an owning retain count.
With that said, something else you can do is follow Apple's usage of *NSError to go along with returning nil to help provide better information of what went wrong to your using code.
You can return nil from a constructor, but if you return nil the maybe-allocated memory will never be freed!
If you're object manages its own life-cycle (and thus memory management), you can release it and return nil from a specific method.
Usually that kind of methods are class method, because if it isn't it involve that the user has a reference to the object, and thus it is hazardous to release it.

Objects creation and instantiation in objective-c

Given the piece of code below where blueViewController is an iVar.
Question: Why not instantiate the iVar directly?
BlueViewController *blueController = [[BlueViewController alloc]initWithNibName:#"BlueView" bundle:nil];
self.blueViewController = blueController;
[blueController release];
It depends on where you are in your class. If you are in your init (and dealloc) method it is recommended to refer to the ivar directly to avoid any side effects in setter logic. Therefore in the init I would do
_blueViewController = [[BlueViewController alloc] initWithNibName:#"BlueView" bundle:nil];
But anywhere else I would do it how you have done it. Then if there is any custom logic in the getter/setter I know it will be run.
To eleborate on #Vladimar's point the synthesized setter for a retain will do some memory management similar to this:
- (void)setMyObject:(MyObject *)newMyObject
{
// If it's the same object we don't need to do anything
if (_myObject != newMyObject) {
[newMyObject retain];
[_myObject release];
_myObject = newMyObject;
}
}
It is much safer to let the getters/setters worry about all this logic any time you set your ivars.
You can initialise iVar directly, but the code you have also handles memory management for the previous blueViewController value. Accessing iVar directly you'll have to release previous value manually before assigning new one.
You can do it all on one line if you want. The important thing is to balance the +alloc with a -release or -autorelease. So, you can say:
self.blueViewController = [[[BlueViewController alloc] initWithNibName:#"BlueView" bundle:nil] autorelease];
That's fine, but some folks prefer to avoid -autorelease, and some folks just prefer simpler steps and/or shorter lines of code. Using an intermediate variable as you've done helps in that respect, and it doesn't cost anything.
It depends on whether the property is retain or not. Most object properties are retained; this is what a retain property looks like:
- (void)setBlueViewController:(BlueViewController *)bvc {
if (bvc != blueViewController) { // blueViewController is local ivar
[blueViewController release];
blueViewController = [bvc retain];
}
}
So what you're doing up there is creating a retain count of +2. When you init, that's a +1; the property then retains it, bumping it up to +2. Your dealloc releases it once, which brings it down to +1...and you've leaked that property. Because you are alloc/init-ing the variable, you don't want to use the setter; instead, assign it directly to the instance variable.
By instantiating it directly, it saves you the trouble of that other release—fewer lines of code means fewer errors. You might, for example, have typed retain by accident and not realized it until your program crashes because you retained a massive class...
Of course, as Caleb says you could autorelease, but that's effectively letting the object lie around in memory until the run loop is finished. It's much easier, and gives you more control, to just not worry about that. There's nothing wrong with assigning the alloc/init to the ivar; in fact, that's the best way to do it.