Pointers on Objective-c - objective-c

From what I understand (and please correct me if I'm wrong):
int x, count = 10;
int *hello;
hello = &count;
x = *hello;
Here the variables x and count are declared to be of type integer. Additionally, the variable count is assigned the value of 10.
hello is a pointer to type integer. hello is then assigned the address of count.
In order to access the value of count, hello must have an asterisk in front of it, ie, *hello.
So, x is assigned the value of whatever is in count and in this case, 10.
However...
Fraction *myFraction = [[Fraction alloc] init];
[myFraction someMethod];
Here, if I understand correctly, myFraction is a pointer to an instance of Fraction class.
myFraction is pointing to (or rather assigned the address of) an object which has been assigned memory and initialised.
Surely, in order to access the object that myFraction points to, I ought to write:
[*myFraction someMethod];
Given the way in which x accessed the value of count, surely in order to access the object, one ought to write this and not:
[myFraction someMethod];
In addition, if I have
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *str = #"Programming can be a headache";
NSLog (#"%#\n", str);
Why is str being treated as an object above? Or is str an object and in which case, why would I want to make it point to an instance of NSString class? Surely, I ought to be able to just assign an object to str?

All the usage of objects in objective c is done through object references, e.g. pointers.
The Objective C syntax lets you treat objects without dereferencing them, this is different than C / C++ for that matter.
str is an object reference of type NSString (as myFraction) and #"Programming can be a headache" is an object reference of type NSString as well, so you can assign it to str.

Additional to Binyamin
Everything inside the brackets [ ] is objective-C and not simple C (so [*object message] is not common to use)
[object message], you send the "message" to your object, and the object responds with something (he can return something or he can do something without anything in return).
Everything with a * on the left is pointer. So *str is a pointer. And where is it point? to an object NSString. The #"blabla" returns the adress of one CONSTANT string that has generated directly by the compiler.
NSLog (#"%#\n", str); here the %# calls the +Description class method of NSString object called str. By default the description of an NSString Object returns the value of the string (the text). %# is not a simple replace like the %d with numbers (int,double etc). All objects have +Description method that inherit from the NSObject (note is Class method and not instant).
description
Returns a string that represents the contents of the receiving class.
(NSString *)description

Related

Explanation for assigning Objective-C NSNumber object to int variable?

Can anyone explain why this works in Objective-C? I would expect it to give an error since an object is being assigned to an int variable. I get that it does work, and this is great, but I am missing why this is allowed?
int i = [NSNumber numberWithInt:123];
Furthermore, this seems to store the wrong value (ie, on my system when I print out the value of "i" using NSLog I get "252711" instead of 123); however, only when the variable is declared and assigned in my main code. If I declare it as an instance variable of an object and then use Key-Value coding to assign it a value, it works properly:
Object instance variables...
#interface myObject : NSObject
{
int anInt;
}
Main code...
[myObject setValue:[NSNumber numberWithInt:123] forKey:#"anInt"];
NSLog(#"%#", [myObject valueForKey:#"anInt"]);
This code prints out "123" as expected, but I'm not sure why given that when using a seemingly similar approach above it does not work properly.
it doesnt "work" and there is a compiler warning about it. the reason it can be compiled is that the NSNumber class method numberWithInt returns a pointer, which can be implicitly converted to int. When you print it out you are getting the address where the objective-c object was allocated.
the SetValue:forKey: method doesnt take an int parameter, it takes an id which is just a pointer to a generic Objective-C object. Key-Value coding is taking care of assigning the intValue of the NSNumber object for you.
When you executing the code:
int i = [NSNumber numberWithInt:123];
You just assigning pointer value to int.
numberWithInt: returns NSNumber* and it's a pointer, pointing to some place in memory where NSNumber object allocated.
And now value of i is not a 123 but decimal representation of NSNumber* pointer.
Read more about pointers in C/Objective-C.

Objective C: Assign a value such that all pointers to that variable obtain the new value

Imagine I define a variable like this
NSString * a = #"Hello people";
And now I copy the pointer to b so that both a and b point to the location where #"Hello people" is stored in memory (right? Or do I misunderstand how this works?)
NSString * b = a;
Now I want to change b such that a is also updated with the new value. The following does not work since it will point b to a new NSString #"Thanks all"
b = #"Thanks all!";
NSLog(#"%#", a); // still "Hello World"
but what I want is to replace whatever is at the memory location of #"Hello people" so that all pointers to it will update as well.
b = ????;
NSLog(#"%#", a); // Whoa, it still points to the same memory location as b!
Thanks!
In this case you want to use NSMutableString instead of NSString.
Because an NSString is immutable, when you change the original, it points to a whole new instance. But if you use an mutable version, the pointer remains unchanged even if the contents change.
However - although this will work, it's a bad idea. Such mutability is fragile. For example, if you have any KVO observers on this property, if the string changes, then no KVO notifications are fired.
Edit
An alternative is to use multiple indirection:
NSString **string;
&string = #"some string";
Now you can have:
NSString **string2 = string;
And changes to string will be propagated to string 2, because although the pointer is the same, the object that it points to will have changed.
Hovewever, you'll need to dereference the pointer to use it, i.e.
NSLog (#"String is: %#", *string);
or
NSLog (#String2 is: %#, *string2);
But you still have that mutability issue.

Getting the class type for a nil object?

If I have an object that is already allocated, then doing object.class returns a non-nil value. So far so good. But, if the object has not yet been allocated, then accessing object.class returns nil.
I want to allocate an object based on its type dynamically, so for example:
#property NSArray *myArray;
...
// myArray is nil so far
self.myArray = [_myArray.class new];
However, I can't do this because _myArray.class is returning nil. So how would I determine the class type of a nil instance?
Update:
It is in fact possible. Check out my answer below.
You cannot determine the class of a nil instance, because it does not have one: it can be, quite literally, of any type derived from the type of the variable. For example, NSMutableArray is perfectly compatible with NSArray:
NSArray *myArray = [NSArray new]; // OK
NSArray *myArray = [NSMutableArray new]; // Also OK
Since the run-time capabilities of different subclasses can vary a lot, it is always up to your program to decide what kind of objects it wants.
Objective-C is a duck-typed language. This means that there are several things you can or can't do, and one of the things you can't is statically get a reference to the type of a variable.
Specifically, in your expression:
[_myArray.class new]
First, _myArray.class is evaluated, and then the result is sent the new message. Since _myArray is nil to begin with, _myArray.class returns nil as well, and the new message will return nil too, because sending any message to nil returns nil (or the closest representation to zero the return type has). This is why it doesn't work.
I suspect you come from a strongly-typed language like C#; what you're doing right now is the equivalent of Foo foo = (Foo)Activator.CreateInstance(foo.GetType()), which is sure to fail because foo.GetType() will either not compile or throw an exception (depending on if it's a class field or a local variable) since it was never assigned a value. In Objective-C, it compiles but it doesn't works. What you would want is Activator.CreateInstance(typeof(Foo)), but notice that Foo is now hardcoded here too, so you might as well just create a new Foo().
You say that the compiler "knows the type" of the object. This is not exactly true. First, NSArray and NSMutableArray are the root classes of the NSArray class cluster. This means that both are abstract, and [NSArray alloc] and [NSMutableArray alloc] return an instance of a subclass (NSCFArray last time I checked, and possibly something else; I recall seeing _NSArrayM). Maybe [NSArray new] works, but it's not giving you a plain NSArray.
Second, type safety is not enforced. Consider this code:
id foo = #"foo";
NSArray* bar = foo; // no warning!
So even though the compiler thinks that bar is an NSArray, it's in fact a NSString. If we plug in your code:
id foo = #"foo";
NSArray* bar = foo; // no warning!
NSArray* baz = [bar.class new];
baz is now an NSString as well. Since you ask for the runtime class of bar, the compiler has nothing to do with the operations.
And precisely because of that kind of behavior, you should probably instantiate your object with a class that you know, using [NSArray new] instead of trusting _myArray to be non-nil, and to be what you think it is.
You must init the property , or it will be nil , send a message to a nil object , it will return nil , so ,you must first init the array like _array = [[NSArray alloc] init];
So, for anyone wondering if this is possible, it is:
objc_property_t property = class_getProperty(self.class, "myArray");
const char * const attrString = property_getAttributes(property);
const char *typeString = attrString + 1;
const char *next = NSGetSizeAndAlignment(typeString, NULL, NULL);
const char *className = typeString + 2;
next = strchr(className, '"');
size_t classNameLength = next - className;
char trimmedName[classNameLength + 1];
strncpy(trimmedName, className, classNameLength);
trimmedName[classNameLength] = '\0';
Class objectClass = objc_getClass(trimmedName);
NSLog(#"%#", objectClass);
Output:
NSArray
Done with the help of extobjc.
Nil has no class type
In Objective-C the actual class on an instance variable is only determined at runtime. So, you can't know the class of a nil object.
This is not an issue in your situation since you only need to do:
NSArray *myArray = [NSArray new];
Or
NSArray *myArray = [[NSArray alloc] init];
In Objective-C most decisions are deferred to the runtime
(as much as possible)
Objective-C is a runtime oriented language, which means that when it's
possible it defers decisions about what will actually be executed from
compile & link time to when it's actually executing on the runtime.
This gives you a lot of flexibility in that you can redirect messages
to appropriate objects as you need to or you can even intentionally
swap method implementations, etc.
This requires the use of a runtime
which can introspect objects to see what they do & don't respond to
and dispatch methods appropriately. If we contrast this to a language
like C. In C you start out with a main() method and then from there
it's pretty much a top down design of following your logic and
executing functions as you've written your code. A C struct can't
forward requests to perform a function onto other targets.
Source: Understanding the Objective-C Runtime

Objective-C: a Pointer That Points to Difference Classes at Different Time

I'm not really experienced with Objective-C. Here is a problem I encountered.
When I want to define a pointer for a particular instance of a class, I can
NSString* foo;
But is it possible to define pointers for instances of classes like this?
x* hotdog; //"x" is the type of pointer hotdog is
hotdog = NSString; //now points to NSString
hotdog* foo; //an instance of NSString is created
hotdog = UIView; //now points to UIView
hotdog* foo; //an instance of UIView is created
How to define the class-pointer hotdog? (what should I replace x with?)
what should I replace x with?
You should replace x with the name of the most specific common ancestor of the classes that you are planning to use with this pointer. In your example, that would be NSObject, because both NSString and UIView inherit it, and there are no other common ancestors. In the worst case, the common ancestor is id.
In general, tricks like that should be avoided in most situations, because reusing a pointer for something really different is bad for readability.
If you want a pointer to an object of a type that's not yet known at compile-time (similar to dynamic in C#), use id:
id hotdog;
hotdog = [[NSString alloc] init];
hotdog = [[NSArray alloc] init];
Only do this when you really need it. If you use it everywhere, your code can easily become a mess since you'll lose track of the type of the variable.
At first I misunderstood your question. I'll leave my old answer here just in case future visitors need it.
The type of pointers to classes is Class and to get an object of that type use +[NSObject class].
Class hotdog = [NSString class]; // now points to NSString
NSString *myString = [[hotdog alloc] init]; // create instance of NSString
hotdog = [NSArray class]; // now points to NSArray
NSArray *myArray = [[hotdog alloc] init]; // create instance of NSArray
You can use either NSObject* or id as the pointer type. NSObject* will accept any subclass of NSObject, while id will accept other Objective-C objects as well.
Note that, to avoid compiler warning messages, you must cast the pointer type back to the (presumably known) actual type before applying any sort of dereferencing operation (other than methods of NSObject).
You can, to be sure you have the expected type of object, use isKindOfClass to check the type:
if ([genericPointer isKindOfClass:[NSArray class]]) {
NSString* arrayElement = [(NSArray)genericPointer objectAtIndex:x];
}
But is it possible to define pointers for instances of classes like this?
I suppose you're asking for the equivalent of C++ templates.
You can't do it and you don't need it, just use the id type:
id foo= #"some text";
If you are working on an instance class the pointer to the class itself is simply self.
If you are working on a class pointer you could just use the id type since it is a generic type. Make sure then the object you are working on is of the expected type by using the isKindOfClass method if you want to invoke some methods of this class.

Explain object variable declaration and assignment

In this snippet:
NSString *testString;
testString = [[NSString alloc] init];
Why, on the second line, do we not have to write *testString = ... in order to access the location where it's actually pointing?
After the first line, what is *testString and what is testString?
The first line you are creating the pointer of NSString type. Pointers in C++ and Objective-C are denoted by the asterisk (*) character when you declare them. The second line you are saying this pointer called "testString" references the memory location of the NSString object that you have allocated in memory.
All objects are referred to by pointers. The first line
NSString * testString;
declares the instance variable. If your variable type is an object (aside from type id), you need the *
from then on the reference to testString is pointer
If you create 2 strings. 2 physical objects are created (in memory)
NSString * testString = [[NSString alloc] init];
NSString * testString2 = [[NSString alloc] init];
//setting testString to testString2 will lose the pointer to testString for good
testString = testString2; //<--bad if you still care about testString (and leaks the memory too)
I recommend checking out Apple's guide on Objective-C. Specifically this section
http://developer.apple.com/library/mac/#documentation/cocoa/conceptual/objectivec/Chapters/ocObjectsClasses.html#//apple_ref/doc/uid/TP30001163-CH11-SW1
Why, on the second line, do we not have to write *testString = ... in order to access the location where it's actually pointing?
The init method returns a generic pointer to an object -- its return type is id. testString is a pointer to an NSString, which is an object, so you are assigning a pointer to another pointer. Dereferencing the assigned-to pointer would be a type mismatch.
A variable name is a place (a label for a memory address) in which to put something. The type of the variable is the kind of thing that you can put there. In the case of a pointer, the kind of thing that you put in it is also a memory address. In order to get that address, you dereference the pointer. The kind of thing that you can put at that address is different from the kind that you put in the pointer itself.
After the first line, what is *testString and what is testString?
After the first line, *testString, or the thing at which testString points, is garbage (actually undefined). testString is a pointer (4 or 8 bytes depending on your system) to a address in memory, and it is also undefined.
After the second line, *testString is an NSString object. testString is still a pointer to an address, where there is a valid NSString object.
That's simply because we affect the pointer.
[[NSString alloc] init] returns a pointer to an NSString.
In Cocoa every object is dynamically allocated (as in malloc in C) and every NSObject is manipulated thru its pointer/address (in such a point that many ObjC programmer don't even know that they are manipulating pointers and not objects)