How to assign another object to point single object? [duplicate] - iphone

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
NSString immutable allows to change its values?
I want to point to an object where in, if I make changes to one object. the same change has to reflect to other object. How to do that?
I have done a sample, but it is not working.
Please check the code once. What is the mistake in my code?
-(void)viewDidLoad{
str = [[NSString alloc] initWithString:#"Taruni"];
str2=str;
str2=#"Kalpana chawla";
[self changeStr:str];
NSLog(#"str = %#",str);
[str release];
[str release];
[super viewDidLoad];
}
-(void)changeStr:(NSString *)x
{
x=#"Chandra";
}
In .h file, I have declared in this way
#property(nonatomic,assign) NSString *str;
#property(nonatomic,assign) NSString *str2;
If I change the value of str2, str is not getting reflected.
How to do that?

Try below code,
-(void)viewDidLoad{
NSString *str = [[NSString alloc] initWithString:#"Taruni"];
NSString **str2 = &str;
*str2=#"Kalpana chawla";
[self changeStr:&str];
NSLog(#"str = %#",str);
[str release];
[str release];
[super viewDidLoad];
}
-(void)changeStr:(NSString **)x
{
*x=#"Chandra";
}

First of all, if you want to change the content of a string you need NSMutableString.
Second of all, in your changeStr: method you did nothing but assigned the "x" pointer to point to another string (and x is local).. In method your pointer "x" is local and assignment (x = something) will not reflect outside of that method. If you want to change something outside you will have to use x.propertyName or [x methodName]. If you want to change your input as to what string does it point to, you need input as :(NSString **)x, then *x = #"Chandra" and [self changeStr:&str].
Third of all, you can not change constant strings (defined like this: #"constant string"), you will have to use [NSString stringWithFormat:#"%#", str] (rather yet NSMutableString for your purpose)

Related

use of titleForState and initWithFormat in objective c

I am a mere beginner in iPhone Programming. I have seen this code in a tutorial which I didn't understand what does it means. I am confused about keywords such as titleForState and initWithFormat.
Can anyone help me to understand the meaning and importance of this syntax.
-(IBAction)buttonPressed: (id)sender {
NSString *title = [sender **titleForState**:UIControlStateNormal];
NSString *newText = [[NSString alloc] **initWithFormat**:
#"%# button pressed.", title];
statusText.text = newText;//statustext is a label
[newText release];
}
initwithFormat allows you to modify a string by adding a variable's value to it, you can add as many variables as you like but you have to add the correct symbol for the correct primitive type. Here are some examples
NSString *thisIsAString = #"String";
float thisIsAFloat = 13.9f;
NSString *strFormat = [[NSString alloc] initWithFormat:#"This is a %#, this is a %f float", thisIsAString, thisIsAFloat];
NSLog(#"%#", strFormat);
This will produce the output This is a String, this is a 13.9f float notice the float and the NSString value have replaced the symbols.
The titleForState is getting the title of an object that has that method. This will return the title for lets say a UIButton that has a title of "Press" for UIControlStateNormal so the value "Press" will be entered into the NSString title. Not though that not everything in sender has the method titleForState the reason this will show up is because sender is a primitive type of id this will cause and error if something is sent that hasn't got titleForState and your app will crash.

Retained NSString in AppDelegate lost after a PushScene

In my AppDelegate, near the end of the init method, I call a [self setup] method. This method gets a string from a URL, trims it, and assigns the string to a property called _songDirectory.
Here's how it looks in the header file:
#property (retain) NSString *_songDirectory;
And here is how it is assigned in the [setup] method:
//set a URL string
NSString *urlString = [NSString stringWithFormat:#"http://www.blahblahblah.com/php/dev/blah.php?routine=blah"];
NSMutableString *infoString = [self getInfoStringFromURL: urlString];
//get the song directory as a string from the infostring
NSRange startIndex = [infoString rangeOfString:#"song_directory=="];
NSRange endIndex = [infoString rangeOfString:#"end_of_data=="];
_songDirectory = [NSString stringWithString: [infoString substringWithRange: NSMakeRange(startIndex.location + startIndex.length, endIndex.location - startIndex.location - startIndex.length)]];
NSLog(#"STRING IN APP DELEGATE: %#", _songDirectory);
NSLog prints the correct string when called in the app delegate. However, after I push a new scene I cannot access _songDirectory from it. The following code in the pushed scene yields EXC_BAD_ACCESS:
NSLog(#"STRING IN PUSHED SCENE: %#", [[[UIApplication sharedApplication] delegate] _songDirectory]);
I can use the above statement to get ints from the app delegate but not strings. I would appreciate some insight!
You're assigning the string directly to the instance variable and not to the property, therefore the string is not retained. It should be self._songDirectory = ... instead of _songDirectory (and you should probably call the property songDirectory, the leading underscore is usually only used for private instance variables).
You need to use:
self._songDirectory = [NSString stringWithString: [infoString substringWithRange: NSMakeRange(startIndex.location + startIndex.length, endIndex.location - startIndex.location - startIndex.length)]];
in order to get the property to work. Otherwise you are just setting the ivar directly and the retain doesn't happen.

Why does this cause a crash?

I have these two buttons hooked up to these two methods (they're nearly identical)
-(void)moveOneImageNewer{
int num = [numberOfImage intValue];
num--;
numberOfImage = [[NSString stringWithFormat:#"%i",num] retain];
//Load the image
[self loadImage];
}
-(void)moveOneImageOlder{
int num = [numberOfImage intValue];
num++;
numberOfImage = [NSString stringWithFormat:#"%i",num];
//Load the image
[self loadImage];
}
If I hit either of them twice (or once each, basically if they get called a total of two times) I get an EXC_BAD_ACCESS. If I throw a retain on: numberOfImage = [[NSString stringWithFormat:#"%i",num]retain] it's fine though. Can someone explain why this is? I did an NSZombie on the instruments and traced it back to this stringWithFormat call. Thanks in advance!
+stringWithFormat: doesn't contain 'new', 'alloc', 'copy', or 'retain', so it should be expected that you have to retain the return value of it if you want the new NSString it creates to stick around.
Edited to include this handy link duskwuff kindly dug up: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html#//apple_ref/doc/uid/20000994-BAJHFBGH
If numberOfImage is a properly declared property, e.g.
#property (copy) NSString *numberOfImage;
and it was properly synthesized (in the #implementation section for the class):
#synthesize numberOfImage;
then you can do:
- (void) moveOneImageNewer
{
self.numberOfImage = [NSString stringWithFormat: #"%i", [self.numberOfImage intValue] - 1];
// Load the image
[self loadImage];
}
The property setter will take care of retaining the string and, if necessary, releasing the previous string.
FWIW, why on earth is numberOfImage a string? Why not a simple int?
numberOfImage is an instance variable or property of your class, right?
You are setting it to a stringWithFormat (which returns an auto-released NSString) without claiming ownership of that object (by calling retain).
If you do not retain it, it will get auto-released before the method is called again (and then the first line will fail, as it tries to access the previously set, now auto-released value).
Consider using properties, they have auto-generated memory management code (including releasing the old NSString when you set the new one).
You haven't retained the string object in "moveOneImageOlder", so that object gets autoreleased at the end of the event cycle and points to nothing. That's why you get the EXC_BAD_ACCESS next time you try to use it.
Use a retain to claim ownership of the NSString. Remember to release when you're done though (you can use properties to help you with this)
-(void)moveOneImageNewer{
int num = [numberOfImage intValue];
num--;
[numberOfImage release];
numberOfImage = [[NSString stringWithFormat:#"%i",num] retain];
//Load the image
[self loadImage];
}
-(void)moveOneImageOlder{
int num = [numberOfImage intValue];
num++;
[numberOfImage release];
numberOfImage = [[NSString stringWithFormat:#"%i",num] retain];
//Load the image
[self loadImage];
}
Add this in dealloc:
- (void)dealloc {
[numberOfImage release];
[super dealloc];
}
Well, the NSString class method "stringWithFormat" returns an autorelease NSString object if I'm right.
So the second call to your method would have numberOfImage pointing to nothing, as the autorelease NSString object it used to be pointing to has already been released and deallocated since you didn't retain it.
The part that is directly causing the crash is [numberOfImage intValue] when you call the method a second time, as you sending a message to an object (pointed to by numberOfImage) that no longer exist.

Potential memory leak

I work on a project on iPhone iOS with Xcode 4.
With Xcode > Product >Analyze I get 35 issues, all of this type:
myTextField.text = [[NSString alloc] initWithFormat:#"0.2f", abc];
and the problem is "Potential leak of an object allocated at ..."
What is the offending object and how can I release it?
Thanks
You're leaking the string that you're assigning to myTextField.text. When this assignment happens, a copy is being made (look at the property definition in the documentation). In most cases, when values are immutable, as is the case with NSStrings, a copy will give you an instance that points to the same location as the object that is being copied, with the retain count incremented by 1.
In the case of your code:
myTextField.text = [[NSString alloc] initWithFormat:#"0.2f", abc];
The retain count of the string that you've allocated is 2.
You will either need to (1) release, (or autorelease) the string, or (2) use one of the NSString convenience methods, e.g. stringWithFormat: to create the string. This will give you an autoreleased string so you won't have to worry about explicitly releasing it.
(1)
NSString *str = [[NSString alloc] initWithFormat:#"0.2f", abc];
myTextField.text = str;
[str release]
or
myTextField.text = [[[NSString alloc] initWithFormat:#"0.2f", abc] autorelease];
(2)
myTextField.text = [NSString stringWithFormat:#"0.2f", abc]; // autoreleased
You are responsible for releasing string object you create here - as you use alloc/init for that.
The most convenient way here to set a string is to use class method +stringWithFormat that returns autoreleased string - so system will release that string object for you later:
myTextField.text = [NSString stringWithFormat:#"0.2f", abc];
Or you can write autorelease explicitly if you want:
myTextField.text = [[[NSString alloc] initWithFormat:#"0.2f", abc] autorelease];
If you don't want to use autorelease you can use temporary variable to create new string and release it after it was set for text field:
NSString *tempString = [[NSString alloc] initWithFormat:#"0.2f", abc];
myTextField.text = tempString;
[tempString release];
The thing is that UiTextFields's text property is declared as:
#property(nonatomic, copy) NSString *text
Therefore in this line:
myTextField.text = [[NSString alloc] initWithFormat:#"0.2f", abc];
A new NSString is created with a retain count of 1, and then myTextField.text copies this object and increased its retain count by 1 or does it??, lets see what is happening:
A NSString object created with alloc initWithFormat with a retain count of 1
A NSString object with is a copy of the previous String, but because NStrings are immutable in this case, copy returns the same object!, therefore the NSString actually has a retain count of 2.

Can't get an NSString ivar to accept a value from an array

I am storing some data (some floats, some strings) to a plist and then reading them back. When I read them back, I assign them to some ivars in my view controller. They are just ivars, not properties.
The floats take their values fine and I can NSLog them and see that they are correct. But no matter what I try, I can't get my NSString ivars to take the string values.
Example: array positions 6 and 7 have the strings Portland, OR" and "Pacific Daylight Time" stored in them - read back from the plist into *array.
This:
cityName = [NSString stringWithFormat:#"", [array objectAtIndex:6]];
timeZoneName = [NSString stringWithFormat:#"", [array objectAtIndex:7]];
NSLog(#" >cityName from array = %#, and now the iVar is = %#", [array objectAtIndex:6], cityName);
NSLog(#" >timeZoneName from array = %#, and now the iVar is = %#", [array objectAtIndex:7], timeZoneName);
Results in this:
>cityName from array = Portland, OR, and now the iVar is =
>timeZoneName from array = Pacific Daylight Time, and now the iVar is =
I put a breakpoint at the end of the method where this happens and for both NSString ivars, the little pop up message says, Invalid Summary.
cityName = [NSString stringWithFormat:#"%#", [array objectAtIndex:6]];
The mistake is that you've missed the format specifier. Specifically though, if the objects in the array are already strings, you can just assign them straight to the ivar:
cityName = [array objectAtIndex:6];
Be careful about object ownership though. You don't own the object returned by objectAtIndex: so if you need to use this ivar in many different methods, obtain ownership by sending retain, and relinquish ownership using release. Alternatively if you choose to establish cityName as a retaining or copying property of your class, use the dot-notation or accessor method:
self.cityName = [array objectAtIndex:6];
// or
[self setCityName:[array objectAtIndex:6]];
If the array contains NSString instances there is no need to call +stringWithFormat:. It is a waste of CPU cycles and undoes any potential optimizations related to immutable strings. Furthermore, relying upon the results of description is never the right answer (though it is nigh unavoidable with NSStrings -- this is the one spot where you can rely on the result).
This (fixed):
cityName = [NSString stringWithFormat:#"%#", [array objectAtIndex:6]];
timeZoneName = [NSString stringWithFormat:#"%#", [array objectAtIndex:7]];
Could be:
cityName = [array objectAtIndex:6];
timeZoneName = [array objectAtIndex:7];
Copy it if you need to. As #dreamlax said, make sure you follow the memory management rules.
Use below
cityName = [NSString stringWithFormat:#"%#", [array objectAtIndex:6]];
You require to use %d or %i for integers and %# is used for string objects.