Losing NSString - iphone

I'm copying an NSString from an NSDictionary into a local NSString using [[NSString alloc] initWithString:], processing it (removing some chars) then sending it to an external object.
I've used two methods a [[MyObject alloc] initWithString:] and [myObject setString:]; neither work.
Both of them make my app crash; when I use a breakpoint on the given area I get an empty NSString; I use NSLogs from the start of the NSString until I send it to my object; they all show the string's correct value…
Thank you all for your valuable input :-)

Replace the [[NSString alloc] initWithString:stringBeingCopied] call with [[NSMutableString alloc] initWithString:stringBeingCopied], creating a mutable string, as opposed to an immutable ("normal") string will stop the setString: calls from crashing your app
Immutable strings, being immutable, don't respond to setString: calls - which are NSString mutators. Creating an NSMutableString instead, which implements setString:, will let you modify the string object.

I've used two methods a [[MyObject
alloc] initWithString:] and [myObject
setString:]; neither work.
Show your work! Can't help you without showing more code. In particular, how did you implement initWithString: and setString: on your MyObject class?

Strings are normally immutable. To modify a string, you need a NSMutableString. Either do [string mutableCopy], or do this from inside the initWithString method. Maybe you do this already, but please post your code if possible. I'm afraid it's hard to give any further help without it...

Related

Why UPDATE statement works with initWithFormat and NOT with stringWithFormat?

I was having an issue with my UPDATE statement as I was telling here: Update issue with sqliteManager
I found out that initWithFormat WORKS
NSString *sqlStr = [[NSString alloc] initWithFormat:#"UPDATE User SET Name = :Name WHERE Id = :Id"];
BUT not stringWithFormat:
NSString* sqlStr = [NSString stringWithFormat:#"UPDATE User SET Name = :Name WHERE Id = :Id"];
Why is this as such? I would like to understand the logic/reasoning behind..
I am guessing that it has to do with the memory management of the string, it might not have been sufficiently retained so it is getting cleaned up before for it is getting used. The difference between the two methods are defined here
I have just found something interesting from this thread: How to refresh TableView Cell data during an NSTimer loop
This, I believe, is the reasoning behind..
I quote what "petergb" said:
[NSString stringWithFormat:...] returns an autoreleased object. Autoreleased objects get released after control returns from the program's code to the apple-supplied run-loop code. They are more or less a convenience so we don't have to release all the little objects that we use once or twice here and there. (For example, imagine how tedious it would be if you had to release every string you created with the #"" syntax...)
We can tell stringWithFormat: returns an autoreleased object because, by convention, methods who's names don't start with alloc or copy always return auto-released objects. Methods like this are said to "vend" an object. We can use these objects in the immediate future, but we don't "own" it (i.e. we can't count on it being there after we return control to the system.) If we want to take ownership of a vended object, we have to call [object retain] on it, and then it will be there until we explicitly call [object release] or [object autorelease], and if we don't call release or autorelease on it before we lose our reference to it by changing the variable to something else, we will leak it.
Contrast with [[NSString alloc] initWithFormat:. This method "creates" an object. We own it. Again, it will be there until we explicitly call [object release].

Difference between these two NSString methods

So I just got asked this at an interview today and after some googling am still unable to figure out the answer (in fact I couldn't even find any code at all which used the [NSString string] method).
What is the difference between
NSString *someString = [NSString string];
NSString *someString = [[NSString alloc] init];
Now my initial thoughts were that [NSString string] would return an object which would be autoreleased whereas using alloc and init would return an object which has been retained. However it seems that this answer was incorrect.
I've looked at the NSString class reference in the apple docs but all it says is
Returns an empty string.
+ (id)string
Return Value
An empty string.
Could somebody explain to me exactly what the difference between these two are?
Was that your response, and did you ask why your answer was incorrect? I ask because your assumption is mostly correct (at a higher level).
It's not exactly 'retained' when returned from alloc+init, it is an object you hold one reference to, and should balance with a release or autorelease. For the convenience constructor (+[NSString string]), you are returned an object which you hold zero references to, but one which you can expect to live until the current autorelease pool is popped unless you send it an explicit retain (assuming MRC or ARC, since it is tagged iOS).
At the lower level, you could make some guesses, but I wouldn't expect that question in many objc interviews (unless you told them you were mid or senior level). Basically, it is implementation defined, but both forms could return the same static, constant NSString (that may have been what the interviewer was looking for). To illustrate:
#implementation NSString
static NSString * const EmptyNSString = #"";
- (id)init
{
self = [super init];
[self release];
return EmptyNSString;
}
+ (id)string
{
return EmptyNSString;
}
...
Again, that's implementation defined, but an obvious optimization. As well, that optimization makes physically subclassing concrete immutable types (NSString) difficult for mutable variants (NSMutableString) in some cases.
Now my initial thoughts were that [NSString string] would return an object which would be autoreleased
Technically, it’s a placeholder string that is constant, i.e., it lives throughout the entire program execution, never being released. It’s not an autoreleased string. Conceptually, and this is what I’d focus as an interviewer, it’s a string (an empty string) that is not owned by the caller, hence the caller shouldn’t release it.
whereas using alloc and init would return an object which has been retained
Technically, it’s a placeholder string that is constant, i.e., it lives throughout the entire program execution. In fact, it’s the same object as the one above, and it is not retained. Conceptually, and this is what I’d focus as an interviewer, it’s a string (an empty string) that is owned by the caller, hence the caller is responsible for releasing it when it’s not needed any longer.
The correct answer is that
NSString *someString = [NSString string];
gives you an empty string that you do not own and that you must not release (according to the memory management rules)
whereas
NSString *someString = [[NSString alloc] init];
gives you an empty string you do own and that you must release (according to the memory management rules).
Without poking into the implementation, you can't say anything else about those two strings. You can't say that they are autoreleased, because they might not be and you can't say what the retain count will be.
In actual fact, you'll probably get (in both cases) the same pointer to a constant object of some NSString subclass, probably with a retain count of UINT_MAX which is used by the run time as a flag to disable normal retain release behaviour for constant strings. I haven't actually tried the above because nobody except the maintainers of the Objective-C SDK needs to care.
You don't often see
NSString *someString = [NSString string];
because it's the same as
NSString *someString = #"";
which is shorter. It's usually used to create an empty NSMutableString
NSMutableString* s = [NSMutableString string];
The only thing I can imagine is that:
Won't allocate memory since it is not made with alloc. It is a constant (an empty string) made by the system and doesn't need to be released.
You allocate the memory for the NSString yourself which means you have to keep track if the NSString still 'lives' or not when you are done with it, and thus need to release it.

Need to retain an NSArray twice to avoid a crash - why?

I have a complex App that runs reliably, but I'm puzzled why I need to retain a particular NSArray ('sources') twice to prevent a crash (although no exception is reported on the console, but the application crashes and returns to the springboard).
A snippet of the code is included below. There's too much code to paste it all, but you have my word that there are no explicit calls to release the array. 'sources' is an instance variable.
If I only retain the array once (or not at all), I get the crash. With two retains, the App is perfectly stable.
NSString *plistPath = [[NSBundle mainBundle] pathForResource:#"Sources" ofType:#"plist"];
sources = [[NSArray arrayWithContentsOfFile:plistPath] autorelease];
[sources retain];
[sources retain];
Thoughts on why I would need to retain this array twice appreciated. Thanks in advance.
You’re using +arrayWithContentsOfFile:, which returns an autoreleased object, then autoreleasing it again. Take out the call to -autorelease and you’ll be OK. You could re-write it as so:
sources  = [[NSArray arrayWithContentsOfFile:plistPath] retain];
There is an explicit call to release the array. autorelease is just as explicit as release — it just happens later. Not only that, but it was wrong to autorelease the array in the first place, since you didn't own it. One retain is necessary to claim ownership of the array. The second one prevents the crash by balancing out the incorrect use of autorelease.
Is it something to do with that autorelease? I can't see why that's there: it should be the factory method that autoreleases. Although I don't know what the consequence of adding an extra autorelease is, it might be worth seeing what happens if you take that out along with one of the retains.
Ditch the autorelease on the factory method. It's why you need a second retain.
That's because arrayWithContentsOfFile: returns an autoreleased array to you. Calling autorelease on this array will release it twice at the end of current event run loop.
NSString *plistPath = [[NSBundle mainBundle] pathForResource:#"Sources" ofType:#"plist"];
sources = [[NSArray alloc] initWithContentsOfFile:plistPath];

How to take an NSString out of an NSMutableString?

That's somewhat confusing. NSMutableString inherits from NSString, but does that also mean that I can pass an NSMutableString anywhere safely where actually an NSString is wanted? And can I assign an NSString to an NSMutableString? How would I get an NSString out of an NSMutableString to avoid problems, if any?
Yes, you can pass an NSMutableString for an NSString. However, be aware that if the object you pass it to stores a reference to this object, it will "see" all the changes you make to the mutable string object. This is not always desirable.
No, not possible. If you had a NSMutableString pointer pointing to an NSString and called, say, appendString: on it, the object wouldn't know how to process the call.
(the first two are OO inclusion polymorphism basics)
If you want to get a non-mutable string from a mutable one, use [mutableString copy].

iPhone Dev - NSString Creation

I'm really confused with NSStrings. Like when should I do
NSString *aString = #"Hello";
of should it be:
NSString *aString = [[NSString alloc] initWithString:#"Hello"];
But then its different when you're assigning a value to an NSString property isn't it?
Can someone clear this up for me?
Thanks!!
In general you should do the first, but they are mostly functionally the same. You can treat constant NSStrings just like normal NSString string objects, for instance:
[#"Hello" length]
will return 5. You can assign them to properties, everything just works. The one thing you might notice is that with the constant NSStrings you don't have to worry about retain/release. That is because they are actually mapped into the applications readonly data section, and don't have allocated memory. Retain and release calls against them still work, they just become noops.
NSString *aString = #"Hello";
Will create an autoreleased string. That is, if you don't explicitly retain it, it will might disappear after your method is over (and sometimes that's totally fine). But if you want to hold on to it past that time, you'll need to retain it.
If you create a property for that string like this
#property (retain) NSString *aString;
And then assign like this:
self.aString = #"Hello";
Then you've properly retained the string and it will stick around.
On the other hand, using alloc, init will create a string for you with a retain count of 1, and if you don't need it past that method, you should release it.
****Edit: #"Hello" is not an autoreleased string, as others have pointed out. My bad. ****