Casting Objective-C Objects - objective-c

I've been wondering this for a while, and Google hasn't provided me with the information I want. How fast does the casting process take? Does it depend on the number of fields an object has? Is it something to be avoided at all costs? Does it differ on x32, x64 and ARM machines?

Casting is only for the compiler to issue you better warnings. At runtime casting has no performance hit. All objects are just objects. You send messages to those objects.
The runtime doesn't care what type you gave when you had a pointer to that object in your code. It will send the message no matter what.
For example:
NSArray *myString = [NSString stringWithFormat:#"Hello"];
NSNumber *longerString = [(NSString *)myString stringByAppendingString:#" World"];
NSLog(#"%#", longerString);
Will log Hello World. You really give types to things so the compiler can check, but the runtime only knows that you're passing a message to an object. It will use the class of the object to look up the method to call from the message name, but it doesn't care what you typed at compile time.
You could have also done:
id myString = [NSString stringWithFormat:#"Hello"];
id longerString = [myString stringByAppendingString:#" World"];
NSLog(#"%#", longerString);
And the runtime will do the exact same thing, but the compiler will match up your types differently and generate warnings/errors based on different semantics (basically, does any object say it responds to this message).

Related

Why does the runtime allow the assignment of an NSDictionary out of an array into an NSString variable?

Consider this code:
NSMutableArray *array = [[NSMutableArray alloc]init];
for(int i = 0; i < 5 ; i++)
[array addObject:[[NSDictionary alloc]init]];
NSString *poisonedString = [array objectAtIndex:0];
In this above snippet, I have an array and I am inserting some dictionary objects into this array. While all this is fine and dandy, when I get the dictionary object from the array and put it into an string object, it is not causing any cast exceptions! The program runs smoothly and then crashes only when we do dictionary operations on the poisonedString! Why is this so? Why doesn't the Objective-C runtime see the type mismatch and raise an exception at the assignment, when the dictionary object is put into poisonedString?
Objective-C is not type-checked at runtime at all unless those checks are explicitly added. What is done at runtime is method lookup in response to a message, and in this the type of the target is not considered only whether the target has an matching method.
At compile time the Clang compiler does as much static type-checking of the Objective-C additions to C as it can to provide the programmer with warnings when types are incorrect. However the programmer can always bypass those warnings with little difficulty if they really wish to, but it is generally ill-advised to do so.
Whenever the type of something is "lost", e.g. when it is put into a collection which allows for any type of object and later extracted, then the compiler cannot provide any meaningful help. It is up to the programmer to add code to check the actual runtime type and then cast the value to the determined type. While the cast itself does nothing at runtime at compile it informs the compiler of the determined type and that allows it to do better type checking and produce better warnings.
You test the type of something with the method isKindOfClass, so the outline template is:
id someVar = ...
if ( [someVar isKindOfClass:[SpecificType class]] )
{
SpecificType *typeKnownVar = (SpecificType *)someVar;
// now use typeKnownVar and compiler will do static checking where possible
}
else
{
// deal with someVar not being of SpecificType
}
HTH
In a nutshell, NSArray supports inserting any type of object into it. If you look at the documentation you can see a generic (id) object is returned when using objectAtIndex:
- (id)objectAtIndex:(NSUInteger)index
With that in mind you can't expect the compiler to know ahead of time what type your object is when you get it from the array.
Because first of all you are not casting :) I can't see any cast, and second of all, welcome to Objective-C, this is what they call a Dynamic Language, and you can read more here
https://developer.apple.com/library/mac/documentation/cocoa/conceptual/ProgrammingWithObjectiveC/WorkingwithObjects/WorkingwithObjects.html
Now back to your code, the arrays are not generic so you can add whatever items of whatever classes you want in the same array and when you get the item, you don't need to cast it, the compiler trusts you :D now if you try to send a message (or as you named it do some operations), it'll throw a runtime exception, so simply if you are in the situation where you don't know if it's an NSString or an NSDictionary, just use the below code to check the type of the object.
if ([array[0] isKindOfClass:[NSDictionary class]]) {
// Do whatever you want
}
else if ([array[0] isKindOfClass:[NSString class]]) {
// Also do whatever you want
}
in NSArray class reference the documentation present that the return of ObjectAtIndex is an id
objectAtIndex:
Returns the object located at the specified index.
- (id)objectAtIndex:(NSUInteger)index
It is not possible to the compiler to know the type of object when your pointer is an id. It's normal that dump at executing time and not at compiling time.

How to extract an object from NSString

It's quite easy get the class/address of an object as a string, using:
NSString* objectInfoString = [object description];
The string returned is something like <ClassName: fk10009567>, with the letters and numbers representing it's unique address in memory, as I understand it.
Or, for just the address, simply using a formatted NSString with the %p place holder.
NSString* addressString = [NSString stringWithFormat:#"%p",myObject];
Is it then possible to create a pointer from this string information?
For Example:
NSObject* foo = [[NSObject alloc]init];
NSString* fooAddressString = [NSString stringWithFormat:#"%p",foo];
Then, I'd like to be able to do something like:
NSObject* newFoo = [NSObject objectForAddressString:fooAddressString];
such that newFoo = foo is true.
The foundation APIs provide a specific mechanism for doing this, without using 'magic strings', although you could do it using stringWithFormat, I guess. (It would be somewhat fragile, as noted).
To get a pointer reference to the object:
//Value now contains a pointer to the object, be careful it doesn't become dangling
NSValue* value = [NSValue valueWithPointer:(__bridge void*) myObject];
To get the object back from the pointer reference:
//If not using ARC you can skip the (__bridge id) here, and change the above cast to just (void*)
MyObjectType* myObject = (__bridge id) [value pointerValue];
Fragility?
It was noted that using '%p' to obtain a pointer value is fragile - while all Objective-C implementations currently return a hex value, the implementation of this could change. In any case, there's a specific API to do it.
Consider also that saving a reference to a pointer is fragile by nature in any case: Having obtained a pointer its necessary to ensure that it doesn't become 'dangling' - meaning the object being referenced goes away before the pointer does. The same strategies as using the __unsafe_unretained (aka assign) memory option should be applied. (No automatic weak references here!)
There are certainly valid applications of this kind of thing, however they are quite specialized and it would be unusual to find yourself doing this in everday apps programming. (I gathered you were asking the question simply to get a deeper understanding of Objective-C - kudos for that).
What is a valid use of this technique?
One valid application is to keep a reference to an Objective-C object in a C++ class. The Box2d physics engine (C++) allows this to provide an integration point with various Objective-C sprite engines.
This does not seem something sane or good thing to do. Relying on the - description of an object is very, very fragile. Why would you need to recover the object from its description? If you want to serialize and deserialize objects, you can do that by implementing the NSCoding protocol. If you want to associate objects with indices or keys, you can use NSArray or NSDictionary, etc...
That said, however, you can make a pointer out of a string:
NSString *addr = #"0xbadf00d";
uintptr_t ptr = strtoull(addr.UTF8String, NULL, 0);
id obj = (id)ptr;

Why cast the NSNumber contents of an NSMutableArray when retrieving the intValue?

In some sample code, an NSNumber is added to a mutable array:
// In the .h, as an instance variable:
NSMutableArray *sequence;
// In the .m file:
sequence = [[NSMutableArray alloc] initWithCapacity:100];
[sequence addObject:[NSNumber numberWithInt:123]];
Then later on, when the integer is needed, it uses:
[(NSNumber *)[sequence objectAtIndex:aCounter] intValue]
I just wonder why the cast (NSNumber *) is needed? Because the program runs fine without it, too. Is it just a good practice? If so, what can it prevent from happening? If there is a bug so that one element is not an NSNumber *, then casting it can create strange behavior too.
Casting only makes the compiler believe that the object (which is returned as of type id, i. e. generic object type with no other information!) is actually an NSNumber, so that it can identify correclty its intValue etc. methods. It doesn't make things differ at runtime. If the object is not an NSNumber, then it will crash at runtime, with or without the casting.
It is fine to do it without the casting, the casting just makes it explicit that you treat it as an NSNumber, if you have a bug and this is not an NSNumber (or more precisly, don't respond to intValue) you'll get some odd behavior anyway.
//In objective-C any object can send message to any other object.
//SO here both statmenst are perfectly valid ,but
[(NSNumber *)[sequence objectAtIndex:aCounter] removeFromSuperview]; //This throws warning and lets u know removeFromSuperview shpuld'nt be called
[[sequence objectAtIndex:aCounter] removeFromSuperview];//here u wont get any warnig
I just wonder why the cast (NSNumber *) is needed?
It's not needed if the signature of the selector that's actually called at runtime is visible to the translation, and all selector signatures visible to the translation match for the selector that's called.
You're probably thinking "What? That's complicated! That's also error prone, especially as my programs evolve!"
If multiple selector signatures for the same selector are visible and you message id, then you should expect undefined behavior because objc collections aren't typed and the compiler may not match the correct selector (if your warning level is high and your includes are all correct, you can see a warning about this).
The simple way to avoid this is to reintroduce the correct type by assignment:
NSNumber * n = [array objectAtIndex:i];
int a = [n intValue];
or by casting:
int a = [(NSNumber*)[array objectAtIndex:i] intValue];
so the compiler can match the selector appropriately for the type, and also warn you when the object may not respond to a given selector, or if the parameters or return types do not match, or if the interface of the type you cast it to is not visible in the translation -- after all, you should have an idea of what the collection contains.
Introducing that type safety properly is a very good practice.
The cast is just needed to stop the compiler from complaining that it's not sure you know what you're doing.
One of the things that the compiler does for you as it compiles is to check whether the interfaces for the recievers of messages say that they respond to the messages you're sending (intValue in this case). The interface of NSNumber does indeed say that it responds to intValue, but the return type of objectAtIndex: is id, which is a generic pointer. The compiler has no way to know what the type of the object at the other end of that pointer is -- that won't be known until runtime.
The cast tells the compiler that you do indeed know the type and that it doesn't need to warn you (or, in some cases under ARC, give an error) about the fact that it's not sure if the receiver of the message responds.
Note that if you changed the class of the cast to something that didn't respond to intValue (such as NSDate), the compiler would gripe at you, but if the object really was still an NSNumber, the message would still succeed at runtime. Casting can't change the type of the object; it is simply an annotation for the compiler.*
*In some cases, it can also increase the readability of your code, too.

Do I need to release a constant NSString?

I'm reading memory management rules to this point where it said
- (void)printHello {
NSString *string;
string = [[NSString alloc] initWithString:#"Hello"];
NSLog(#"%#", string);
[string release];
}
you have ownership and have to release string, but I'm curious about the #"Hello". #" " is the syntax for creating and NSString, and it's an object. So doesn't that get leaked?
#"…" is a literal instance of NSString. When the compiler sees a literal string, it maps the string into the binary file (e.g. your program) and the string is available as an NSString object when the binary is loaded (e.g. when you run your program). You don’t have to manage the memory occupied by literal strings because they’re an intrinsic part of your binary — they are always available, they never get released, and you don’t have to worry about managing their memory.
Bavarious's answer is correct. For the curious, I can add that this is documented in Apple's “String Programming Guide”, specifically the section “Creating Strings” where it says (emphasis mine):
The simplest way to create a string object in source code is to use the Objective-C #"..." construct:
NSString *temp = #"/tmp/scratch";
Note that, when creating a string constant in this fashion, you should use UTF-8 characters. Such an object is created at compile time and exists throughout your program’s execution. The compiler makes such object constants unique on a per-module basis, and they’re never deallocated.

Advantage of data type id vs NSString in Objective C?

This code...
NSString * s = [[NSString alloc] initWithString:#"Hello, World"];
s = s.lowercaseString;
NSLog(#"%#", s);
...allows the use of dot notation but is strongly typed.
This code...
id s = [[NSString alloc] initWithString:#"Hello, World"];
s = [s lowercaseString];
NSLog(#"%#", s);
... is weakly typed and requires use of square brackets.
Other than that, is there any advantage of using one over the other?
If you're creating an NSString, then you might as well declare it as an NSString, and let the compiler help you.
The point of using id is to prevent strong coupling, and to use objects whose types are not known until a later time. e.g IBAction methods include the sender as a parameter as an id, because the exact type of the object isn't known.
Edited to add:
You may be new to the language, so I'll mention a couple of things
Firstly, where you have #"Hello, World", you already have an NSString, just one that is static. So you don't need to go through initWithString to create it. Just write:
NSString *s = #"Hello, World";
And, because you didn't alloc it, you don't have to worry about releasing it.
Secondly s.lowerCaseString. As Stephen has already answered, this is considered to be bad style. When you change a string to lower case, you aren't getting a property of the the string, you are causing an operation to be done on the string, in which case, you really should use bracket syntax.
Yes. The compiler warns you if you try to put a NSString into a method that expects a NSNumber.
It's more likely that the compiler finds your mistakes.
Arguably the former code is incorrect. You should only really use the dot notation to get/set properties, and lowercaseString is a method.
Otherwise, as you suggest, the only real difference is type safety. If you had a typo, say you put [a loercaseString], the compiler wouldn't shout at you.
There are certainly cases where you'd use id but your example is not one of them