iphone assigning instance variables - iphone

I just spent the last 3 hours trying to figure out this error. I would like someone to explain it to me so I don't do it again.
I assigned an NSString instance variable without using "self". When the class ("self") released, I received a "bad access" error. I have done this exact same thing in another class with the same variable declarations and do not have this error. Below is my code. I commented out the line that broke and the line below fixes it. But I don't understand why... Notice that there are other instance variables that do not cause this problem. Should I always use the "self" reserved word when assigning instance variables? Please let me know.
declarations
#property (nonatomic, readonly, assign) int IID;
#property (nonatomic, assign) int ProfileIID;
#property (nonatomic, retain) NSDate *NoteDate;
#property (nonatomic, copy) NSString *NoteText;
code snippet
// the default date format is Year-Month-Day
NSDateFormatter *df = [[[NSDateFormatter alloc] init] autorelease];
[df setDateFormat:kDateFormat];
IID = sqlite3_column_int(selectstmt, 0);
ProfileIID = sqlite3_column_int(selectstmt, 1);
// notice this does not cause a memory error
NoteDate = [[df dateFromString: [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 2)]] retain];
// the following may be NULL. Checking using the sqlite3_column_text method
const char *columnText = (const char *)sqlite3_column_text(selectstmt, 3);
if(columnText != NULL)
{
// this causes a memory error
//NoteText = [NSString stringWithUTF8String: columnText ];
// this does not cause memory error
self.NoteText = [NSString stringWithUTF8String: columnText ];
}

The reason that
NoteDate = [[df dateFromString: [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 2)]] retain];
is fine is because you retain the variable. Since you do not allocate the string, but call stringWithUTF8String on NSString, you do not take ownership of the variable, and so the string returned to you is autoreleased. However, since you retain it, this does not cause problems.
If variables are returned autoreleased, then they are released when the autorelease pool is drained, which occurs at the end of each event (see more on autorelease pools). This is no good with an instance variable, because it needs to stick around after the current event.
When you assign the variable by:
NoteText = [NSString stringWithUTF8String: columnText];
Your setter method is not invoked, so the returned string (which, again, is autoreleased) is not retained, and so is released by the autorelease pool at the end of the event.
Calling it as:
self.NoteText = [NSString stringWithUTF8String: columnText];
does retain the string, since the line is another way of writing:
[self setNoteText:[NSString stringWithUTF8String: columnText]];
which invokes your setter method and retains the variable, preventing it from being released at the end of the current event.

Assigning NoteText from within a class method doesn't invoke the synthesized setter method, it sets the instance variable directly. This means your string isn't being retained (or copied, in the case of your setter), and the crash is when trying to release an object which has already been released. Do this:
self.NoteText = [NSString stringWithUTF8String: columnText ];
This will call your setter, and all will be well.
Edit:
Just to be clear, this is true for all ivars.
myVariable = someValue; // Sets the ivar directly.
self.myVariable = someValue; // calls [self setMyVariable].

This confusion between ivar and setter methods is why I never name my setters and my ivars the same.
Apple typically names its ivars starting with an underscore (_), for example NoteText. In my case, I've taken to having a prefix of i for ivars. For example:
NSString* i_name;
#property (nonatomic, copy) NSString* name;
#synthesize name = i_name;
That way you can easily tell the difference between an ivar assignment:
i_name = [[whatever title] retain];
and a setter method call
self.name = [whatever title]; // Equivalent to [self setName:[whatever title]
The setter, since it is defined with copy (or similarly for retain) will take ownership of the variable passed in and release ownership of the old value. The ivar assignment does none of that.
Note also that your propery names should start with a lower case letter or they will not be KVO compliant.

Related

IOS retain , Assign

I observed the following behavior.
Took two property variables.
#property (nonatomic, retain) NSString *stringOne;
#property (nonatomic, assign) NSString *stringTwo;
In .m file written below code..
NSMutableString *localstring= [[NSMutableString alloc] initWithString:#"test"];
self.stringOne = localstring;
NSLog(#"localstring = %d", [string retainCount]);
NSLog(#"string one retain count = %d", [self.stringOne retainCount]);
self.stringTwo = localstring;
NSLog(#"localstring = %d", [localstring retainCount]);
NSLog(#"string two retain count = %d", [self.stringTwo retainCount]);
Here localstring retain count is 1 because of alloc. Now i gave
self.stringOne = localString.
The retain count of localstring will become two because of retain property of stringOne. Now i gave
self.stringTwo = localString.
Even here the localstring retain count is incremented by one. Notice that i have given assign property to stringTwo. Practically the retain count of localstring or stringTwo should not increase by 1 as it is assign property.
Please correct me if i am wrong.
Thanks
Jithen
Dump the retainCount; it is useless. http://www.whentouseretaincount.com/
The source of your confusion is in not understanding how pointers work. Modify your code like this:
#interface BBQ:NSObject
#property (nonatomic, retain) NSString *stringOne;
#property (nonatomic, assign) NSString *stringTwo;
#end
#implementation BBQ
- (void) burn
{
NSMutableString *localstring= [[NSMutableString alloc] initWithString:#"test"];
self.stringOne = localstring;
NSLog(#"localstring = %p", localstring);
NSLog(#"string one = %p", self.stringOne);
self.stringTwo = localstring;
NSLog(#"localstring = %p", localstring);
NSLog(#"string two = %p", self.stringTwo);
}
#end
It'll spew something like this:
2013-04-11 08:48:13.770 asdffadsfasddfsa[18096:303] localstring = 0x10010aaf0
2013-04-11 08:48:13.772 asdffadsfasddfsa[18096:303] string one = 0x10010aaf0
2013-04-11 08:48:13.772 asdffadsfasddfsa[18096:303] localstring = 0x10010aaf0
2013-04-11 08:48:13.772 asdffadsfasddfsa[18096:303] string two = 0x10010aaf0
There is only one string instance in play; localstring, stringOne, and stringTwo all hold references to exactly one instance of NSMUtableString.
Thus, you'll see +1 RC of that one string instance for the alloc, +1 for the assignment to the stringOne property and no change for stringTwo.
(RC's should only be reasoned about in terms of deltas; if you retain an object, you need to balance that with a release when you no longer need the object. That the object may be retained by something else is irrelevant.)
When I ran this code:
#interface ViewController ()
#property (nonatomic, retain) NSString *stringOne;
#property (nonatomic, assign) NSString *stringTwo;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self test];
}
- (void)test
{
NSMutableString *localstring = [[NSMutableString alloc] initWithString:#"test"];
NSLog(#"localstring (before setting `stringOne` or `stringTwo`) = %d", [localstring retainCount]);
self.stringOne = localstring;
NSLog(#"localstring (after setting `stringOne`) = %d", [localstring retainCount]);
NSLog(#"string one retain count = %d", [self.stringOne retainCount]);
self.stringTwo = localstring;
NSLog(#"localstring (after setting `stringTwo`) = %d", [localstring retainCount]);
NSLog(#"string two retain count = %d", [self.stringTwo retainCount]);
}
#end
I received this console log:
localstring (before setting `stringOne` or `stringTwo`) = 1
localstring (after setting `stringOne`) = 2
string one retain count = 2
localstring (after setting `stringTwo`) = 2
string two retain count = 2
And all of those values are precisely as one would expect.
When you first create the object referenced by the local variable, that object has a +1 retain count.
When you set the retain property, stringOne, the object's retain count will be incremented to +2, and as both localstring and stringOne reference that same object, they'll both report the same retainCount.
But when you use the assign property, stringTwo, though, the retainCount does not change.
When you declare a property with retain, it automatically 'retains' the object, thus increasing its retain count.
So NSMutableString *localstring= [[NSMutableString alloc] initWithString:#"test"]; makes retain count = 1;
Then self.stringOne = localstring; makes retain count = 2.
My thinking is if the property is given retain, then after this line
self.stringOne = localstring , the retain count of self.stringone
should become one
When you create an object, it will start with a retain count of 1.
First of all, never use retainCount for anything. It is simply not reliable since it is a global retain count, and can be influenced by other factors outside of your code. Amazingly, in this case, it is correct though. Let's examine:
//Immediately localstring is +1 because you allocated it
NSMutableString *localstring= [[NSMutableString alloc] initWithString:#"test"];
//self.stringOne is a retain property, so localstring is incremented again (+2)
self.stringOne = localstring;
//self.stringTwo is a retain property, so localstring is incremented again (+3)
self.stringTwo = localstring;
Note that now localstring, self.stringOne and self.stringTwo all point to the same location in memory. You are not copying the memory contents every time you use the = sign (your way of thinking seems to indicate that you think that is how it works). You are simply pointing another variable at a location in memory and saying "Don't deallocate this piece of memory until I say so." (at least in the case of retain properties).
Conclusion: localstring's retain count, self.stringOne's retain count, and self.stringTwo's retain count are all the same.
Sidenote: It is impossible for an object to have a retain count of zero. The only time that can happen is when retainCount is sent to nil (which I assume self.stringOne is when you test it)
While it is never a good idea to look at retainCount when writing code, it is behaving as it should in this case. I think your understanding of memory management seems to be a little bit off.
To answer your question,
NSMutableString *localstring= [[NSMutableString alloc] initWithString:#"test"];
This creates a mutable string Object,increments its retain count and returns a pointer to it. Note that retainCount is associated with the Object and not the pointer.
When you assign it to your retain property,
self.stringOne = localstring;
it passes retain to your Object and increments its retain count by 1 again. Now your object's retain count is 2 and both the pointers point to the same object. So, when you log retainCount, you get what you get. Hope this answers your question.

MutableCopy AllocLeak MemoryLeak

I have an NSTimer that fires once per second.
And every second I have an NSString that needs to be changed.
I've never tried to deal with memory management before so I'm not sure if what I'm doing is right but instruments is saying under "alloc" that the line of code with stringByReplacingOccurrencesOfString has 45MB of "Live Bytes" after about a minute...
(and the live byte count keeps on rising with every second and eventually crashes the app).
I think my issue lies somewhere with the MutableCopy code?
Here is my code:
-(void)myTimer {
if (testedit) {
[testedit release];
[withString1a release];
[forString1a release];
}
testedit = [[NSString alloc] init];
withString1a = [[NSString alloc] init];
forString1a = [[NSString alloc] init];
testedit = [[NSString alloc] initWithFormat:#"example"];
withString1a = [[NSString alloc] initWithFormat:#"e"];//this string gets its values randomly from an array in my real code
forString1a = [[NSString alloc] initWithFormat:#"flk34j"];//this string gets its values randomly from an array in my real code
testedit = [[testedit stringByReplacingOccurrencesOfString:withString1a withString:forString1a] mutableCopy];//memory leak /:
}
You are allocating memory for each object twice. When you alloc the second time and assign it to the same variable, the first piece of alloc'd memory becomes inaccessible and unreleasable.
Then you make a mutableCopy of testedit and assign the copy to the original's variable. Again, you leave a piece of inaccessible memory floating around.
The rule with non-ARC memory management is - for every alloc, new, copy or retain you need to have a corresponding release. You have 6 allocs, one copy, and only 3 releases.
Here are some suggestions.
Remove these duplicated allocations:
testedit = [[NSString alloc] init];
withString1a = [[NSString alloc] init];
forString1a = [[NSString alloc] init];
Presumably testedit, withString1a and forString1a are all iVars. (Please declare your iVars as autosynthesized properties and refer to them as self.testedit ... etc. that will make your code so much clearer to stack overflowers).
Take out all of this:
if (testedit) {
[testedit release];
[withString1a release];
[forString1a release];
}
Assuming these are all iVars, the correct place to release them is in your object's dealloc method
In fact withString1a and forString1a can be local variables, as you get their content from elsewhere:
NSString* withString1a = [[[NSString alloc] initWithFormat:#"e"] autorelease];
NSString* forString1a = [[[NSString alloc] initWithFormat:#"flk34j"] autorelease];
You can autorelease them as you don't need them to hang around after the method has finished.
These lines can also be written:
NSString* withString1a = [NSString stringWithFormat:#"e"];
NSString* forString1a = [NSString stringWithFormat:#"flk34j"];
(-stringWithFormat is a convenience method that returns an autoreleased object)
That leaves us with these two lines.
testedit = [[NSString alloc] initWithFormat:#"example"];
testedit = [[testedit stringByReplacingOccurrencesOfString:withString1a
withString:forString1a] mutableCopy];
It's not clear why you are treating testedit as an immutable string in the first line and a mutable string in the second. You don't need a mutable string here at all, as you are replacing testedit with a new string.
self.testedit = [[NSString alloc] initWithFormat:#"example"];
self.testedit = [[testedit stringByReplacingOccurrencesOfString:withString1a
withString:forString1a] copy];
(you need copy as stringByReplacingOccurrencesOfString:withString: returns an autoreleased object, and here you want to keep hold of it)
THE last piece of the jigsaw is getting rid of your _testedit iVar memory allocation. You do this in the dealloc method of your object:
- (void) dealloc {
[_testEdit release];
[super dealloc];
}
(Note that init, accessor, and dealloc methods are the three places where you should not refer to an iVar using property syntax.)
All good, but really, you should be using ARC! You are _far_more likely to introduce memory bugs this way than if you rely on the compiler to manage memory for you.
I would suggest you to make use of #property here.
In .h file declare the properties as:
#property (nonatomic, retain) NSString *testedit;
#property (nonatomic, retain) NSString *withString1a;
#property (nonatomic, retain) NSString *forString1a; //if required write the #synthesize as well in .m class
You can write your timer method as:
-(void)myTimer {
self.testedit = #"example";
self.withString1a = #"e";//this string gets its values randomly from an array in my real code
self.forString1a = #"flk34j";//this string gets its values randomly from an array in my real code
self.testedit = [self.testedit stringByReplacingOccurrencesOfString:self.withString1a withString:self.forString1a];
}
In dealloc method, you can set all the above properties as nil (self.testedit = nil;) or do a release on them([testedit release];).
If possible, try to switch to ARC, you dont have to worry about the memory management. The problem with your code was that you are using a lot of alloc/init statements without releasing the variable before doing it. This causes it to lose the reference of that variable and you will leak it. You dont need that many allocation statements. For every allocation or retain, there should be a corresponding release/auto-release statement.
If you're using ARC you shouldn't have an issue. If you aren't using ARC you can try adding autorelease:
testedit = [[[testedit stringByReplacingOccurrencesOfString:withString1a withString:forString1a] mutableCopy] autorelease];
You are getting a memory leak because you never de-allocate testedit. Whenever you call alloc, that means you need to deallocate it. This usually just means calling release.
Do something like this instead, then be sure to free up the memory you've allocated:
NSString* newString = [[testedit stringByReplacingOccurrencesOfString:withString1a withString:forString1a] mutableCopy];

Which way is the correct way to allocate memory with a property?

Which way is correct?
NSString *c = [[NSString alloc] init];
self.character = c;
[c release];
or
self.character = [[NSString alloc] init];
And why? Thanks.
It depends on how your property is declared. If you used
#property (nonatomic, retain) NSString *someString;
The setter will be created to retain someString, in which case the correct way is your first method. If you used:
#property (nonatomic, assign) NSString *someString;
Your second method will be correct, since it will just assign the pointer and not retain anything.
It depends on how you've defined your property.
If it's copy or retain, the synthesized setter (setCharacter: in your example) will take ownership of any objects you assign to the property. In this situation your first example is correct. The second would lead to a memory leak as you've claimed ownership of the NSString twice and you will (probably) only relinquish ownership once; thus the memory can never be reclaimed.
If it's assign on the other hand, the setter won't do anything special and your second example would be correct. The first would result in an EXC_BAD_ACCESS error if you tried to do anything with the NSString. I should note that you generally only use assign for primitive types and delegates.
I suggest you have a read over the Memory Management Programming Guide and the Declared Properties section of The Objective-C Programming Language guide.
The answer depends on your #property definition. Likely it's something like (retain) or (copy) for an NSString. In that case, assigning to self.character will increment the retain count. So the bottom:
self.character = [[NSString alloc] init];
You've set the retain count to 1 with the alloc and self.character will also retain it for a count of 2, so that'll leak. Should be
self.character = [[[NSString alloc] init] autorelease];
or the top version.
The answer to this now with iOS 5 is to use ARC.

Why NSString variable needs to be retained?

I have the following code in my .h file:
#interface Utils : NSObject {
NSString *dPath;
}
#property(nonatomic, retain) NSString *dPath;
And in my .m file:
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
dPath = [[documentPaths objectAtIndex:0] stringByAppendingPathComponent:kDatabaseName];
[dPath retain];
Why do I have to retain dPath if it's already defined as (nonatomic, retain)?
If I don't add the [dPath retain]; I get some strange, random errors and the application crashes when using this variable in other functions. I guess that's because of some autorelease somehere but I don't have any.
So, what is the (nonatomic, retain) doing anyway? Is it really necessary the [dPath retain]; or am I just hiding something else with that?
Because the code isn't calling the dPath property's setter method, it's just setting the instance variable dPath directly:
dPath = [[documentPaths objectAtIndex:0] stringByAppendingPathComponent:kDatabaseName];
[dPath retain];
So it has to be retained manually.
You will be able to (in fact you need to) omit the retain call if the property setter was used like this (notice the self.):
self.dPath = [[documentPaths objectAtIndex:0] stringByAppendingPathComponent:kDatabaseName];
or like this (notice the setDPath:):
[self setDPath:[[documentPaths objectAtIndex:0] stringByAppendingPathComponent:kDatabaseName]];
The setter retains the NSString for you so you don't have to do it yourself.
A nice little practice to follow in order to avoid the confusion, is to affix an underscore to your ivar name to indicate it's an ivar:
NSString *dPath_;
Then synthesize your property like this, to associate it with your differently-named ivar:
// self.dPath is the property, dPath_ is the ivar
#synthesize dPath = dPath_;
Then modify your dealloc method, as well as any other code that directly references the instance var, to use the affixed name instead:
- (void)dealloc {
[dPath_ release];
[super dealloc];
}
try setting and getting it with
self.dPath
If you want to call the property setter method, which will invoke the retain, then you want to write:
self.dPath = ...
Jamming stuff into a variable with:
dPath = ...
completely ignores the properties of this instance variable. Which is why you ended up needing to do the retain manually.

How to transfer values between classes on iPhone?

I want to send a string from one class to the other:
1) In class1, I add a property to hold the string:
#property (nonatomic, retain) NSString *str;
2) and a method to send back a string:
-(NSString *)sendBackStr:(NSString *)strURL
{
NSString *str = [[NSString alloc] stringWithString:strURL];
return str;
}
3) In class2, I add a property to hold the received string:
#property (nonatomic, retain) NSString *returnStr;
4) and the following code:
Class1 *c1 = [[Class1 alloc] init];
returnStr = [c1 sendBackStr:#"URL"];
But the program stops at returnStr = [c1 sendBackStr:#"URL"]; Any ideas about what's wrong with it?
stringWithString is a class method returning an autoreleased string. You should be calling it like this:
myProperty = [NSString stringWithString:strURL];
Here I assume your property does a copy, to increment the retain count on the autoreleased string that's returned from the stringWithString method. (Objects returned from alloc calls have a retain count of one and are not autoreleased.) It's more usual to give strings the copy property rather than the retain one - you usually just want your own copy of a string, not a shared reference to a string owned by someone else.
What I also can't understand is why you've written the code like this, unless it's just an example. In class 2, all you need to do is write
returnStr = [NSString stringWithString:#"URL"];
stringWithString: is a message that needs to be sent to the NSString class, not an instance of your class (returned via alloc).
The correct code should be:
-(NSString *)sendBackStr:(NSString *)strURL
{
return [NSString stringWithString:strURL];
}
You might want to familarize yourself more about the idioms around allocation, retention, and autoreleasing of pointers. If you wanted to alloc this string for some reason and return it from the sendBackStr: message, then you would probably want this code:
-(NSString *)sendBackStr:(NSString *)strURL
{
return [[[NSString alloc] initWithString:strURL] autorelease];
}