Pass by value vs Pass by reference - objective-c

I have been looking into some basics over the last couple days and I realized that i never truly understood why pass-by-reference for NSString/NSMutableString did not work.
- (void)testing{
NSMutableString *abc = [NSMutableString stringWithString:#"ABC"];
[self testing:abc];
NSLog(#"%#",abc); // STILL ABC
}
-(void)testing:(NSMutableString *)str {
str = [NSMutableString stringWithString:#"HELP"];
}
How do i go about this? I want my testing method to be able to manipulate the String from the main method. I have been using this with Mutable Arrays, dictionary etc and works fine. Feels strange that I never realized how this works with Strings.
But the value gets changed in something like this which is a reference to the first string
NSMutableString *string1;
NSMutableString *string2;
string1 = [NSMutableString stringWithString: #"ABC"];
string2 = string1;
[string2 appendString: #" HELP"];
NSLog (#"string1 = %#", string1); // ABC HELP
NSLog (#"string2 = %#", string2); // ABC HELP

Like Java, Objective-C has only passing and assigning by value. Also like Java, objects are always behind pointers (you never put the object itself into a variable).
When you assign or pass an object pointer, the pointer is copied and points to the same object as the original pointer. That means, if the object is mutable (i.e. it has some method that mutates its contents), then you can mutate it through one pointer and see the effects through the other one. Mutation is always achieved by calling a method, or assigning to a field directly.
-(void)testing:(NSMutableString *)str {
[str setString:#"HELP"];
}
Assigning to a pointer never mutates the object it points to; rather, it makes the pointer point to another object.

I cannot in good conscious let this wrong answer linger on the internet.
Pass by reference in objective c is POSSIBLE; which is why it is better than Java.
Here's how:
- (void)testing
{
NSMutableString *abc = [NSMutableString stringWithString:#"ABC"];
[self testingHelper:&abc];
NSLog(#"%#", abc); // NOW HELP
}
- (void)testingHelper:(NSMutableString **)str {
*str = [NSMutableString stringWithString:#"HELP"];
}

Related

How do I put a pointer to an NSString pointer into a NSDictionary?

I would like to put a pointer to an NSString pointer into an NSDictionary, and naturally, get it back out again. But I can't figure out the syntax.
I think is is something like
NSString* myString = #"Hi";
NSString**myStringPointer = myString;
NSDictionary* dictionary = #{#"pointer":myStringPointer};
But that is clearly not correct.
I am trying to change what string an NSString points to inside a selector.
-(void) updateString:(NSString*) aString {
aString = #"Hello World"; //
}
-(void) testUpdateString {
NSString *textString = #"TEST";
[self updateString:testString];
// testString still is #"TEST";
}
Thank you.
You can only put (pointers to) things that inherit from NSObject in an NSDictionary; a pointer to (a pointer to) an NSString isn't such an object. You can wrap it in an NSValue to store it in a dictionary.
NSDictionary *dictionary = #{ #"pointer": [NSValue valueWithPointer:myStringPointer], };
While it's worth being aware of the general idea of wrapping things that couldn't otherwise be put into an NSDictionary, NSArray, etc., in NSValue for this purpose, I can't think of a good reason to store an NSString ** in an NSDictionary, so it might be better to look at why you're trying to do that and whether there's a better way to achieve your larger goal.
You don't need a dictionary here, you can pass the object by reference to the updating
method:
-(void) updateString:(NSString **) aString {
*aString = #"Hello World";
}
-(void) testUpdateString {
NSString *testString = #"TEST";
[self updateString:&testString];
}
(If you are curious what actually happens behind the scenes, look up
__autoreleasing in the "Transitioning to ARC Release Notes".)

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

Repointing a pointer inside an Objective-C method

Firs of all, sorry if my english is not absolutely correct. It's not my native language but I'll try to explain myself the best I can.
I'm having a hard time trying to understand the following issue. Take in account the following code:
// On a class named SPOTest
- (void)referenceTest:(NSMutableString *)originalText
{
[originalText appendString:#" world!!!"]
}
// From another place
NSMutableString *myText = [NSMutableString stringWithString:#"Hello"];
NSLog(#"Contents of myText BEFORE: %#", myText);
SPOTest *myTest = [[SPOTest alloc] init];
[myTest referenceTest:myText];
NSLog(#"Contents of myText AFTER: %#", myText);
The output:
Contents of myText BEFORE: Hello
Contents of myText AFTER: Hello world!!!
I find it understandable. I'm working with pointers so if I change the thing and the end of a pointer, I'm changing that thing for all the pointers pointing to it. On the other hand, if I change the code and do this:
// On a class named SPOTest
- (void)referenceTest:(NSMutableString *)originalText
{
NSMutableString *newText = [NSMutableString stringWithString:#"Hello world!!!"];
originalText = newText;
}
// From another place
NSMutableString *myText = [NSMutableString stringWithString:#"Hello"];
NSLog(#"Contents of myText BEFORE: %#", myText);
SPOTest *myTest = [[SPOTest alloc] init];
[myTest referenceTest:myText];
NSLog(#"Contents of myText AFTER: %#", myText);
Then I get this:
Contents of myText BEFORE: Hello
Contents of myText AFTER: Hello
Why is that? I suppose the correct way to do this is to use a double indirection and an implementation similar to the one used with NSError mechanism but I want to understand why I'm obtaining this behavior. If I can change the contents and the end of myText pointer from the referenceTest: method in the first example, why can't I change the address of myText from the same method in the second example?
I know I'm missing something trivial but I can't find it and I'd like to understand this to better understand the reasoning behind NSError mechanism.
Thank you!
In the second case you're changing the local copy of that pointer. If you want to repoint it in the calling scope, you'd need to use a pointer to a pointer, i.e.:
- (void)referenceTest:(NSMutableString **)originalText
{
NSMutableString *newText = [NSMutableString stringWithString:#"Hello world!!!"];
*originalText = newText;
}
And call it thusly:
[myTest referenceTest:&myText];
And it is worth noting that stringWithString returns an autoreleased string, which means your function is too.
There's a difference between objects and pointers to objects.
Someone has created an NSMutableString object, which exists somewhere in memory. We don't really care where it is. That someone received an NSMutableString* which points to the NSMutableString object. A copy of that NSMutableString* was given to your method referenceTest. There can be any number of pointers to that NSMutableString object, but there is only one object.
The appendString method changes the NSMutableString object itself.
The stringWithString method creates a new NSMutableString object and returns a pointer to it. So now we have two objects, and newText is a pointer to the second one. When you assign newText to originalText, originalText becomes a pointer to the second NSMutableString object. However, originalText is just the parameter in your method. The pointer that the calling method holds isn't changed by this.

If I want to make a new instance of an object in a function whose pointer is passed by reference in it

- (void)createAString:(NSString **)str
{
*str = [NSString stringWithString:#"Hi all!"];
[*str autorelease]; // ???? is this right ?
}
How should I use release or autorelease ? I don't want to release outside of the function of course :)
...
NSString *createStr;
[self createAString:&createStr];
NSLog(#"%#", createStr);
You're correct that you'd generally want to return autoreleased (or the like) objects from out params when you use this form. Your assignment statement in the function that sets *str to a string:
*str = [NSString stringWithString:#"foo"];
is already doing the right thing, because that method returns an instance of NSString that the caller doesn't own. Just like you could return this string object from your function without any further memory management, you can set it as the outparam as you've done. Your second snippet showing the call site is fine.
This said, I'm worried about a few things in your code that you should be sure you understand:
The value of str inside the method is still a **, and sending that a message (as you've done for the speculative autorelease) is nonsense. Be sure you fully understand doubly indirected pointers before using them too liberally. :) If you need to send str a message after creating it, send it to *str, which is what contains the NSString *.
Setting an outparam like this when the function returns void is not idiomatic Cocoa. You would normally just return the NSString * directly. Outparams are rare in Cocoa. (Usually just NSErrors get this treatment from framework calls. Otherwise they conventionally use name like getString to differentiate them from normal get accessors which don't use the word "get".)
I hope -stringWithString was just an example. That method is almost never used in practice, since it's equivalent (in this case) to just using a #"string literal" (although that would muddy your example).
Instead of using a double pointer, would it not be more elegant to use an NSMutableString instead?
- (void)createAString:(NSMutableString *)str
{
[str setString:#"Hi all!"];
}
....
NSMutableString *createStr = [[NSMutableString alloc] init];
[self createAString: createStr];
NSLog(#"%#", createStr);
[createStr release];
Or, even better, just have the createAString method return an NSString.
- (NSString *)createAString
{
return #"Hi all!"; // this is autoreleased automatically
}
I wouldn't want to presume that your needs are this simple, though. =)

Objective C /iPhone : Is it possible to re initialize an NSArray?

I read that non mutable data types can't be modified once created.(eg NSString or NSArray).
But can they be re-initialized to point to a different set of objects?
If so, do I use release to free any alloc from first time round in between uses? eg:
myArray declared as NSArray *myArray in interface, and as nonatomic/retain property.myArray set in initialization code to a point to an array of strings as follows.
self.myArray = [myString componentsSeparatedByString:#","];
But later I want to re-initialize myArray to point to a different set of strings
self.myArray = [myOtherString componentsSeparatedByString:#","];
Is it possible? Thanks...
It really depends what you mean with re-initialize. You can assign another immutable object to a pointer, because the pointers aren't constant.
Example:
#interface MyObj : NSObject {
NSString *name; // not needed in 64bit runtime AFAIK
}
#property(retain) NSString *name; // sane people use copy instead of retain
// whenever possible. Using retain can
// lead to some hard to find errors.
#end
/* ... another file ... */
MyObj *theObject = [[[MyObj alloc] init] autorelease];
theObject.name = #"Peter";
NSString *oldName = theObject.name;
NSLog(#"%#", theObject.name); // -> Peter
NSLog(#"%#", oldName); // -> Peter
theObject.name = #"Martin";
NSLog(#"%#", theObject.name) // -> Martin
NSLog(#"%#", oldName) // -> Peter
If the behavior above is what you want, that's fine.
If you want that last line to return Martin you're in trouble. Those are constant strings and are not meant to be modified. You could, if you really want, modify the memory of the object directly, but this is dangerous and not recommended. Use mutable objects if you need such behaviour.
Yes you can reinitialized the NSArray. Here is the sample code that i used to re-initialized the NSArray.
NSString *keywords = #"FirstName|LastName|Address|PhoneNumber";
NSArray *arr = [keywords componentsSeparatedByString:#"|"];
NSLog(#"First Init - %#,%#,%#,%#",[arr objectAtIndex:0],[arr objectAtIndex:1],
[arr objectAtIndex:2],[arr objectAtIndex:3]);
arr = nil;
keywords = #"First_Name|Last_Name|_Address|_PhoneNumber";
arr = [keywords componentsSeparatedByString:#"|"];
NSLog(#"Second Init - %#,%#,%#,%#",[arr objectAtIndex:0],[arr objectAtIndex:1],
[arr objectAtIndex:2],[arr objectAtIndex:3]);
Of course they can. Saying that an NSArray is immutable doesn't mean that an attribute of a class of that type cannot be changed. You can't change the content, but you can assign new content to it.
If you want to make also changing the reference impossible you should use const keyword.