What is the normal behavior in Objective-C if you call a method on an object (pointer) that is nil (maybe because someone forgot to initialize it)? Shouldn't it generate some kind of an error (segmentation fault, null pointer exception...)?
If this is normal behavior, is there a way of changing this behavior (by configuring the compiler) so that the program raises some kind of error / exception at runtime?
To make it more clear what I am talking about, here's an example.
Having this class:
#interface Person : NSObject {
NSString *name;
}
#property (nonatomic, retain) NSString *name;
- (void)sayHi;
#end
with this implementation:
#implementation Person
#synthesize name;
- (void)dealloc {
[name release];
[super dealloc];
}
- (void)sayHi {
NSLog(#"Hello");
NSLog(#"My name is %#.", name);
}
#end
Somewhere in the program I do this:
Person *person = nil;
//person = [[Person alloc] init]; // let's say I comment this line
person.name = #"Mike"; // shouldn't I get an error here?
[person sayHi]; // and here
[person release]; // and here
A message sent to a nil object is perfectly acceptable in Objective-C, it's treated as a no-op. There is no way to flag it as an error because it's not an error, in fact it can be a very useful feature of the language.
From the docs:
Sending Messages to nil
In Objective-C, it is valid to send a
message to nil—it simply has no effect
at runtime. There are several patterns
in Cocoa that take advantage of this
fact. The value returned from a
message to nil may also be valid:
If the method returns an object, then a message sent to nil returns
0 (nil), for example:
Person *motherInLaw = [[aPerson spouse] mother];
If aPerson’s spouse is nil,
then mother is sent to nil and the
method returns nil.
If the method returns any pointer type, any integer scalar of size less
than or equal to sizeof(void*), a
float, a double, a long double,
or a long long, then a message sent
to nil returns 0.
If the method returns a struct, as defined by the Mac OS X ABI
Function Call Guide to be returned in
registers, then a message sent to
nil returns 0.0 for every field in
the data structure. Other struct
data types will not be filled with
zeros.
If the method returns anything other than the aforementioned value
types the return value of a message
sent to nil is undefined.
From Greg Parker's site:
If running LLVM Compiler 3.0 (Xcode 4.2) or later
Messages to nil with return type | return
Integers up to 64 bits | 0
Floating-point up to long double | 0.0
Pointers | nil
Structs | {0}
Any _Complex type | {0, 0}
One thing you should be clear on is that in Objective-C, you don't call a method on an object, you send a message to an object. The runtime will find the method and call it.
Since the first versions of Objective-C, a message to nil has always been a safe no-op that returns nil. There's a lot of code that depends on this behavior.
Nothing happened. When you send a message to nil it means that there is no receiver
and the message fly away. objc_msgSend method is used from Runtime library. Message dispatch mechanism is used that is why Objective-C is different and there are a lot of advantages are based on this principle. It will not throws any errors as Java or Swift do
Related
I was thinking how this "Powerful Solution" according to apple of the Optional Variables is actually powerful if it's something that we already had in Obj-c?
var mystring: String? = nil
if mystring {
//string is not nil
}
Second Scenario won't compile
var mystring: String = nil
if mystring {
//string is not nil
}
We were able to do this in Obj-C before without any additional set up.
NSString * somestring = #"Test";
if(something != [NSNull null]){
//Do something.
}
or
NSString * anotherstring = nil;
if(anotherstring == [NSNull null]){
//display error.
}
so I am really confused on how this is that powerful as they claim if it already existed in a former language.
Some info about Optional Variables
The optional is a type on its own (actually an enum), and it can hold 2 values:
an actual instance/value of the type the optional is used for (corresponding to the Some enum case)
a nil value (corresponding to the None enum case), which represent the absence of value
The difference with other languages like ObjectiveC is that optionals don't use a valid type value, which can have a meaning in some cases and a different meaning in others.
In objective C, the absence of a reference type is represented by nil, which is actually a pointer to the location 0x00000000 (in a 32 bits scenario).
The absence of a value type instead is usually by convention. A function returning an integer can define -1 as absence of value, but -1 is an integer itself, and if the function can return negative values it cannot be used.
In Swift instead an optional can have either a valid integer value, or None, which is not itself an integer (nor an instance of a class, a struct, or whatever type is used with the optional).
Also, more important, you cannot assign nil to a non optional variable - that results in a compilation error, hence preventing a lot of common bugs that usually are discovered at runtime, and frequently hard to track down.
Last, whereas in objective C you can use nil for reference types, you cannot use for value type (as mentioned above for the integer type). In swift instead an optional can be nil regardless of the contained type - so a Int? can be either an integer or nil.
Swift optionals let you make it explicit whether a variable can be nil, whereas Objective-C is all for guessing games. Less nightmares about EXC_BAD_ACCESS errors. That's where the power lies.
In Objective-C a pointer to an object could be nil, yes. But there was no enforcement about if nil made sense.
NSString *shouldNeverBeNil = #"a string!";
shouldNeverBeNil = nil;
NSLog("Hello, %#", shouldNeverBeNil); // "Hello, "
In ObjC this compiles fine though we should never say hello to nothing. That's a bug.
But if we do the same in Swift it doesn't even compile and we don't get a runtime bug at all.
var shouldNeverBeNil: String = "a string!"
shouldNeverBeNil = nil; // Compilation error.
NSLog("Hello, %#", shouldNeverBeNil); // never happens
Optionals allow you to bless variables with the ability to be nil. Compilation errors are always preferable to runtime errors since it's impossible for an end user of your app to run into a compilation error.
If you want to allow that value to be nil Swift makes you bless it explicitly, as an Optional. Now if it's nil, you explicitly allowed it and Swift reminds you to handle handle both the nil case and the value case in your code.
var okToBeNil: String? = "a string!"
okToBeNil = nil;
if okToBeNil != nil {
NSLog("Hello, %#", okToBeNil!); // never happens
} else {
NSLog("What is your name?")
}
I m taking a NSMutabledictionary object in NSString like this :
NSString *state=[d valueForKey:#"State"];
Now sometimes state may be null and sometimes filled with text.So Im comparing it.While comparing state becomes NSString sometimes and NSCFString othertimes..So unable to get the desired result..
if([state isEqualToString#""])
{
//do something
}
else
{
//do something
}
So while comparing it is returning nil sometimes.So immediately jumping into the else block.
I need a standard way to compare if the state is empty whether it is a NSString or NSCFString ...
How can I do it?
If you're unable to get the result you want, I can assure you it's not because you get a NSCFString instead of a NSString.
In Objective-C, the framework is filled with cluster classes; that is, you see a class in the documentation, and in fact, it's just an interface. The framework has instead its own implementations of these classes. For instance, as you noted, the NSString class is often represented by the NSCFString class instead; and there are a few others, like NSConstantString and NSPathStore2, that are in fact subclasses of NSString, and that will behave just like you expect.
Your issue, from what I see...
Now sometimes state may be null and sometimes filled with text.
... is that in Objective-C, it's legal to call a method on nil. (Nil is the Objective-C concept of null in other languages like C# and Java.) However, when you do, the return value is always zeroed; so if you string is nil, any equality comparison to it made with a method will return NO, even if you compare against nil. And even then, please note that an empty string is not the same thing as nil, since nil can be seen as the absence of anything. An empty string doesn't have characters, but hey, at least it's there. nil means there's nothing.
So instead of using a method to compare state to an empty string, you probably need to check that state is not nil, using simple pointer equality.
if(state == nil)
{
//do something
}
else
{
//do something
}
You can do this
if([state isEqualToString:#""])
{
//do something
}
else
{
//do something
}
You must have to type cast it to get the correct answer.
NSString *state = (NSString *) [d valueForKey:#"State"];
if(state != nil)
{
if(state.length > 0)
{
//string contains characters
}
}
I have a class "ABC" and its method which returns non autoreleases object of that class.
#interface ABC:NSObject
+(ABC *)aClassMethodReturnsObjectWhichNotAutoreleased;
#end
#implementation ABC
+(ABC *)aClassMethodReturnsObjectWhichNotAutoreleased{
ABC *a = [[ABC alloc]init];
return a;
}
#end
If I have a protocol Foo.
#Protocol Foo
#required
-(void)abc;
#end
My ABC class is "not" confirming Foo protocols.
1st call
id<Foo> obj = [ABC aClassMethodReturnsObjectWhichNotAutoreleased]; //show warning
It shows warning "Non Compatible pointers.." thats good.Abc did not confirm protocol Foo
BUT
2nd call
id<Foo> obj = [NSArray arrayWithObjects:#"abc",#"def",nil]; // It will "not" show warning as it will return autorelease object.NSArray don't confirm protocol Foo
In first call compiler gives warning and in second call compiler is not giving any warning.I think that is because i am not returning autorelease object.
Why is compiler not giving warning in 2nd call as NSArray is also not confirming FOO
Thanks in advance
In your first example, the return value is a specific type so the compiler can verify the assignment.
In the second example, the NSArray arrayWithObjects: method has a return type of id. You can assign an object of type id to a variable of any type. The compiler has no way to verify that what you are doing is truly correct or not.
This issue has nothing to do with autoreleased objects. It's all about the data types. id is a kind of catch-all type that can be anything.
What is difference between nil and Nil in iOS development?
And similarly what is difference between true and TRUE in iOS development?
I think this will help you understand the difference between nil and Nil.
Please find the below link:
Refer the answer of Damien_The_Unbeliever which states:
Googling "Nil vs nil" found this post http://numbergrinder.com/node/49, which states:
All three of these values represent null, or zero pointer, values. The
difference is that while NULL represents zero for any pointer, nil is
specific to objects (e.g., id) and Nil is specific to class pointers.
It should be considered a best practice of sorts to use the right null
object in the right circumstance for documentation purposes, even
though there is nothing stopping someone from mixing and matching as
they go along.
Link for that answer can be seen here:
What does 'Nil' represent in Obj-C?
EDIT-2:
Is there a difference between YES/NO,TRUE/FALSE and true/false in objective-c?
nil is the literal null value for Objective-C objects, corresponding to the abstract type id or any Objective-C type declared via #interface. For instance:
NSString *someString = nil;
NSURL *someURL = nil;
id someObject = nil;
if (anotherObject == nil) // do something
Nil is the literal null value for Objective-C classes, corresponding to the type Class. Since most code doesn’t need variables to reference classes, its use is not common. One example is:
Class someClass = Nil;
Class anotherClass = [NSString class];
The book "iPhone Programming. The Big Nerd Ranch Guide" cites the following method (page 96)
(void)mapView:(MKMapView *)mv didAddAnnotationViews:(NSArray *) views {
MKAnnotationView *annotationView = [views objectAtIndex:0];
id <MKAnnotation> mp = [annotationView annotation];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance([mp coordinate], 250, 250);
[mv setRegion:region animated:YES];
}
I'm confused because of the asterisk usage. The line that begins with "MKAnnotationView" and the following one can be represented in an abstract fashion by:
ObjectType variableName = [object message];
Questions:
In the first case an asterisk precedes the variable name, but not in the second. Why?
In the case where the asterisk is used, should not be the pointer the assigned to nil?
Thanks.
I tend to think of it as what variable types require an asterisk, not what variable names require an asterisk. Objective C doesn't allow you to allocate objects on the stack like so:
// Declare an NSObject. Won't work.
NSObject myObject;
Instead, all objects must be dynamically allocated on the heap using pointers like so:
// Declare a pointer to an NSObject. Will work.
NSObject* myObject = [[NSObject alloc] init];
id is a special Objective C keyword that just means "A pointer to some Objective C object". This may or may not inherit from NSObject and is dynamically typed. What's important to note is that, while there is no asterisk, this is still a pointer to an object:
// Same as before. Will work.
id myObject = [[NSObject alloc] init];
The only difference is that the compiler has no information about what myObject is.
As a finishing note, id <MKAnnotation> is exactly the same as a regular id, but with some extra information for the compiler. Read it as "a pointer to some Objective C object that behaves like an MKAnnotation". MKAnnotation, in this case, is the name of a Protocol whose required methods you are declaring that particular id to implement.
id is already defined as a pointer to a struct. If you look at its definition in objc.h, you would that id is defined as,
typedef struct objc_object {
Class isa;
} *id;
Since it is already a pointer to an objc_object, you can create pointers to objects without using the asterisk as,
id myObject;
Also saying that an object is type id gives the compiler absolutely no information about the object except its class which comes from the isa property.
An NSObject on the other hand is defined as,
#interface NSObject <NSObject> {
Class isa;
}
To create a pointer to an object of NSObject or one of its subclass (such as MKAnnotationView), you would declare it as,
NSObject *myObject;
MKAnnotationView *myObject;
We are putting the asterisk here to denote that it is a pointer.
Specifying the protocol(s) next to the type gives the compiler more information for static-type checking.
You should check out this article for a brief introduction to the differences between id and NSObject. For an in-depth understanding, checkout this article on the Objective-C runtime.
ObjectType is normally something like "pointer to a MKAnnotationView", which is represented in Objective-C as it is in C: "MKAnnotationView *". Exceptions include the "id" type, various integer and floating point types (including their typedefs), enums (which are really integer types), and some small structs like CGRect.