Understanding Instantiation in Objective-C - objective-c

I’m currently trying to learn Objective-C by reading books and online tutorials, also referring to the Apple documentation but some things just don’t click. I have a question about classes, I have been using the NSString for a while now without putting too much attention on how it is used.
I was under the impression that in order for someone to be able to use a method from a certain class in Objective-C you first needed to instantiate it, something like…
ClasssName *varName = [[ClassName alloc]init];
Then you would call methods like...
[varName someMethod];
But looking at how the NSString is used I’m now I little confused, for instance here is how we would normally use it...
NSString *someString = #"some text here";
[someString stringByAppendingFormat: #"some text = %d", 3];
Following what I have read about classes we would need to do something like the following instead.
NSString *someString = [[NSString alloc]initWithString: #"some text here"];
[someString stringByAppendingFormat: #"some text = %d", 3];
Can someone explain why some classes do not require instantiation before using its methods?

Objective-C knows some abbreviations that are called literals. The compiler is aware of the special notation. A string literal is compiled into the binary and exits throughout the lifetime of an app.
For most cases it will behave like an object created on runtime.
if two literals are identical, only one object will be created and live forever
if you create NSString *string = [[NSString alloc] initWithString:#"My String"]; with #"My String" being used as a literal before, also string can point to it.
Since Apple LLVM Compiler 4.0 Objective-C knows some more literals. But in contrast to string literals these literals are created during runtime through convenient initializers.
Note that
[someString stringByAppendingFormat: #"some text = %d", 3];
does not change someString. It returns a new string object.
NSString *newString = [someString stringByAppendingFormat: #"some text = %d", 3];

The #"Text" syntax gives you an autoreleased string back, it can be thought of as a shorthand.
when you write
[[NSString alloc]initWithString: #”some text here”];
you conceptually create an autoreleased string with #”some text here” and then you create a retained new string with initWithString.

Related

Should I use defensive copies in Objective C? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I was playing around with mutability, and I came up with the following code in which an immutable object can be cast to a mutable one.
- (NSString *) getaString {
NSMutableString * string = [[NSMutableString alloc] init];
[string appendString:#"This "];
[string appendString:#"was mutable."];
return string;
}
- (void)viewDidLoad {
[super viewDidLoad];
//Get a string returns an NSString, which is then cast to a mutable string with a compler warning.
NSMutableString * string = [self getaString];
[string appendString:#" And apparently still is"];
_showText.text = string;
}
or with no compiler warning
- (NSArray *) getaString {
NSMutableString * string = [[NSMutableString alloc] init];
[string appendString:#"This "];
[string appendString:#"was mutable."];
//Cast to NSString.
NSString * immutableString = string;
NSArray * array = [[NSArray alloc] initWithObjects:immutableString, nil];
return array;
}
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableString * string = [[self getaString] objectAtIndex:0];
[string appendString:#" And apparently still is"];
_showText.text = string;
}
The UITextField shows the whole string of "This was mutable. And apparently still is", with no compiler warning. I've seen multiple SO posts that recommend simply casting or using mutable objects as immutable objects, but as I've just shown, that can be dangerous. Also, the cast still works without the array, but I do get a compiler warning.
My question is, should I be considering using java style defensive copies? I haven't seen any mention of defensive copies in objective C, and all I could find in Apple's documentation was a vague mention that it’s best to adopt some defensive programming practices. I'm concerned both about security and about protecting against careless coding.
The example you've given is misleading.
You are storing a NSMutableString in an array and you are taking it out. Why would you expect the string to be immutable after that?
However there are cases in which defensive copies are pretty much a standard in Objective-C.
Consider a class (let's call it CustomClass) defining a property for an NSString and a method to print it:
#property (nonatomic, strong) NSString *aString;
- (void)printTheString;
Now, since NSMutableString is a subclass of NSString, a client of this class could potentially do something like:
CustomClass *anObject = [CustomClass new];
NSMutableString *aMutableString = [NSMutableString stringWithString:#"Hey!"];
anObject.aString = aMutableString;
[anObject printTheString]; // Hey!
[aMutableString appendString:#" Got you!"];
[anObject printTheString]; // Hey! Got you!
which can be dangerous in some cases.
It has then become common practice to use the copy attribute, instead of strong, for immutable classes with a mutable subclass:
#property (nonatomic, copy) NSString *aString;
In this way a defensive copy is made when the string is assigned, preventing the client to mess with the object later on.
The previous example would then print Hey! both times.
It's also worth noting that for most of this classes sending copy to an immutable object returns the same object, instead of an actual copy. In this way you can have your cake and eat it too, since the copy will be performed only when needed.
I don't know for sure whether you should make defensive copies in Obj-c, but it is possible to make mutable copies of an immutable string, and it is possible to make immutable versions of a mutable string.
There aren't any immutable strings in your code, by the way. NSMutableStrings in an NSArray are still mutable, so you aren't doing any conversion. The array is the thing that cannot have objects appended to it.
Here's why: The array is just holding a pointer to the NSMutableString, not the actual object, so you're not changing the contents of the array by changing the contents of the string, because the memory address pointed to by the array stays the same.
Example:
NSString *original = #"Hello, world!";
// putting the original in a mutable string
NSMutableString *copy = [original mutableCopy];
NSArray *array = [NSArray arrayWithObjects:copy, nil];
// the object in the array can still be modified
[[array objectAtIndex:0] appendString:#" Goodbye, cruel world!"];
// make an immutable version of the mutable string
NSString *copyOfTheCopy =[NSString stringWithString:[array objectAtIndex:0]];
NSLog(#"%#", [array objectAtIndex:0]);
// just to make sure...
[[array objectAtIndex:0] appendString:#"Got you!"];
NSLog(#"%#", [array objectAtIndex:0]);
NSLog(#"%#", copyOfTheCopy);
The output should be:
2013-11-03 21:16:06.099 SomeProject[7045:303] Hello, world! Goodbye, cruel world!
2013-11-03 21:16:06.100 SomeProject[7045:303] Hello, world! Goodbye, cruel world!Got you!
2013-11-03 21:16:06.100 SomeProject[7045:303] Hello, world! Goodbye, cruel world!
Another answer given by Gabriele Petronella caused me to make a change that gets rid of one of those gotchas with pointers. This one doesn't use a pointer to the NSMutableString and instead makes a new string from the old one. Sorry I can't vote you up yet, you taught me something :)
If you're looking to obtain an immutable NSString from an NSMutableString, you can do something like this:
NSString *anImmutableString = [NSString stringWithString: aMutableString];
So if we take your original code in the question, and I'm going to assume that your viewDidLoad is where you want an immutable string:
- (NSArray *) getaString {
NSMutableString * string = [[NSMutableString alloc] init];
[string appendString:#"This "];
[string appendString:#"was mutable."];
NSArray * array = [[NSArray alloc] initWithObjects:string, nil];
return array;
}
- (void)viewDidLoad {
[super viewDidLoad];
NSString *string = [NSString stringWithString:[[self getaString] objectAtIndex:0]];
//[string appendString:#" And apparently still is"];
_showText.text = string;
}
Now, if you still want to append to string in viewDidLoad, you can, but you'd have to do it differently (the same way you append to any other NSString). It'd look something like this:
NSString *newString = [string stringByAppendingString:#" And apparently still is"];
Now look at the contents of the variables.
string = "This was mutable." //as you built it from an NSMutableString in the getaString method
newString = "This was mutable. And apparently still is" //as built from calling "stringByAppendingString" method on your variable string in viewDidLoad
It's important to note that the contents of newString are quite misleading here. newString is not an NSMutableString. It's a regular NSString. Calling stringByAppendingString returns an NSString that is the result of appending the argument you send to the end of the NSString you're calling the method on. (And the contents of the NSString you called the method on remain unchanged--it's immutable).
If you would like newString to be an NSMutableString, you'll have to do something like this:
NSMutableString *newString = [[string stringByAppendingString:" And apparently still is"] mutableCopy];

Objective-C: What is the difference between creating an object from alloc/init and class method calls?

For example,
NSString *string = [NSString stringWithString:#"a string"];
NSString *string = [[NSString alloc] initWithString:#"a string"];
and while we're talking about strings, is there any difference by setting up a string with:
NSString *string = #"a string";
?
As a final note, this isn't a specific question about NSString. I'm asking on a wider scope of all NSObjects.
There is no difference in ARC, but prior to it there was a difference: alloc/init returns an item with ref count of at least one that you'd need to release when you don't need it, while the class method returns an autoreleased item that you'd need to retain if you would like to keep it. The ARC compiler knows all this, and takes care of retaining/releasing for you based on your ownership specifications.

Why are these two NSString pointers the same?

When I alloc and init two NSString variables and compare their pointers, they are the same. Here's a snippet that shows this:
NSString *s1 = [[NSString alloc] initWithString:#"hello world"];
NSString *s2 = [[NSString alloc] initWithString:#"hello world"];
if (s1 == s2) {
NSLog(#"==");
}else {
NSLog(#"!=");
}
Why are s1 and s2 the same?
There are three things going on here:
Firstly, the two identical string literals you're passing in to initWithString: will have the same address to start. This is an obvious optimization for constant data.
Secondly, when you nest alloc and init with strings, the runtime performs an optimization, the alloc call essentially becomes a no-op. This is done using the NSPlaceholderString class. This means the pointer you get back here will be coming from initWithString:, not from alloc.
Thirdly, under the hood, initWithString: is calling CFStringCreateCopy, which as you may find, has the following behavior: Since this routine is for creating immutable strings, it has an optimization. It simply calls CFRetain() and returns the same object that was passed in.
Thanks for the very interesting question. I had fun figuring it out.
#"hello world" strings are of class NSConstantString.if you use #"hello world" in two places, they will be referencing the very same object.
From documentation.
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, though you can retain
and release them as you do any other object. You can also send
messages directly to a string constant as you do any other string:
BOOL same = [#"comparison" isEqualToString:myString];

Assign to NSString after alloc/init

This doesn't seem to work:
NSString *string = [[NSString alloc] init];
string = #"%#M", anotherstring;
I expect this to make "string" equal to "5M" if "anotherstring" is "5".
Is this not the right syntax? Now, I could use initWithFormat and it would work, but how can you separate it into two different lines and also work?
There are two mistakes in your code. Firstly, NSStrings are immutable, and once you allocate and initialize them, they're set, and there's no way to change them. For that, you'd have to look into NSMutableString.
Secondly, the syntax of your code makes no sense. #"%#M", anotherString is not a valid Objective-C method call. You are indeed looking for -initWithFormat: to perform the operation you want. The code should look like this:
NSString *string = [[NSString alloc] initWithFormat:#"%#M", anotherString];
Read more about NSString and how to use it in the NSString Programming Reference document, and the String Programming Guide to get a sense of how to work with strings in Cocoa and Objective-C.
This line:
string = #"%#M", anotherstring;
is syntactically correct, but it doesn't do what you want it to do. This is how you format a string:
NSString *string = [[NSString alloc] initWithFormat:#"%#M", anotherstring];
There's no point in separating it into two lines. This:
NSString *string = [[NSString alloc] init];
string = [[NSString alloc] initWithFormat:#"%#M", anotherstring];
will create an extra NSString object, and also cause a memory leak.
How about
NSString* string;
string = [[NSString alloc] initWithFormat:#"%#M", anotherString];
Keep in mind that the = operator is assignment. Any time you use it, any value was stored in your variable is overwritten with the new one. So even if your original code was syntactically correct it still has faulty semantics that would, in this case, cause a memory leak.
just make it into a property and you dont need to worry about releasing and retaining the "string" (that is if you autocreate it by using synthesize). and dont forget to autorelease the object ur assigning to the property:
self.string = [[[NSString alloc] init] autorelease]

confused about NSString *str

I am kind of confused by the behavior of NSString *str..
I assigned it in several ways, sometimes it works, and sometimes it becomes null.
NSString *str = #"/hi/hello"; // this one always works
// this sometimes becomes null after the function ends
NSString *str2 = [str lastPathComponent];
// as above
NSString *str3 = [NSString stringWithString:str2];
NSString *str4 = [NSString initWithString:str3];
I am not quite familiar with the object behavior of Obj-C, is it just like C++?
If so, how can I do assignment safely like
string str = "hi";
string str2 = str;
behaves in C++?
ex: I declare a string in my .h file,
how to assign it safely that it wouldn't become NULL after a function ends?
I know it's a very basic question, but I can't find the answer in NSString reference page.
Really thanks for any help!
The behaviour is not just like C++. Objects are reference-counted. If you want to keep one around, you must place a claim on it.
If you create the object yourself with a method whose name includes the word alloc, new or copy then you have ownership already. This is like a C++ new. (When you have created an object with alloc, you need also to initialise it with some method whose name begins init. But you have to create it first. In C++ both things would be considered parts of the single act of construction.)
Objects you receive from other methods (such as two of the three NSString methods you mention) are only transiently available unless you explicitly claim ownership by calling [object retain]. You only need to do this if you want to keep them around beyond the immediate context. (There isn't really an equivalent to this in C++.)
However you gain ownership, you must relinquish it when you are finished by calling [object release]. This sort of like a C++ delete, except that the object isn't actually destroyed until all ownership claims are released.
Getting to grips with this is really really really important, perhaps the only important thing you need to know to use Objective-C. Read the object ownership documentation carefully and you'll be sorted.
I assume you're not using garbage collection? If this is the case then you need to retain the string.
NSString* str2 = [[str lastPathComponent] retain];
I suggest you do some reading on objective-c memory management.
NSString *str = #"/hi/hello";
This works because it creates a string literal. Answers to this question are worth a read to understand these in Objective-C
What's the difference between a string constant and a string literal?
In all these cases you are creating autoreleased strings. These will be deallocated when you return to the application's runloop.
NSString *str2 = [str lastPathComponent];
NSString *str3 = [NSString stringWithString:str2];
In this last one I assume you meant [[NSString alloc] initWithString:str3]
This creates a string that is retained. But this isn't a good way to create static strings.
You should create static strings in your implementation file like this
static NSString *myConstant = #"constantString"