Passing nil object pointer in Objective-C - objective-c

I create an object which I set to nil by default before including it in a method as a parameter. I do a check later if the object is still nil or not. The object is set to change in the method but the result is still nil. I'd expect the method to be able to alter the nil object. If I have the code that's inside the method replace the method call, it results in it being NOT nil.
MyObject *objectTemp = nil;
[self methodCallWithObject:objectTemp];
if (objectTemp == nil) NSLog(#"nil");
else NSLog(#"NOT nil");
// always results in "nil"
method:
-(void) methodCallWithObject:(MyObject)objectTemp {
objectTemp = [NSValue valueWithCGPoint:CGPointMake(5.3f, 2.6f)];
}

In order to change objectTemp outside of the method, you have to pass a pointer to objectTemp, which means that methodCallWithObject actually needs to take a pointer to a pointer:
-(void) methodCallWithObject:(MyObject **)objectTemp {
*objectTemp = [NSValue valueWithCGPoint:CGPointMake(5.3f, 2.6f)];
}
(However, it would probably make more sense to have methodCallWithObject just return a new object.)

Related

Check object if it's equal to nil or to [NSNull null]

if object set to nil and I want to check for its value.
if object != nil {
// do something
}
or
if object != [NSNull null] {
// do something
}
I guess the second condition will be triggered but I am not sure why.
Can someone explain please?
As others have pointed out, object != nil && object != NSNull.null would give you the expected behaviour, however it might be tedious and error prone to write this pair of conditions every time.
Alternatively you can use inverted logic, by adding an nonNullValue method to virtually almost all objects in the system:
// in some header file
#interface NSObject(NullExtension)
- (instancetype)nonNullValue;
#end
// in some implementation file
#implementation NSObject(NullExtension)
// regular objects are not null (right?)
- (instancetype)nonNullValue {
return self;
}
#end
#implementation NSNull(NullExtension)
// let's make NSNull report as being null
- (instancetype)nonNullValue {
return nil;
}
#end
// adding this just for the sake of completeness, it's highly unlikely
// that JSON's will decode NSProxy instances
#implementation NSProxy(NullExtension)
- (instancetype)nonNullValue {
return self;
}
#end
you can then simply use it on your pointers:
// since we're in Objective-C, a nil pointer will always fail the check
// and thanks to the NSNull extension, NSNull instances will behave the same
if ([object nonNullValue] != nil) {
// NSNull won't get here
// nils won't get here
// other objects will get here
}
This approach is a little bit invasive as it touches all NSObject subclasses, however it eliminates the need of writing multiple conditions.
If you want to make sure object isn't nil and it isn't NSNull null then do:
if (object && object != [NSNull null]) {
// do something with object
} // else it's either nil or NSNull null
The difference between [NSNull null] and nil is that nil is an empty object that has completely disappeared from memory, and we use [NSNull null] when we want to express the idea that "we need a container that has nothing in it," which is "an object whose value is null." If you look up the development documentation you'll see that the class NSNull inherits NSObject and has only one "+ (NSNull *) null;" Class methods. This means that the NSNull object has a valid memory address, so any reference to it in the program will not cause the program to crash.

Objective C pointer to pointer - how to distinguish passing nil vs not initialized variable set to nil

I have a method which accepts pointer to pointer param:
+(void)someMethod:(NSString*_Nullable*_Nullable)parsed;
Now, if i call this method and pass "nil" as parameter, and then i do the dereference inside of method like:
*parsed = soemthing;
I get crash BAD Access. Now question is, how to construct condition to distinguish passing "nil" vs passing not initilized variable like:
NSString* s; // this is technically nil too, but dereference works and doesn't crash
[someObj someMethod:&s];
to prevent the crash mentioned in first case.
The solution is relatively simple, you should never pass an uninitialized variable. Consider doing this:
NSString *s = nil;
[someObj someMethod:&s];
Note the &s as you have declared someMethod to require a NSString **. By doing &s the parsed will always be defined, as the variable is obviously stored somewhere in memory. Its value, stored at *parsed will have been initialized to nil. You should then be able to do things like:
+(void)someMethod:(NSString* _Nullable *_Nullable)parsed {
if( NULL != parsed ) {
if( nil == *parsed ) {
*parsed = #"Our variable *s will now be set!";
}
}
}

How to pass ivar into a function and set it without losing the reference to the original object

I am passing an ivar (NSMutableArray) into some method. I was expecting that if I modify the object inside the function, it would be reflected outside the function, but in this case I need to set the object; something like the following:
- (void) someMethod:(SMResponseObject *)response onData:(NSMutableArray *)imAnIvar {
imAnIvar = [response objects];
//Some other stuff
}
But I noticed that the memory reference of imAnIvar inside the function changes when I set it, and given that, the actual ivar doesn't change. I understand that the problem is that I'm changing the reference of the object inside the method, so it stops pointing to the ivar and then it points to some other random memory direction.
I thought about one solution to this problem, and it can be to ensure that the ivar is not nil before calling the function and do something like this:
- (void) someMethod:(SMResponseObject *)response onData:(NSMutableArray *)imAnIvar {
NSMutableArray *data = [response objects];
[arrayForTableView removeAllObjects];
for(id element in data){
[imAnIvar addObject:element];
}
//Some other stuff
}
So I use the original object instead of setting it directly. The problem is that in order for this to work I need to ensure that the ivar is not nil, which I think is not clean, because I'll need to do something like this on every call to the method:
if(!_ivar){
//alloc it
}
So my question is: Is there a way to force the local scope variable to point to the original variable even if I'm setting it? if not, is there any cleaner way to make this work?
Do you mean this?
- (void)setFoo:(SomeClass **)objPtr
{
*objPtr = someOtherObject;
}
// call it as:
SomeClass *foo = someObject;
NSLog(#"Before: %#", foo);
[self setFoo:&foo];
NSLog(#"After: %#", foo);
Why not use a getter for the array so that you need not check for the array being nil while using it?
-(NSMutableArray *)iAmAnIvar {
if(_iAmAnIvar == nil) {
_iAmAnIvar = [NSMutableArray array];
}
return _iAmAnIvar;
}
And when you have to set a value to the array, as you mentioned in your question, you could use
[self.iAmAnIvar removeAllObjects];
[self.iAmAnIvar addObject:someObj];
I believe you can use the - (id)copy; function of NSObject
so your code might look like this:
- (void)someFunction:(NSString *)someArg
{
NSString *str = [someArg copy];
}

Why does setting self.object to nil cause a crash

In the following scenario I get a crash
if (self.videoEngine != nil)
{
[self.videoEngine.player.view removeFromSuperview];
[videoEngine release];
self.videoEngine = nil;
}
The videoEngine object is (nonatomic, retain), and it is synthesized using videoEngine = _videoEngine. If I remove the self.videoEngine = nil line the code works properly. Is this correct behaviour, and why does the nil line cause a crash? Would the self.videoEngine = nil still cause an issue within the viewDidUnload function?
When you call "self.videoEngine = nil;" it calls its setter method and in the setter method by default it releases the object and then it sets it to the value provided by you, so in this case you are releasing your object once and then setter method is trying to release it again that is causing crash, now if you remove the "[videoEngine release];" that would be fine and there will be no memory leak.
Hope it is clear now.
You should only release _videoEngine because that is the the synthesized name. videEngine is only the name of the setter and getter, but the value is stored in the syntheseized name. So your code should be:
if (self.videoEngine != nil)
{
[self.videoEngine.player.view removeFromSuperview];
[_videoEngine release];
self.videoEngine = nil; // Unnecessary
}
But you donĀ“t need to call self.videEngine = nil after releasing the _videEngine because the setter will always return nil.
It is not considered a proper method of releasing by calling the setter method with nil, although it works, like is done with the line: self.videoEngine = nil; // Unnecessary.
The proper way of releasing is only [_videoEngine release];

Obj-C ARC: How to remove an object from an array/set and then return it as an autoreleased object?

How do I rewrite this method for ARC?
- (KTThumbView *)dequeueReusableThumbView
{
KTThumbView *thumbView = [reusableThumbViews_ anyObject];
if (thumbView != nil) {
// The only object retaining the view is the
// reusableThumbViews set, so we retain/autorelease
// it before returning it so that it's not immediately
// deallocated when removed form the set.
[[thumbView retain] autorelease];
[reusableThumbViews_ removeObject:thumbView];
}
return thumbView;
}
The automatic ARC migrator gives me this error:
[rewriter] it is not safe to remove an unused 'autorelease' message; its receiver may be destroyed immediately
Just remove the [[thumbView retain] autorelease]; line. The first line will make a strong reference guaranteeing its around as needed.