In the example
NSString *message = #"Hello";
message = #"World";
If message is just a pointer why don't I need to explicitly say whatever is in message is now equal to string or *message = #"World"; like in C?
DISCLAIMER
The discussion below gives a general idea on why you never dereferenciate a pointer to an object in Objective-C.
However, concerning the specific case of NSString literals, this is not what's happening in reality. While the structure described below is still sound and it may work that way, what's actually happening is that the space for a string literal is allocated at compile time, and you get its address back. This is true for string literals, since they are immutable and constant. For the sake of efficiency therefore each literal is allocated only once.
As a matter of fact
NSString * a = #"Hello";
NSString * b = #"Hello";
NSLog(#"%# %p", a, a); // Hello 0x1f4958
NSLog(#"%# %p", b, b); // Hello 0x1f4958
ORIGINAL ANSWER
Because it will be translated to
message = [[NSString alloc] initWithUTF8String:"Hello"]];
which will boil down to
message = objc_msgSend(objc_msgSend(objc_getClass("NSString"), #selector(alloc)), #selector(initWithUTF8String:), "Hello");
Now if we take a look to the signature of objc_msgSend
id objc_msgSend(id theReceiver, SEL theSelector, ...)
we see that the method returns an id type, which in Objective-C is the object type. But how is id actually defined?
typedef struct objc_object {
Class isa;
} *id;
id is defined as a pointer to an objc_object struct.
So in the end #"string" will translate in a function call that will produce a pointer to an object (i.e. an objc_object struct, if you prefer), which is exactly what you need to assign to message.
Bottom line, you assign pointers, not objects.
To better clarify the last concept consider this
NSMutableString * a = [NSMutableString stringWithString:#"hello"];
NSMutableString * b = a;
[a setString:#"hola"];
NSLog(#"%#", a); // "hola"
NSLog(#"%#", b); // "hola"
If you were assigning objects, b would have been a copy of a and any further modification of a wouldn't have affected b.
Instead what you get is a and b being two pointers to the same object in the heap.
Related
I was doing some tinkering with tree traversals (which I have solved in a much more straightforward way) but I have come across an issue in the following piece of Objective C logic:
- (NSString *)someWrapperFunction
{
NSString *result = #"";
NSString *(^appendBlock)(int, NSString **) = ^NSString *(int a, NSString **adder){
if (a == 0)
{
// base case
return #"";
}
NSLog(#"%d", a);
*adder = [*adder stringByAppendingFormat:#"-%d-", a];
NSLog(#"adder: %#", *adder);
return [*adder stringByAppendingString:appendBlock(a-1, adder)];
};
appendBlock(5, &result);
return result;
}
Basically, I want to create a block of code that concatenates numbers into the given string (adder). The result should be: "-5--4--3--2--1-".
I get a segmentation fault with the above code but with some other code that I wrote for the tree traversal, the adder string was essentially not getting updated. Any pointers to what I am doing wrong here? (Is it possible that the variable that is being updated by the inner block (inside recursion) is disallowed as it is already being occupied by the outer block OR is it just that NSString is non-mutable data type?)
In any case, I want to keep the design of the function the same; how would I solve this problem (using c/objective)?
After some searching and experimenting I found a way to fix this.
There is no reason to be using a double-pointer for your adder parameter in the block. Just use a regular pointer and update your code accordingly.
The error is coming from the fact that inside of the block, appendBlock is NULL and you end up dereferencing the NULL pointer trying to call it.
Here's an updated version that works:
- (NSString *)someWrapperFunction
{
NSString *result = #"";
NSString *(^appendBlock)(int, NSString *);
__block __weak NSString *(^weakBlock)(int, NSString *);
weakBlock = appendBlock = ^NSString *(int a, NSString *adder){
NSString *(^innerBlock)(int, NSString *) = weakBlock;
if (a == 0)
{
// base case
return #"";
}
NSLog(#"%d", a);
adder = [adder stringByAppendingFormat:#"-%d-", a];
NSLog(#"adder: %#", adder);
// Split this update to make it easier to debug.
NSString *update = innerBlock(a-1, adder);
return [adder stringByAppendingString:update];
};
appendBlock(5, result);
return result;
}
Output: "-5--4--3--2--1-"
This update is rewritten for point #1 (which really has nothing to do with your original issue.
To solve point #2 this update creates the original appendBlock variable as well as a new __block __weak weakBlock reference to the same block. And then inside the block, a new (strong) block pointer is created to reference the weak block pointer. Without the use of the weak pointer, the code works but causes a warning.
int a=1;
int * b;
b = &a;
int **c=&b;
In Objective-C, the Pointer (*) variable is used for primitive data types as well with classes like NSString, NSError etc...
NSString *str = #"iOS"; // or NSString *str= [[NSString alloc] initWithString : #"iOS"];
NSArray *arr =[[NSArray alloc] init];
I have seen in Objective-C (NSError **) what is use of double pointer objects for classes in Objective-C?
There is no such thing as a "double pointer". If you call it a "double pointer", you are just getting yourself confused.
Write a function that should return two ints. You can't have two return values, so you write
void f (int* result1, int* result2)
{
*result1 = 1;
*result2 = 2;
}
Now write a function that should return two NSString*. That should make it obvious.
#import <Foundation/Foundation.h>
int main (int argc, char * argv[])
{
#autoreleasepool {
NSString *str = #"Programming is fun";
NSLog (#"%#", str);
}
return 0;
}
In the line
NSString *str = #"Programming is fun";
the constant string object Programming is fun is assigned to the NSString variable str. Its value is then displayed using NSLog .
The NSLog format characters %# can be used to display not just NSString objects, but other objects as well.
/*****/
The previous paragraph was from a book I read, what is really confusing to me is why is he keep using the words variable and objects interchangeably? are objects and varaibles the same thing? so far this is the only confusing part about obj-c to me.
please explain, thank you
An object is an instance of a class. Something that is allocated in memory.
A variable is a name which you use to access something like an object (NSString for example) or a primitive (int for example).
In your case so your object is an instance of NSString, that contains #"Programming is fun":
NSString *str = #"Programming is fun";
The variable to access that object is str.
For example in this code:
NSString *greeting = #"Hello";
NSLog(#"Greeting message: %#\n", greeting );
Greeting takes the value of a string, not an address. It also displays a string in NSLog and not an address. However, I thought pointers were supposed to be used like this:
int var = 20; /* actual variable declaration */
int *ip; /* pointer variable declaration */
ip = &var; /* store address of var in pointer variable*/
NSLog(#"Address of var variable: %x\n", &var );
/* address stored in pointer variable */
NSLog(#"Address stored in ip variable: %x\n", ip );
/* access the value using the pointer */
NSLog(#"Value of *ip variable: %d\n", *ip );
return 0;
I've always wondered why it's okay to do this with string pointers.
Well, that is something called Syntactic Sugar. What we are actually seeing; exactly doesn't happen like that under the hood.
For example, the code you have written:
NSString *greeting = #"Hello";
NSLog(#"Greeting message: %#\n", greeting );
When you pass greeting into NSLog, actually the following line of code gets executed.
NSLog(#"Greeting message: %#\n", [greeting description]); // description is a method defined in NSObject and NSString inherits it.
And even if you do:
NSString *greeting = #"Hello";
Now, greeting variable doesn't hold the contents of the string, neither it can because it is a pointer. It just holds the address of NSString #"Hello" where it is stored. And again, the assignment of pointer happens under the hood. The same is the case with the C language; we can write the following code in C, and it will compile without any errors:
char *string = "Hello, world!";
In C, the string "Hello, world!" is basically a character array, and string variable actually stores the pointer to this character array.
If you see the definition of NSLog method, it looks something like this:
FOUNDATION_EXPORT void NSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
It clearly shows that NSLog message receives an NSString pointer. But what do we actually pass? We pass the NSString in it, but what is actually passed is a pointer to that NSString, again under the hood :)
I hope this helps you.
%# is the string formatter for NSObjects, calling the objects -description method. If you want the pointer address of the string object try %p.
NSString *string = #"A string";
NSLog(#"Object contents: %#", string);
NSLog(#"Object address: %p", string);
I thought that I knew how to use fast enumeration, but there is something I don't understand about it. If I create three NSString objects and three NSNumber objects and put them in an NSMutableArray:
NSString *str1 = #"str1";
NSString *str2 = #"str2";
NSString *str3 = #"str3";
NSNumber *nb1 = [NSNumber numberWithInt:1];
NSNumber *nb2 = [NSNumber numberWithInt:2];
NSNumber *nb3 = [NSNumber numberWithInt:3];
NSArray *array = [[NSArray alloc] initWithObjects:str1, str2, str3, nb1, nb2, nb3, nil];
then I make do fast enumeration on all NSString objects, like this:
for (NSString *str in array) {
NSLog(#"str : %#", str);
}
In the console, I get this result :
2011-08-02 13:53:12.873 FastEnumeration[14172:b603] str : str1
2011-08-02 13:53:12.874 FastEnumeration[14172:b603] str : str2
2011-08-02 13:53:12.875 FastEnumeration[14172:b603] str : str3
2011-08-02 13:53:12.875 FastEnumeration[14172:b603] str : 1
2011-08-02 13:53:12.876 FastEnumeration[14172:b603] str : 2
2011-08-02 13:53:12.876 FastEnumeration[14172:b603] str : 3
I logged only the NSStrings, but I get a line for every object in the array, even the NSNumbers and I don't understand why. Does fast enumeration always use every object contained in an array?
When you write a forin loop like that, it casts every object in the array as an NSString, then prints them out as requested.
If you want only the NSStrings, you would need to write something like this:
for (id obj in array) {
if ([obj isKindOfClass:[NSString class]]) {
NSLog(#"str: %#", obj);
}
}
The for all loop doesn't know the difference between NSStrings and Integers -- it will simply go through the entire array, cast each as an NSString, and print them out as you asked.
I'm pretty sure that fast enumeration returns all objects in the array- all that you're doing in for (NSString *str in array) is typecasting str to an NSString. In the body of the loop you need to check the class of the returned object to make sure that it is an NSString.
for(NSString *str in array)
{
if([str isKindOfClass:[NSString class]])
NSLog(#"str : %#", str);
}
Objective-C is dynamically typed, meaning that at runtime (when the loop actually runs), objects are all effectively one type (id) with different classes. The language allows optional compile-time static typing, but all that does is check whether the messages you're sending are valid for the type you've marked. It doesn't actually change the behavior of your program. If you cast an object to be a different type than it actually is, all you're doing is lying to the compiler and defeating its type-checker.
Every object that descends from NSObject implements the method - (NSString)description, %# in Objective-C formate string will take the corresponding argument for the %# and call its description method, Most subclasses of NSObject will implement there own version of - (NSString)description. The same thing happens when you type
> po anObject
in the debugger.
for (NSString *str in array) {
is a way to enumerate through all the elements in array.
You expectative that by specifying NSString you get only the objects of that type is not correct. Rather, all the objects pointers are cast to that type (NSString*).
Have a look at Fast Enumeration in The Objective-C Programming Language guide.
I don't understand where is the unexpected behavior, using the enhanced for loop in an NSMutableArray will just iterate thru every single object in the array which in your case is 6, the result is correct and expected.
The numbers will just get casted to Strings.
in fast enumeration no typecasting,just assigning the pointer into new object