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;
Related
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.
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.
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.
The documentation for NSDictionary says that the method objectForKey returns nil if the NSDictionary does not contain your key; however, isn't nil the same as zero? If so, how do I know if the return value means that the dictionary contains the key mapped to zero or if that key is just non-existant?
NSDictionaries (and, indeed, all Cocoa collection objects) can only contain Objective-C objects, not C primitives like int. Therefore, were you to store 0 in a dictionary, you'd do it like this:
[myDictionary setObject:[NSNumber numberWithInt:0] forKey:#"myKey"];
and therefore, retrieving it would go like this:
NSNumber* resultObj = [myDictionary objectForKey:#"myKey"];
if (resultObj == nil)
{
//Key didn't exist
}
else
{
int result = [resultObj intValue];
//Now do your work.
}
This concept of 'wrapping' a C primitive in an object to store it in a collection, then 'unwrapping' it on the other end is very common in Cocoa. (You might also look into NSValue if you're trying to work with non-number values.)
Edited: Although the direction in memory NULL and nil point to happen to be 0x0 and it has always been and it may always be, you can't use that value for other purposes but to define an undefined address in memory. In the case of NULL it means an undefined pointer. nil means an undefined object pointer. The idea behind these #defines is that there's a rigid standard for programmers and programs to know and communicate undefined addresses in memory, and it could change to 0x42 in a new compiler or standard and NOTHING should happen. So, don't think nil or NULL as 0; yes they are, but that's a mere accident. It's not a feature.
nil is not the same as 0. nil is an object pointer, 0 is a numeric value
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.