How does ARC deal with local variable within the method? - ios

For example,
- (void) method
{
NSString *string = #"This is a string.";
}
Do I need to add
string = nil;
at the end of the method in order to let ARC release it?
Situation may be different in non-literal object such as
- (void) method
{
NSData *data = [[NSData alloc] init];
}
Do I need to add at the end
data = nil;
to release it?

You don't need to nil it, but ARC doesn't release it either. Since it's a literal, it's statically allocated in the app's binary. It's never released.
- (void)method {
NSString *string = #"I'm never released because I'm statically allocated";
NSString *arcReleasesMeAfterMyLastSourceRef = [NSString stringWithString:string];
}

Related

Why two strings allocated with NSString *str1 = [[NSString alloc]init]; have same address?

NSString *str1 = [[NSString alloc]init];
NSString *str2 = [[NSString alloc]init];
NSLog(#"%p\n%p",str1,str2);
result
str1:0x7fff7b559d00
str2:0x7fff7b559d00
Why str1 and str2 have same memory address?
NSString is immutable, so two empty strings are identical. Therefore, Cocoa can return the same object every time you create it.
The real question, however, how can this be done when alloc returns two different addresses for the two strings?
The answer is that init is allowed to substitute the value of self for anything it wishes, and return a completely different object. For example, NSString's init can be implemented like this:
-(id)init {
static NSString *empty = nil;
if (!empty) {
empty = [[NSString alloc] initWithCharacters:"" length:0];
}
return empty;
}
Note: The real code in Cocoa will almost certainly be different; this is only an illustration to show how the same address could be returned for different allocations.

Objective-C memory leak when returning NSString

I want to be sure that my code is not leaking, since this small snippet is called thousand times in my app. I run the app through Instruments and the initWithBytes seems to be problematic. Is anything wrong in this code?
First [reader readString] is called.
case FirstCase:
{
NSString *string = [reader readString];
[self setPropertyByName:propertyName value:string];
break;
}
...
readString is returns the strings which is autoreleased.
- (NSString*) readString
{
...
NSString *string = [[[[NSString alloc] initWithBytes:cursor length:stringLength encoding:NSUTF8StringEncoding] autorelease];
return string;
}
Is the code OK? Any other better approach to avoid autorelease?
I cannot change my code to ARC. Plain old non-ARC memory management.
What you posted is OK. The only rule at this point is that methods contain "create" or "alloc" will return an object that needs to be explicitly released. In your case that is the string returned in the readString method.
Since the object will be returned you need to retain it till the end of the run loop cycle which the autorelease pool will do. What that means for instance is if this method will be called in a for loop the objects will not be deallocated before the loop has exited.
If you want or need to avoid that I suggest you to do the same pattern with "create" or "alloc" and return an object not being autoreleased:
case FirstCase:
{
NSString *string = [reader createReadString];
[self setPropertyByName:propertyName value:string];
[string release];
break;
}
...
- (NSString*) createReadString
{
...
NSString *string = [[[NSString alloc] initWithBytes:cursor length:stringLength encoding:NSUTF8StringEncoding];
return string;
}

NSString value nil inside onEnterTransitionDidFinish method

I guess its a very basic memory concept. But couldn't figure it out what happens with below case. Any insight would be helpful.
This could be similar to Problems with NSString inside viewWillDisappear
But I wanted to know why there requires a #property. How can we do it without taking #property. Please provide some inside view.
in .h I have NSString *someString
in .mm (this is my non-ARC cocos2d+box2d game scene)
-(id)initWithString:(NSString *)tempString
{
if(self = [super init])
{
someString = [[NSString allo]init];
someString = tempString;
}
return self;
}
-(void)onEnterTransitionDidfinish
{
[super onEnterTransitionDidfinish];
NSLog("The String is %#",someString);//Becomes nil here
}
-(void)printString
{
NSLog(#"The String is %#",someString);//This works fine
}
If you are not using ARC then you need to learn a lot more about memory management.
The following two lines:
someString = [[NSString allo]init];
someString = tempString;
should be:
someString = [tempString copy]; // or [tempString retain];
And be sure you call [someString release] in your dealloc method.
BTW - you are not using a property. someString is declared as an instance variable, not a property.

How to better initialize strings to avoid dead stores

I found a few questions like this but I couldn't find this particular question. I have a number of strings that are initialized as
NSString *string = [[NSString alloc] init];
which are then assigned a value depending on the results of an if/else block:
if ([anotherThing isEqualToString:#"boogers"]) {
string = [NSString stringWithFormat:#"some characters"];
} else {
string = [NSString stringWithFormat:#"some _other_ characters"];
}
and then string is used later in the method.
How can I accomplish this without leaving a dead store at the alloc/init stage? If I alloc inside the if (or the else), the string is gone by the time I need it several lines down.
You don't have to initialize the string on that first line -- you just need to declare it:
NSString *string = nil;
if ([anotherThing isEqualToString:#"boogers"]) {
string = #"some characters";
} else {
string = #"some _other_ characters";
}
The [NSString stringWithFormat:] will initialize a new NSString object for you, basically what you are doing is declaring a new object each time, just set the pointers for your strings as NSSTring *someString, *someOtherString, *allTheStringsYouNeed; and then use any class method to initialize it even #"Characters"; will work correctly as the compiler do it at runtime for you.

gettin EXC_BAD_ACCESS while using nsstring

I am getting crazy during 4 hours and I really need help. Here is the code:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
//check if strGroup has prefix and suffix #
BOOL result;
result = [strGroup hasPrefix: #"#"];
if (result)
{
result = [strGroup hasSuffix: #"#"];
if (result)
{
NSMutableString* string = [NSMutableString stringWithString: strGroup];
str = [strGroup substringWithRange: NSMakeRange (1, [string length]-2)];
strToHoldAllContact = [NSString stringWithFormat:#"%#",str];
}
}
NSLog(#"strToHoldAllContact=%#",strToHoldAllContact);
}
I am gettin the value of strToHoldAllContact correctly. But when I try to access strToHoldAllContact from another method I am getting the error:
[CFString respondsToSelector:]: message sent to deallocated instance 0x856f2a0
Use
strToHoldAllContact = [NSString stringWithFormat:#"%#",str];
[[strToHoldAllContact retain] autorelease];
and forget about release.
where ever you are initializing or setting the string do this [strToHoldAllContact retain]; and don't forget to release it once you are done using it
Just replace
strToHoldAllContact = [NSString stringWithFormat:#"%#",str];
to
strToHoldAllContact = [[NSString alloc] initWithFormat:#"%#",str];
And release it after you don't need it anymore.
with ARC, in .h declare strToHoldAllContact as:
#property(strong) NSString *strToHoldAllContact;
in .m, use it (after #synthesize) as self.strToHoldAllContact = [NSString stringWithFormat:#"%#",str];
this way you will not have problems.
without ARC,in .h declare strToHoldAllContact as:
#property(retain) NSString *strToHoldAllContact;
and use it same ways as with ARC in.m file.

Resources