How does this Objective-C code work? - objective-c

Code:
int main(int argc, const char * argv[]) {
id idObject = #"12345";
NSNumber *n = idObject;
NSLog(#"%#\n", [n description]);
return 0;
}
It prints "12345". How? I guess it's because Objective-C uses dynamic binding. Thus, decision which method to choose is made at run-time and this decision is based on the name of the method (selector) and the receiver object. Maybe the receiver object gets known due to "isa" pointer... ?

This works because:
All objects that inherit from NSObject have a description method.
Objective-C doesn't enforce types, so n is actually an NSString and not an NSNumber as you might suppose.

You are right.
The code works, because n refers to an object that understands the message description. (The object is a instance object of class NSString and these objects understand that message.)
The type of the object reference n (id, NSString*, NSNumber*, whatever) is without any meaning for the dispatching process.
At runtime you can collect many information about objects and its types. You cannot collect information about object references. (There is a single case, but this is not important.)

To add:
You're not actually typecasting by setting idObject to be referenced by NSNumber * n. The compiler doesn't know what type id should be, so it allows you to assign it to anything.
With your code snippet running you can see a bit more on how this is played out:
And then for comparison (creating an NSNumber from the string literal):

Related

Meaning of #property (readonly) void *data; in Objective c

I am new to iOS programming, I am preferring Swift language and I don't know Objective C. While I am wandering through some library, I got a value of type UnsafeMutableRawPointer in swift, that is actually a String value with utf8 encoding.
So I just looked into the corresponding objective c class and the variable is declared as
#property (readonly) void *data;
So why there is void pointer and why it is converted as UnsafeMutableRawPointer?
Consider me as a noob in Objective c or c.
Thanks in advance
This whole thing might be quite a lot for a beginner to understand. So let's start with ObjectiveC syntax:
Property #property (readonly) void *data; exposes interfaces which says there must be a method of type - (void *)data which means an instance method returning a void pointer. A void pointer being a pointer to anything.
ObjectiveC is then kind of a pure C a level deeper. I will not check exact transformation but since C has no methods this is all done with functions or even pointers to functions. So somewhere down there there should be a function (let's say the name of this class is MyDataClass)
void *myDataClass_data(MyDataClass *self) { return self->_data; } // Or whatever the implementation is
So nothing really interesting is going on under the hood. The whole thing just returns a position in memory without any further information of what should be there. You as a developer must know and interpret it. From C (or ObjectiveC) this is very simply. A few examples:
char *aString = (char *)myDataClass.data; // A pure C string. Expected to be null terminated
int *arrayOfIntegers = (int *)myDataClass.data; // An array of integers
int thirdItem = arrayOfIntegers[2];
MyDataClass *nextItem = (MyDataClass *)myDataClass.data; // A pointer to another instance
for(MyDataClass *iterator = myDataClass; iterator != nil; iterator = (MyDataClass *)iterator.data) {}
I hope you get the picture. The point is that C and then also ObjectiveC are very unsafe when it comes to data types. You can basically convert anything into anything however you want it and it will compile. The problem is what will happen in runtime.
When looking at Swift things get much safer and you can not just say something like let integer: Int = myDataClass as Int. You can force cast it and it will crash. Or you can do optional cast and it will return nil.
So once transitioned from C/ObjectiveC you will receive an unsafe mutable raw pointer. That means it got a position in memory witch it has no idea about what it is and how to use it. You may try to convert it to anything you want but it is unsafe as it will ignore all type checking. It is mutable probably because data it holds may be changed at any given time by any system. It is raw as it holds no additional information (like it's a string). And it's a pointer because it only points to a position in memory.
(All the snippets are symbolical to explain what goes on under the hood. Please do not take them literal)

No matching function for call to pthread_create Objective-C ARC conversion

converting my project to ARC but says it can't due to the following error 'No matching function for call to pthread_create'. Here is the code it falls in, happens specifically on the line starting with pthread create. How can I fix this? It also says Candidate function not viable: no known conversion from 'NSString *' to 'void * _Nullable' for 4th argument in the sidebar underneath the error.
I've cut off the rest of the function but can provide more detail if necessary.
void World::loadWorld(std::string name)
{
if(doneLoading==0)
{
doneLoading=1;
Resources::getResources->stopMenuTune();
if(LOW_MEM_DEVICE)
{
menu->deactivate();
Resources::getResources->unloadMenuTextures();
terrain->allocateMemory();
terrain->loadTerrain(name,TRUE);
doneLoading=2;
hud->fade_out=1;
}
else
{
terrain->allocateMemory();
pthread_t foo;
pthread_create(&foo,NULL,loadWorldThread, nsstring(name));
}
}
As your error message indicates the 4th argument to pthread_create is of type void *. Under ARC you cannot simply pass an Obj-C object reference as a void * as ARC would is not able to track the reference once it is stored in a C(++) pointer variable, and therefore cannot manage the object's memory.
For situations where an Obj-C reference must be passed into the C(++) world a bridge cast can be used to inform ARC how the memory should be managed. However in your case there a better way, just pass the C++ pointer, name, without creating an NSString. If loadWorldThread expects a std::string that is the correct thing to do anyway. If it expects an NSString * then either:
modify it to take a std::string and do any required conversion to NSString * within it; or
write a small intermediate function which takes a std::string, produces an NSString * from it, and then calls loadWorldThread. Pass this new function to pthread_create.
Doing either of the above avoids the use of a bridge cast in the pthread_create call to move the Obj-C reference into the C(++) world and out of ARC control; and another bridge cast in loadWorldThread (or intermediate function as above) to move it back into the Obj-C world and into ARC control.
Addendum
Expanding on the last paragraph, as the method there seems better suited to your situation. First, it is assumed that your code:
nsstring(name)
takes a value of type std::string and returns a value of type NSString, if it does not then look up how to do this conversion.
After the above expression you have a reference to an NSString under ARC control. You cannot simply pass such a reference as a void *, you must take it out of ARC's control first and take responsibility for its memory management (but not for long as you will see). You can bridge cast your NSString * to a CFStringRef:
CFStringRef cfName = (__bridge_retain CFStringRef)nsstring(name);
You can now pass cfName, which is a reference to a heap-allocated CFString, as a void *.
Now in loadWorldThread; which should be declared to take a void *, something like void loadWorldThread(void *arg) { ... }; you need to bridge cast your CFStringRef back to NSString * and hands responsibility for its memory management back to ARC:
NSString *nsName = (__bridge_transfer NSString *)arg;
The above is a standard pattern to pass an ARC controlled reference though an anonymous reference (void *).
(Note: the above uses CFStringRef to make it clear that you are passing around a reference to a manually managed CFString, you can cast directly to void * and back again, indeed you will notice that when casting back arg was not first cast to a CFStringRef to demonstrate this.)
HTH

Is reference counting the same as ownership counting?

Consider the following statement from "Big Nerd Ranch: Objective-C Programming" - Chapter 21: Object Instance Variables and Properties:
When an object has an object instance variable, the object with the pointer is said to own the object that is being pointed to.
Now consider the following scenario:
#import <Foundation/Foundation.h>
int main(int arc, const char * argv[])
{
#autoreleasepool {
NSString *message = #"Hello, world!";
}
return 0;
}
Here, the message object has one (1) reference. But... does it have any owner(s)?
If we strictly stick to the cited definition, there is no object with a pointer referencing this NSString. Does that mean that message has one (1) reference but no (0) owners?
And, if that is the case, what does ARC take into account when deciding whether to deallocate an object? Reference count or ownership count?
Reference counting is simply a number maintained by the object.
Ownership is a policy, almost a philosophy. It is a way of thinking that tries to ensure that you intervene coherently with an object's reference count.

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.

Objective C Instance Method Help *Beginner*

Can you guys help me understand a concept real quick, I'm having trouble understanding the conversion from C to objective-C:
If I had a particular instance method that look like this:
-(void)addOwnerNamesObject:(NSString *)n;
{
// ownerNames defined as NSMutableSet
[ownerNames addObject:n];
}
I understand a few things...
It is an instance method that can be called by the program.
In C this would not return anything (just execute the code in the curlies)
In C, the syntax is slightly less confusing - (void)InstanceMethod(Char *nameOfArgument)
Here's where I need help:
When you call this method are you still sending it an argument?
If so, is that argument an NSString instance that the method names n?
And finally... off topic
If you have a method...
-(id)someMethod:(NSString *)pn
{
}
What is the (id) for? does that tell the compiler that it can return any type of object?
Thanks for helping the Newbie... Much appreciated.
First of all, you should really take a look at the basic Objective-C documentation.
In Objective-C, a method can be preceded by a + or - sign.
+ is for class methods, - is for instance methods.
Then you have the return type, inside parenthesis, and the method name.
- ( int )foo;
An instance method named foo, returning an int.
A similar C function would be:
int foo( void );
In Objective-C, the method name is a bit special when you have arguments.
For instance:
- ( int )foo: ( double )num;
A member method named foo:, returning an int and taking a double argument named num.
Similar C function:
int foo( double num );
Now with multiple arguments:
- ( int )foo: ( double )num1 bar: ( float )num2;
A member method named foo:bar:, returning an int and taking a double argument named num1 and a float argument named num2.
Similar C function:
int foo( double num1, float num2 );
About your question on id, it's simply the method return type.
id is a typedef used for Objective-C instances.
Basically, it's a void *.
id does represent an Objective-C object pointer, for any class.
You already know what you're talking about.
1.) When you call this method are you still sending it an argument?
yes, whatever is after the colon
add multiple colons to pass additional parameters...
-(void)addOwnerNamesObject:(NSString *)n withSomeIntYouWantToPass:(int)value;
2.) If so, is that argument an NSString instance that the method names 'n'?
yes
3.) What is the (id) for? Does that tell the compiler that it can return any type of object?
yes, you will return an NSObject or subclass of NSObject
First the dash (-) in the method name says that this is an instance method which means you need an instance to send this message to. The call would look something like this:
NSString* s = #"a string";
[someInstance addOwnersNameObject:s];
In this case you are passing the NSString instance s to the addOwnersNameObject message.
id is like void * in C.
To add to those very valid answers already given with a further discussion of id:
Objects in Objective-C are typeless, which means that at a fundamental level you don't need to know the type to be able to talk to the object. That's one of the big differences between Objective-C and, say, C++.
Pointers to objects are usually typed, such as NSString * to make the code more readable and to indicate your intentions to the compiler so that it can provide suitable warnings if you do anything odd.
id is a typeless pointer to an object. Any object type can be passed as id and any id value can be assigned to any object pointer without casting.
99.99% of the time, id could be replaced with NSObject * since 99.99% of objects inherit from NSObject, meaning that you could use the fact of inheritance rather than the fact of typeless objects to pass things around generically. However NSObject is a little bit special in being both an object and a protocol and some objects aren't actually subclasses of NSObject — NSProxy and the classes that represent blocks jump immediately to mind. You'll rarely be particularly interested in those special cases but id is nevertheless often used as a convention because people prefer the semantics of passing an object with no indication of its type to passing an object with a known ancestor.