This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
NSString retainCount is 2147483647
Let say i have an class named as MyTestClass.h.
There are three NSString variables which are initialized different ways
Class structure is look like
#interface MyTestClass : NSObject {
NSString *testString1;
NSString *testString2;
NSString *testString3;
}
#property (nonatomic, retain) NSString *testString1;
#property (nonatomic, retain) NSString *testString2;
#property (nonatomic, retain) NSString *testString3;
#end
MyTestClass.m
#implementation MyTestClass
#synthesize testString1, testString2, testString3;
-(id) init{
self.testString1 = #"";
[self setTestString2:#""];
testString3 = #"";
}
Now i am planning to create an object of MyTestClass
MyTestClass *obj = [[MyTestClass alloc] init];
I think after this code line execution testString1, testString2 and testString3 retainCounts will be 1.
Am i correct my friends?
may i know that what will happened if i release testString3 ?
Any help on this is appreciated.
Thanks
Since you are using literal strings in this example retainCount is of no importance (not even as a delta) since those string objects aren't actually ever going to be dealloc'd.
However, if you were assigning a runtime allocated string to each of your properties, the first two would be retained, the third would not. Since your properties are declared as retain and you're using dot syntax in one and the "setProperty" syntax in the other, the same setter is executed and the object passed to that setter is retained. The third example you're simply setting the backing ivar for the property to the value on the right and not affecting it's ownership.
It's worth noting, retainCount is only ever useful as a delta and shouldn't be thought of as an explicit number. You should never explicitly check the value of retainCount, since it's absolute value is unpredictable and of no use. You seem to understand this in your question, but it's worth restating whenever dealing with retainCount to make sure all involved understand it.
Related
I'm confused on what the proper way to write custom init methods for youw own subclass in terms of memory management, custom subclasses, and arrays. If I have properties like:
#property (nonatomic, retain) NSString *name;
#property (nonatomic, retain) NSMutableArray *array;
#property (nonatomic, retain) SomeSubclassOfNSObject *object;
#interface SomeSubclassofNSObject
#property (nonatomic, retain) NSString *category;
How do I write my init method?
do you do:
initWithName:(NSString *)aName object:(SomeSubclassOfNSObject *)anObject {
if (self = [super init]) {
self.name = aName; // or do you do name = aName or name = [aName copy] autorelease] or name = [NSString alloc] initWithFormat:#"%#", aName]
self.object = anObject; // do I need to make a copy of this object so they don't point to the same object?
// loop through NSMutableArray and copy the objects?
// not really sure what to do for arrays.
}
return self;
}
I would recommend self.name = aName; in most cases because this takes advantage of the generated setter and thus the retain count is incremented implicitly. That means your reference is safe whatever the caller of init will do afterwards with aName. The same applies to the dealloc counterpart: just write self.name = nil; and your done.
Things are different if you are supplying NSMutableString because changes inside of your class will affect other classes' references to this. But from design view mutable strings should be used as paramters only if it's your intention that they are manipulated.
self.object = anObject;: Well it depends what you want. If all classes should point to the same object don't make copy (I think this is most often exactly what you want). There might be cases when it is reasonable to make a deep copy.
Arrays: You need something like array = [[NSMutableArray alloc] init]; in your init method. Afterwards the retain count will be incremtented automatically for every object you add i.e. you must not call retain on the added object itself. Like in 2. there might be situations where you really want to have copies of the objects of some source array. OK do it but this is rarely the case.
More often you have an existing array and want a sub-array of it or a special sorted version. So you have got a new array but the same elements.
This was the short answer. More about this in:
Advanced Memory Management Programming Guide
Declared Properties
is this line of code correct re memory management (re NSDate copy)?
I have a class with properties:
#property (nonatomic, retain) NSDate* start;
#property (nonatomic, retain) NSDate* coreWeStart;
Now in the init method, assuming self.start is already set, is this correct re setting the coreWeStart to the same date:
self.coreWeStart= [[self.start copy] autorelease];
Just double checking my understanding that:
needs a 'copy' as otherwise it would refer to the same object and
needs an autorelease as I did do a copy
thanks
I would say kind of, but it could still be done better. Specifically, you could do:
#property (nonatomic, copy) NSDate* coreWeStart;
...and then:
self.coreWeStart = self.start;
...to get the same thing with less code. Also be sure to do self.coreWeStart = nil in dealloc (and self.start = nil too).
Yep. You got it.
Copy returns a new object with a retain count of one.
assigning it to the retain keyword property will increment the retain count.
autorelease will decrement the retain count.
So your object has the coreWeStart property with a retain count of one, which is a copy of the start property.
In this example:
#interface something : something
{
NSString *saveString;
}
-(void)saveStringForLater:(NSString*)myString
{
//do stuff with myString
...
//then save it for later
saveString = myString;
}
-(void)someOtherTimeInFuture
{
//do stuff with saveString
...
}
So given the above, my questions are:
1) Is this safe/proper way of doing this?
2) Will I need to worry about releasing saveString?
3) Should I be copying the string instead of just saving the pointer?
Excuse my ignorance as I am fairly new to Obj-C but have a C++ and C# background.
Thanks!
This is what #properties are for. They manage getter and setter code for you, so you don't have to think about these questions.
.h
#interface MyClass : NSObject
{
NSString *myString;
}
#property (nonatomic, retain) NSString *myString;
#end
.m
#implementation MyClass
#synthesize myString;
-(void)dealloc
{
[myString release];
[super dealloc];
}
#end
With those things in place, you can now talk about self.myString and not worry about memory. When you assign to it it'll do a retain. If you assign again, it'll release the first object and retain the new one. And then it'll stick around retained until your viewcontroller unloads.
You can by all means accomplish this same end with an iVar (which is what you're doing in your code sample), but then memory management is yours to handle, and it can be a bit fiddly. Best to use the #property system to create appropriately memory-managing setter code.
You have 3 optins,
Copy - should be using if the string can change or when getting called from a code you have on control of like third party
Retain - will increase the reference count to the object and will prevent destruction of it
In both these options you have to release it when you done with it
Last you can define a property with retain,copy attribute - this will let the system worry about managing it and probably the best option in most cases
This makes no sense to me. Maybe someone here can explain why this happens.
I've got an NSMutableString that I alloc at the top of my iPhone app, then append to later in the process. It results in a SIGABRT, which doesn't add up to me. Here's the code:
Header File (simplified):
#interface MyAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
NSMutableString *locationErrorMessage;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, copy) NSMutableString *locationErrorMessage;
#end
And the relevant parts of the Main:
#implementation MyAppDelegate
#synthesize window;
#synthesize locationErrorMessage;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
self.locationErrorMessage = [[NSMutableString alloc] init];
}
- (void)anotherFunction {
[self.locationErrorMessage appendString: #"Blah Blah Blah"];
}
This all seems simple enough. What am I missing?
I would call this a bug in how property setters are generated, but the answer is pretty simple:
You declared the property as (nonatomic, copy). This means that whenever the locationErrorMessage property is set, it's going to invoke copy on the new value and use that copy as the property value.
Unfortunately, invoking copy on an NSMutableString does not result in an NSMutableString, it results in an NSString (which cannot be mutated using something like appendString:).
So the simple fix would be to change the property declaration from copy to retain.
(I would say that the bug would be: If you declare a property for a mutable object as copy, then the copy setter should actually use mutableCopy and not copy) => rdar://8416047
Your property is copying the passed in string. A copy always is immutable, so you’re trying to send appendString: to an immutable NSString. Declare your property as retain and it will work or write a custom setter that copies the string using mutableCopy.
You also have a memory leak, you should use [NSMutableString string] instead of the alloc-init sequence.
Btw, you have a leak there,
self.locationErrorMessage = [[NSMutableString alloc] init];
you're copying the value, but you never release the actual first allocated NSMutableString.
What is the difference between these two?
#property (nonatomic, retain)
#property (nonatomic, copy)
What is the other type like this?
http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW27
Using retain is equivalent to this method:
- (void)setMyObject:(id)object {
myObject = [object retain];
}
Using copy is like this:
- (void)setMyObject:(id)object {
myObject = [object copy];
}
The main difference is that there are now two copies of the same object. Now, if you change an instance variable in your class (such as changing #"A" to #"B"), the original object will stay intact (it will still be #"A").
As a general rule, use:
#property(nonatomic, copy)
..for NSString properties and this for all other object properties:
#property(nonatomic, retain)
For attributes whose type is an immutable value class that conforms to the NSCopying protocol, you almost always should specify **
copy
** in your #property declaration. Specifying **
retain
** is something you almost never want in such a situation.
Since in almost all cases you want to prevent mutating an object's attributes behind its back, you should mark the properties representing them copy. (And if you write the setter yourself instead of using #synthesize you should remember to actually use copy instead of retain in it.)