what is wrong when checking if the objects is nil - objective-c

I have read the docs from apple http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/ProgrammingWithObjectiveC/WorkingwithObjects/WorkingwithObjects.html
It says that we can check if object is null like...
XYZPerson *somePerson;
// somePerson is automatically set to nil
if (somePerson != nil) {
// somePerson points to an object
}
Most probably i am doing something wrong but need your help to find what it is.
I have a class C2,I create the C2 object but not initialising,when checking with the code below ,app writes NOT NİL to output.What am i doing wrong.
Thanks for your help.
C2 * o3;
if (o3 != nil) {
NSLog(#"NOT NİLLLL");
}else{
NSLog(#"NOT");
}

Unlike members of classes that are zeroed out on initialization, local variables are not initialized automatically by pre-ARC compilers. If you would like your local o3 to be nil, you need to initialize it yourself:
C2 * o3 = nil;
The behavior of not initializing locals unless explicitly directed by the program comes from C: there, too, the locals are not initialized by default.

Related

Objective-C Passing address of non-local object to __autoreleasing parameter

How can I change this line of code [NgnAVSession releaseSession: &audioSession]; so that I will no longer get this error:
Passing address of non-local object to __autoreleasing parameter for
write-back
this is the whole method
- (void)viewWillDisappear:(BOOL)animated
{
[NgnAVSession releaseSession: &audioSession];
[UIDevice currentDevice].proximityMonitoringEnabled = NO;
}
Here is the declaration of releaseSession
Header
+(void) releaseSession: (NgnAVSession**) session;
Implementation
+(void) releaseSession: (NgnAVSession**) session{
#synchronized (kSessions){
if (session && *session){
if([(*session) retainCount] == 1){
[kSessions removeObjectForKey:[*session getIdAsNumber]];
}
else {
[(*session) release];
}
*session = nil;
}
}
}
You are using a very old library. Try getting a newer version.
Then read up how Cocoa use NSError*. You really need to do this, because otherwise you cannot possibly understand what's going on.
Long story short: The compiler assumes that you pass the address of an autoreleasing variable. If needed it can turn a local variable into an autoreleasing one. That cannot be done with a non-local variable.
What these guys are doing is just wrong, wrong, wrong, wrong, wrong. If they want to keep track of all sessions without counting references, the easiest way is to create a wrapper object holding a weak reference, putting the wrapper objects into the array, and in the dealloc method you can remove the object from the array.
I'd suggest that you throw away their releaseSession and do exactly what I said before.

Are there Optional variables in Objective C?

I enjoy using the new Optional class in Java. Is there an equivalent in Objective C?
I need something that can hold a small value like nil until I try to get its value, at which point it is initialized and has the new value cached for next time I read it. I don't want to check if the object is nil at every point where I try to read its value.
You can lazy load the variable using a getter.
- (MyClass *) something {
if(!_something) {
_something = [MyClass new];
}
return _something;
}
Thus, each time you use instance.something, it will do the checking for you and load the object if it's not there already.
If it's a simple one-liner and you simply don't want to use if, you can skip out the keyword (I hear this is quicker, but can't verify that now):
- (MyClass *) something {
return _something ?: (_something = [MyClass new]);
}
This is very similar to the unwrapping in Swift where myObject?.aValue will return aValue only if myObject != nil. Or the if let statement: if let value = myObject?.aValue
In objective C, there is no specific syntax dedicated to this however you can easily test for existence using simple if statement e.g.: if(myObject). Because Objective-C objects are pointers and the address of a NULL pointer is 0x0 this if statement will evaluate to false if myObject is NULL (or nil if you like).
If you try to read a property of a nil object you will likewise get nil (for properties that are also objects). And if you try to set a nil object's property, nothing will happen.
I like to use the ternery operator as much as possible e.g.:string != nil ? [textField setText:string] : NULL;
As suggested in previous answers you can use lazy instantiation in your specific situation.

Pointer initialized

I know in Objective-C and during programming on iOS SDK, pointers are used all the way around.
What is the best way to learn whether a pointer was initialized or not in Objective-C?
Check if it is nil?
CSomeClass *p;
//....
if(p==nil)
??
PS: in other words what are the default values in Objective-C for variables? Pointers?
UPDATE
Actually I have the following situation.
Imagine I have some pointers Pointer *p1, Pointer *p2 in some class. Then imagine someone calls this class, i.e., it is a view and must be displayed. Then in my class I want to check that if none had initialised p1 and p2 (e.g., p1 == nil? p2==nil?) I want to display empty text.
Are these some sort of comparisons done in Objective-C? For example, what are the default values of p1 and p2 if they were not initialised? Do values by default get initialized to something in Objective-C? Maybe to null?
What is the best way to learn whether a pointer was initialized or not
in Objective C? Check if it is nil ???
Yes, you are correct(By initializing, I am assuming that you meant allocation and not actual initialization of setting default properties). You can check for nil if you have declared it as CSomeClass *p; in ARC. In non-ARC, you should initialize it as CSomeClass *p = nil;.
So here you can do it as,
if (p) { //or if (p != nil)
//do your operations
} else { //same as if (!p) or if (p == nil)
//display error message
}
Actually I have following situation. Imagine I have some pointers
Pointer *p1, Pointer *p2 in some class. Then imagine someone calls
this class, i.e., it is a view and must be displayed. Then in my class
I want to check that if none had initialized p1 and p2 (e.g., p1 ==
nil? p2==nil?) I want to display empty text. Are these sort of
comparisons done in ObjC?
Yes, that is fine in Objective C. You can check it as if (p1 && p2) or if ((p1 != nil) && (p2 != nil)). Both are fine. In the else part, you can add the empty text which should be displayed.
For example what are the default values of p1 and p2 if they were not
initialized? Do values by default get initialized to something in
ObjC?? maybe to null?
In ARC, it will be nil. In non-ARC you should equate to CSomeClass *p1 = nil; before doing this or else it will be a dangling pointer with some garbage value.
Here is the documentation on ARC.
Something important to understand here is that Objective-C uses reference counting - this is why the terminology of saying "a pointer is initialized" is a bit problematic.
The way to know if an object even exists (Doesn't mean it's initialized!)
if (!object) {
NSLog(#"Object is nil");
}
If you wish to release an object, it's always best practice to nil it out. This way, others won't send a message to deallocated instance (causes a nasty crash):
[object release],object = nil;

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.

Passing arguments by value or by reference in objective C

I'm kind of new with objective c and I'm trying to pass an argument by reference but is behaving like it were a value. Do you know why this doesn't work?
This is the function:
- (void) checkRedColorText:(UILabel *)labelToChange {
NSComparisonResult startLaterThanEnd = [startDate compare:endDate];
if (startLaterThanEnd == NSOrderedDescending){
labelToChange.textColor = [UIColor redColor];
}
else{
labelToChange.textColor = [UIColor blackColor];
}
}
And this is the call:
UILabel *startHourLabel; // This is properly initialized in other part of the code
[self checkRedColorText:startHourLabel];
Thanks for your help
Objective-C only support passing parameters by value. The problem here has probably been fixed already (Since this question is more than a year old) but I need to clarify some things regarding arguments and Objective-C.
Objective-C is a strict superset of C which means that everything C does, Obj-C does it too.
By having a quick look at Wikipedia, you can see that Function parameters are always passed by value
Objective-C is no different. What's happening here is that whenever we are passing an object to a function (In this case a UILabel *), we pass the value contained at the pointer's address.
Whatever you do, it will always be the value of what you are passing. If you want to pass the value of the reference you would have to pass it a **object (Like often seen when passing NSError).
This is the same thing with scalars, they are passed by value, hence you can modify the value of the variable you received in your method and that won't change the value of the original variable that you passed to the function.
Here's an example to ease the understanding:
- (void)parentFunction {
int i = 0;
[self modifyValueOfPassedArgument:i];
//i == 0 still!
}
- (void)modifyValueOfPassedArgument:(NSInteger)j {
//j == 0! but j is a copied variable. It is _NOT_ i
j = 23;
//j now == 23, but this hasn't changed the value of i.
}
If you wanted to be able to modify i, you would have to pass the value of the reference by doing the following:
- (void)parentFunction {
int i = 0; //Stack allocated. Kept it that way for sake of simplicity
[self modifyValueOfPassedReference:&i];
//i == 23!
}
- (void)modifyValueOfPassedReference:(NSInteger *)j {
//j == 0, and this points to i! We can modify i from here.
*j = 23;
//j now == 23, and i also == 23!
}
Objective-C, like Java, only has pass-by-value. Like Java, objects are always accessed through pointers. "objects" are never values directly, hence you never assign or pass an object. You are passing an object pointer by value. But that does not seem to be the issue -- you are trying to modify the object pointed to by the pointer, which is perfectly allowed and has nothing to do with pass-by-value vs. pass-by-reference. I don't see any problem with your code.
In objective-c, there is no way to pass objects by value (unless you explicitly copy it, but that's another story). Poke around your code -- are you sure checkRedColorText: is called? What about [startDate compare:endDate], does it ever not equal NSOrderedDescending? Is labelToChange nil?
Did you edit out code between this line
UILabel *startHourLabel;
and this line?
[self checkRedColorText:startHourLabel];
If not, the problem is that you're re-declaring your startHourLabel variable, so you're losing any sort of initialization that was there previously. You should be getting a compiler error here.
Here are the possibilities for why this doesn't work:
the label you pass in to checkRedColorText is not the one you think it is.
the comparison result is always coming out the same way.
... actually, there is no 3.
You claim you initialised startHourLabel elsewhere, but, if it is a label from a nib file, you should not be initialising it at all. It should be declared as an IBOutlet and connected to the label in the nib with interface builder.
If it is not a label in the nib i.e. you are deliberately creating it programmatically, you need to check the address of the label you initialise and check the address of the label passed in to checkRedColorText. Either NSLog its address at initialisation and in checkRedColorText or inspect it with the debugger.