Why is this string immutable? - objective-c

Why does the code give the error - Attempt to mutate immutable object with appendFormat: ?
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
for (NSTextTestingResult *match in matches) {
<omitted>
NSMutableString *value;
value = (NSMutableString *)[response stringWithRange:range];
if ([dict objectForKey:#"traveler"])
[dict objectForKey:#"traveler"] appendFormat:#"%#", value]; // Errors here
[dict setObject:value forKey:key];
}
Value is being created as a _NSCFString.

Because [response stringWithRange:range] returns an immutable NSString *, and casting doesn't make it become mutable.
You want value = [[response stringWithRange:range] mutableCopy];.
Note that if you're not using ARC, you need to remember to release the mutableCopy. Although the return value of [response stringWithRange:range] is autoreleased, the mutableCopy is not.

I dont think you can cast a string to mutable like that.
You need to do it like this
ms = [[NSMutableString alloc] init];
[ms setString:immutableString];
Oops wrong again the way the subclass works you should be able to do it like this more simply.
ms = [NSMutableString stringWithString: immutableString];

Related

NSString, NSArray Memory leak in method

everytime I call this method 2 NSString and 1 NSMutableArray objects leak, which is disgusting, because i'm using it a lot in my app.
Here's the method:
+ (NSString *)queryStringFromParameters:(NSDictionary *)parameters {
NSMutableArray __block *entries = [[NSMutableArray alloc] init];
[parameters enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
NSString *entry = [NSString stringWithFormat:#"%#=%#", [key pcen], [obj pcen]];
[entries addObject:entry];
}];
return [entries componentsJoinedByString:#"&"];
}
Here is the [pcen] method
- (NSString *)pcen {
CFStringRef string = CFURLCreateStringByAddingPercentEscapes(NULL,
(CFStringRef)self,
NULL,
CFSTR("!*'();:#&=+$,/?%#[]"),
kCFStringEncodingUTF8);
return [(NSString *)string autorelease];
}
They are in the same file, my project is ARC, but for this file I unchecked ARC.
Why this leak happens every time I try to use it?
Thank you!
You do not release the entries array.
And btw, the __block modifier is not necessary here, because you do not modify that variable inside the block.
You alloc/init the NSArray in the queryStringFromParameters: method. The array you return is indeed an autoreleased object ([entries componentsJoinedByString:#"&"]) but you never release the entries array.
You can replace the line
NSMutableArray __block *entries = [[NSMutableArray alloc] init];
by
NSMutableArray __block *entries = [NSMutableArray array];
to solve the issue.
The strings leak because they are saved in the leaked NSArray.
In your queryStringFromParameters method i think there is no need to alloc entries. Simply use auto-referencing array
NSMutableArray *entries = [NSMutableArray array];
in second method u used CFURLCreateStringByAddingPercentEscapes which has second argument as u passed (CFStringRef)self but that should be OriginalString - The CFString object to copy.
An example of CFURLCreateStringByAddingPercentEscapes is below:
CFStringRef originalURLString = CFSTR("http://online.store.com/storefront/?request=get-document&doi=10.1175%2F1520-0426(2005)014%3C1157:DODADSS%3E2.0.CO%3B2");
CFStringRef preprocessedString = CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, originalURLString, CFSTR(""), kCFStringEncodingUTF8);
Also remove __block as #Martin R said

Initialize the empty string in ObjectC?

Someone use the following to initialize the NSstring
NSString *astring = [[NSString alloc] init];
I am wondering why not just use
NSString *atring = nil or NSString *astring = #""
There is no semantic difference between NSString *astring = [[NSString alloc] init]; and NSString *astring = #""; - but NSString *astring = nil; is completely different. The first two produce a reference to an immutable string value, the last indicates the absence of a value.
Whether the various ways of generating an zero-length string produce different objects is entirely an implementation detail. The code:
NSString *a = [[NSString alloc] init];
NSString *b = [NSString new];
NSString *c = #"";
NSString *d = [NSString stringWithString:#""];
NSLog(#"%p, %p, %p, %p, %p", a, b, c, d, #""); // %p = print the value of the reference itself
outputs (the exact values will vary):
0x7fff7100c190, 0x7fff7100c190, 0x1000028d0, 0x1000028d0, 0x1000028d0
showing only 2 zero-length string objects were created - one for #"" and one for alloc/init. As the strings are immutable such sharing is safe, but in general you should not rely on it and try to compare strings using reference comparison (==).
NSString *atring = nil
is different -- it's a nil pointer, not an empty string.
NSString *astring = #""
is almost the same, if you change it to something like
NSString* astring=[#"" retain];
It's one of the things that "don't matter"; he or she simply used one way. Probably for no particular reason at all.
NSString *atring = nil; is simply setting the pointer to nil and does nothing other than ensure that pointer is set to nil;
NSString *astring = #""; is a shorthand literal and is the equivalent of [NSString stringWithString:#""];
On another point I don't know why you would want to initialize a string to nothing if its not mutable since you won't be able to change it later without overriding it.

How to put elements from NSMutableArray into C char?

I have a NSMutableArray and I need to sort its elements into separate C char.
How to accomplish that? Or is it better to put the elements into NSStrings?
I've tried this, and it crashes when I try to log the result:
NSMutableArray *array = [[NSMutableArray alloc] init];
... do something to fill the array ...
NSString *string;
string = [array objectAtIndex:0];
NSLog(#"String: %#", string);
*I really prefer putting the elements of the array into C char, because I already have some woking code using char instead of NSStrin*g.
Thanks!
Dont see any specific reason to convert NSString to C chars. To sort an array full of NSStrings try this method -
NSMutableArray *array = [[NSMutableArray alloc] init];
sortedArray = [array sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
NSString *string = [sortedArray objectAtIndex:0];
NSLog(#"String: %#", string);

problems during object release

I have some problems during when and which object to be release
You can say my knowledge towards this is less
i have following conditions please suggest me the answer accordingly
situation-1
NSMutableString *str=[[NSMutableString alloc]initWithFormat:#"Hello World!"];
NSMutableArray *array=[[NSMutableArray alloc]init];
[array addObject:str];
Now when i tried to release str then usage of array affected in future...and Vice Versa
Tell me can i release both?
situation-2
NSMutableString *str=[[NSMutableString alloc]init];
str=#"Hello World !";
str=[self getData]; //calling a method which returns a string
[str release];
I think i am creating a memory leak here(how to solve it?)
please clear these situations
in the first situation, you'll need to call [str release]; after adding it to the array, like this:
NSMutableString *str = [[NSMutableString alloc] initWithString:#"Hello World!"];
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObject:str];
[str release];
This way, array holds the only retain call on the string. Once you release array later, you won't have any memory leak issues.
I'm a little confused about the second situation. str here is a pointer. You seem to be assigning three different objects to to same pointer:
NSMutableString *str = [[NSMutableString alloc] init]; //first object
str=#"Hello World !"; //second object
str=[self getData]; //third object
by the time you call [str release], you've created a memory leak because you've lost the first mutable string. The second time you called str =, you lost any way to access that first NSMutableString.
Assuming that you're looking to concatenate all of these (since you chose NSMutableString), you might try this:
NSMutableString *str = [[NSMutableString alloc] init]; //first object
[str appendString:#"Hello World!"];
[str appendString:[self getData]];
[str release];
If the [self getData] method returns an autoreleased string, you'll be fine. If getData returns a retained string (if you used alloc and init), you'll need to assign it to an intermediate pointer and release it after adding it to str.
What is the need of creating the NSMutableString You can directly use NSString for this purpose

NSArray filled with bool

I am trying to create an NSArray of bool values. How many I do this please?
NSArray *array = [[NSArray alloc] init];
array[0] = YES;
this does not work for me.
Thanks
NSArrays are not c-arrays. You cant access the values of an NSArray with array[foo];
But you can use c type arrays inside objective-C without problems.
The Objective-C approach would be:
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObject:[NSNumber numberWithBool:YES]];
//or
[array addObject:#(NO)];
...
BOOL b = [[array objectAtIndex:0] boolValue];
....
[array release];
EDIT: New versions of clang, the now standard compiler for objective-c, understand Object subscripting. When you use a new version of clang you will be able to use array[0] = #YES
Seems like you've confused c array with objc NSArray. NSArray is more like a list in Java, into which you can add objects, but not values like NSInteger, BOOL, double etc. If you wish to store such values in an NSArray, you first need to create a mutable array:
NSMutableArray* array = [[NSMutableArray alloc] init];
And then add proper object to it (in this case we'll use NSNumber to store your BOOL value):
[array addObject:[NSNumber numberWithBool:yourBoolValue]];
And that's pretty much it! If you wish to access the bool value, just call:
BOOL yourBoolValue = [[array objectAtIndex:0] boolValue];
Cheers,
Pawel
Use [NSNumber numberWithBool: YES] to get an object you can put in the collection.