Is it a variable or an object? Im very confused - objective-c

#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.

Related

Objective-C Noob: How to define + call a method in main?

I wrote a method that works inside of an object, but now I want to extract it so that it's just a function. This is my broken command line tool program:
#import <Foundation/Foundation.h>
+ (NSMutableString *)reverseString:(NSString *)originalString {
NSMutableString *reversedString = [[NSMutableString alloc] init];
for (NSInteger i = originalString.length; i > 0; i--) {
[reversedString appendFormat:#"%c", [originalString characterAtIndex:i-1]];
}
return reversedString;
}
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSString *originalString = #"original string";
NSMutableString *newString = [reverseString:originalString];
NSLog(#"Reversed string: %#", newString);
}
return 0;
}
My question is, how would I call the reverseString method from main()? I don't think I'm defining it properly. Do I have to declare it too? I know that the contents of my method work fine, but I don't know how to define it in a way that allows main to see it.
A "method" is, by definition, part of a class. There are two types, instance methods and class methods. To invoke an instance method, you need, well, an instance of the class. To invoke a class method, you don't need an instance. You can just invoke it directly on a class.
By contrast, there are also "functions". You don't need an instance or a class to invoke a function.
So, it sounds like you want a function. Functions are something that Objective-C inherits from C. The syntax for functions is different from the syntax for methods. Here's how your code might look using a function:
NSMutableString* reverseString(NSString *originalString) {
NSMutableString *reversedString = [[NSMutableString alloc] init];
for (NSInteger i = originalString.length; i > 0; i--) {
[reversedString appendFormat:#"%c", [originalString characterAtIndex:i-1]];
}
return reversedString;
}
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSString *originalString = #"original string";
NSMutableString *newString = reverseString(originalString);
NSLog(#"Reversed string: %#", newString);
}
return 0;
}
By the way, your code does not "work fine". You can't iterate through a string by what it calls "characters" and treat all of them as independent. What NSString calls "characters" are actually UTF-16 code units. Not all Unicode characters can be expressed as single UTF-16 code units. Some need to use two code units in what's called a surrogate pair. If you split up and reverse a surrogate pair, you'll get an invalid string.
As a separate issue, Unicode has combining marks. For example, "é" can be expressed as U+0065 LATIN SMALL LETTER E followed by U+0301 COMBINING ACUTE ACCENT. Again, if you reorder those "characters", the accent will combine with a different character (or fail to combine at all).
The correct way to iterate through the composed character sequences of a string is to use the -[NSString enumerateSubstringsInRange:options:usingBlock:] method with the NSStringEnumerationByComposedCharacterSequences option.
By "I want to extract it so that it's just a function" you're implicitly saying "I want a C-style function, not an Objective-C class method". C-style functions are declared and called differently (blame history).
static NSMutableString * reverseString(NSString * originalString) {
...
}
...
NSMutableString *newString = reverseString(originalString);

Why does a string pointer in Objective-C accept and return the value of the string and not a memory address?

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);

Why dereferencing a NSString pointer is not necessary?

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.

Converting char array into NSString object

As per my assignment I have to take in input from a user via a console to be used with NSString.
At the moment I have
char* name[100]; // declaring char array
NSString* firstName; // declaring the NSString
printf("Please enter first name \n");
printf("=> ");
scanf("%s", &name);
firstName = [NSString stringWithCString:name encoding:NSASCIIStringEncoding];
This works, however I am getting this warning
Incompatible pointer types sending 'char [100]' to parameter of type
'const char '
I don't want to be having these errors coming up in the code, I would like to also mention I'm using Xcode 4.2.
Can anyone explain to me why I'm getting these errors, and if I can possibly overcome them?
Many thanks in advance!
Change this:
char* name[100];
to
char name[100];
The first form creates an array of 100 pointers to char. The second one creates an array of 100 char elements. What might be confusing, is that name in that last case, is in fact a pointer, pointing to the first of these 100 char elements.
As printed with NSLog is assigned to initialize a NSString.
NSLog(#"%s", arrayChar);
NSString *str = [NSString stringWithFormat:#"%s", arrayChar];
NSLog(#"Array to String: %#",str);

incorrect variable value outside main()

i have this code
#import <Foundation/Foundation.h>
int testint;
NSString *teststring;
int Test()
{
NSLog(#"%d",testint);
NSLog(#"%#",teststring);
}
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
testint = 5;
NSString *teststring = [[NSString alloc] initWithString:#"test string"];
Test();
[pool drain];
return 0;
}
in output i have:
5
(null)
why Test function doesn't see correct teststring value? What should I do, to have correct "test string" in output?
You're shadowing a global variable with a local one. If the intent is to use the global testString, you shouldn't re-declare it with "NSString*".
in output i have:
5 (null)
why Test function doesn't see correct teststring value?
Because you never assigned anything there. In main, you declared a local variable with the same name, and initialized that variable with the pointer to the NSString object you created.
how should i declare global objects with "alloc init"?
You don't.
Declarations create variables (or sometimes types). The NSString *teststring lines (both of them) are declarations: One of a global variable, the other of a local variable.
alloc messages (and most other messages to classes) create objects.
Thus, this line:
NSString *teststring = [[NSString alloc] initWithString:#"test string"];
declared a local variable (teststring) and created a string object, and initialized the variable to hold the pointer to the string object.
(Note that “initWithString:” initializes the object, not the variable. The part from the = until the semicolon is the initializer for the variable.)
You meant to assign to the global variable, not declare a local variable. So, do that: Leave out the type specifier to turn the declaration into an assignment statement:
teststring = [[NSString alloc] initWithString:#"test string"];
By the way, you don't need to use alloc and initWithString: here. #"test string" is already an NSString object. And when you do alloc something, don't forget to release it (assuming you didn't turn on the GC).
You have two different variables named testint. The one in main() is shadowing the global one.
how should i declare global objects with "alloc init"?
Strings are a special case. You can do this:
NSString* foo = #"bar";