I am implementing a copyWithZone method for a custom A class, in which a NSNumber pointer was declared as (retain) property
#class A <NSCopying>
{
NSNumber *num;
}
#property (nonatomic, retain) NSNumber *num; // synthesized in .m file
-(id) copyWithZone:(NSZone*) zone {
A *new = [[A alloc] init];
new.num = [num copy];
return new;
}
When I debug, I always find new.num is the same address as the self.num.
Even if I use
new.num = [NSNumber numberWithFloat: [num floatValue]];
I still get the same address. In the end, I have to use
new.num = [[[NSNumber alloc] initWithFloat:[num floatValue]] autorelease]
to achieve the result I want. I am just wondering why NSNumber complies to but does not return a new memory address when copied?
Thanks
Leo
NSNumber is immutable. Making a copy is pointless and, thus, the frameworks just return self when copy is invoked.
If a class implements NSCopying, you should mark the property as copy (not retain). -copy on immutable classes (NSString) will simply return a reference to the object (w/a bumped retain count). If passed a mutable instance, it'll be copied to an immutable instance. This prevents an external party from changing the state behind your object's back.
Not only is NSNumber immutable - for low values it as also a Flyweight.
NSNumber isn't mutable, so there is no need to force physical copying.
You should be using [[A alloc] initWithZone:zone] when implementing the NSCopying protocol.
As others have stated though, NSNumber is immutable and so returns the same object.
Related
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.
When inserting an object into an array with a property is there any reason to invoke the getter/setter with self? i.e.
[self.myArray insertObject: myObject];
Or can I just use:
[myArray insertObject: myObject];
the gist would be:
.h
#interface ArrayViewController : UIViewController <UITextFieldDelegate>
{
NSMutableArray *myArray;
int itemNumber;
}
#property (nonatomic, retain) NSMutableArray *myArray;
#end
.m
- (IBAction)createMyArray
{
self.myArray = [[NSMutableArray alloc] initWithObjects: nil];
}
-(IBAction) addItemToMyArray
{
NSString *myString = [[NSString alloc] initWithFormat:#"item %d",itemNumber];
[myArray addObject: myString];
//[self.myArray addObject: myString]; //Or should I use self?
[myString release];
NSLog(#"myArray = %#", myArray);
itemNumber++;
}
//- (void)dealloc etc. not shown
Conceptually, it doesn't matter, so long as your getter method only returns the existing field value and doesn't, eg, do some "just in time" allocation or some such.
However, it's good practice to come up with a policy (personal or group) that you stick with, so that the caveats of that policy become second nature. Constantly switching styles results in sloppy, buggy code.
I tend to always use the self. for properties, just to remind myself that they are, in fact, properties, and to make it less likely that I'll accidentally set the value without using the property notation.
Either will work but you need to be aware of what you are doing. Using self. will invoke the setter/getter methods while the other will just access the variable directly. Using the variable directly, while perfectly valid, is discouraged outside of the initializer and dealloc method. The reason is you are losing out on the benefits of the property, especially setting using self. because it will properly assign/copy/retain the value for you correctly. Another reason not use property variables directly is because of atomicity but in your case you declared it as nonatomic.
Both of those are fine. It's mostly a stylistic choice. Using self.myArray will result in a call to the getter [self myArray].
When using alloc/init you should not set the returned value to a property, as these will retain twice:
self.myArray = [[NSMutableArray alloc] initWithObjects: nil];
use
myArray = [[NSMutableArray alloc] initWithObjects: nil];
or
self.myArray = [NSMutableArray array];
for the initialization.
The insert operations are equivalent though.
I typically skip the getter because I rarely find it valuable and it clutters up the readability of the code a bit. However, I tend to use the setter because I find it easier to allow the auto-generated setter methods to handle the retain/release semantics
In your case it's not an obligation to use self.myArray but for this case belloaw it will be an obligation:
-(void) addItemToMyArray:(NSAarray *)myArray
{
NSString *myString = [[NSString alloc] initWithFormat:#"item %d",itemNumber];
[self.myArray addObject: myString];
[myString release];
NSLog(#"myArray = %#", self.myArray);
itemNumber++;
}
to difference between the class attribut and the function argument.
I am developing a iPhone app using core data that has a to-many relationship and in one of my classes i have a NSSet property. I am creating an NSSet, assigning to this property and then releasing the object, the problem is a i am getting an EXC_BAD_ACCESS.
NSSet *feedSet = [[NSSet alloc] initWithSet:mutableFeedSet];
Signature *signature = (Signature *) [NSEntityDescription insertNewObjectForEntityForName:#"Signature" inManagedObjectContext:context];
signature.site = [feed objectForKey:#"site"];
signature.url = [feed objectForKey:#"url"];
signature.feedList = feedSet;
NSLog(#"%d", [feedSet retainCount]);
[context save:&error];
[feedArray release];
[mutableFeedSet release];
[formatter release];
[feedSet release];
when i printed the feedSet retain count i realized that the signature.feedList = feedSet; wasn't retaining the object, so i removed the [feedSet release]; and the i got the problem solved... The question is. Why when a assign the feedSet to the feedList property it didn't retained the object?
Thanks!
Probably Signature is your class, and you have property feedList. If you want to retain the object you have to declare it like this
#property(nonatomic, retain) NSSet* feedList;
If signature.feedList = feedSet; isn't retaining it, it is because the property is defined as assign (not copy or retain). Or, if not synthesized, your setter implementation is hosed.
If that isn't the case, you have a stray autorelease or release somewhere.
Note that retainCount is not a very good indicator here; autorelease will not cause the retain count to decrement immediately.
Aha! You said #dynamic feedList; Is this a managed object subclass?
#dynamic does not provide method implementations. So, either you have implemented setFeedList: or you are subclassing NSManagedObject (or their is a superclass involved).
Which is it?
And post the crash backtrace, too, please.
Hey all. I know this question's been asked but I still don't have a clear picture of memory management in Objective-C. I feel like I have a pretty good grasp of it, but I'd still like some correct answers for the following code. I have a series of examples that I'd love for someone(s) to clarify.
Setting a value for an instance variable:
Say I have an NSMutableArray variable. In my class, when I initialize it, do I need to call a retain on it?
Do I do
fooArray = [[[NSMutableArray alloc] init] retain];
or
fooArray = [[NSMutableArray alloc] init];
Does doing [[NSMutableArray alloc] init] already set the retain count to 1, so I wouldn't need to call retain on it? On the other hand, if I called a method that I know returns an autoreleased object, I would for sure have to call retain on it, right? Like so:
fooString = [[NSString stringWithFormat:#"%d items", someInt] retain];
Properties:
I ask about the retain because I'm a bit confused about how #property's automatic setter works.
If I had set fooArray to be a #property with retain set, Objective-C will automatically create the following setter, right?
- (void)setFooArray:(NSMutableArray *)anArray {
[fooArray release];
fooArray = [anArray retain];
}
So, if I had code like this: self.fooArray = [[NSMutableArray alloc] init]; (which I believe is valid code), Objective-C creates a setter method that calls retain on the value assigned to fooArray. In this case, will the retain count actually be 2?
Correct way of setting a value of a property:
I know there are questions on this and (possibly) debates, but which is the right way to set a #property?
This?
self.fooArray = [[NSMutableArray alloc] init];
Or this?
NSMutableArray *anArray = [[NSMutableArray alloc] init];
self.fooArray = anArray;
[anArray release];
I'd love to get some clarification on these examples. Thanks!
According to Apple's Object Ownership Policy, any method that begins with the words alloc or new, or contains copy is owned by the caller.
To obtain ownership of an object, you must retain it.
So, in your first example, the retain is unnecessary because you already own the object.
The correct way to do this:
fooArray = [[NSMutableArray alloc] init];
Since autoreleased objects are owned by the current autorelease pool, you must call retain on them to gain ownership of them, so this example is correct:
fooString = [[NSString stringWithFormat:#"%d items", someInt] retain];
This would work fine as well:
self.fooString = [NSString stringWithFormat:#"%d items", someInt]; //retained by property setter
And for your last example using the property setter, this would be the correct way to do it:
NSMutableArray *anArray = [[NSMutableArray alloc] init];
self.fooArray = anArray;
[anArray release];
Instead of having to do the above, I'd suggest the following solution:
self.fooArray = [NSMutableArray arrayWithCapacity:10];
arrayWithCapacity: will return an autoreleased NSMutableArray, which is the retain-ed by the property setter method. :)
Ideally you would want to use the accessors whenever possible, especially when dealing with objects as they help avoid many memory issues. So even for instance variables, you should do:
self.fooArray = ...;
instead of
fooArray = ...;
The reason why you should declare properties for object instance variables is because the memory management is slightly more complicated, and recreating it by hand each time is tricky. The correct setter for a nonatomic, retained property would look like:
- (void)setFoo:(NSArray *)aFoo {
if (foo == aFoo) {
return;
}
NSArray *oldFoo = foo;
foo = [aFoo retain];
[oldFoo release];
}
You are right about the instance variable having a retain count of 2 when you do something like this (assuming foo is retained):
self.foo = [[NSMutableArray alloc] init];
The first retain count is coming from alloc, and the second one from your synthesized setter. Any of these should work:
// longer, explicit version, releases immediately (more efficient)
NSMutableArray *aFoo = [[NSMutableArray alloc] init];
self.foo = aFoo;
[aFoo release];
// autoreleased, not so bad unless you're a memory management freak
self.foo = [[[NSMutableArray alloc] init] autorelease];
// an even shorter version of the above
self.foo = [NSMutableArray array];
To create private properties, you can declare them as a class extension in the .m implementation file. To give an example, consider a simple Person object, which has a name, and a boolean property didSave which simply indicates whether the object has been saved to some database or not. Since we don't want to expose this to the outside world, but still keep the benefits of properties inside the implementation file, we can create the header file will all instance variables (public, private, protected) and only public properties:
// Person.h
#interface Person {
NSString *name;
#private
BOOL didSave;
}
#property (nonatomic, retain) NSString *name;
#end
But declare private properties inside the implementation:
// Person.m
// property is declared as a class extension, making it
// invisible to the outside world.
#interface Person ()
#property BOOL didSave;
#end
#implementation
// synthesize as normal
#synthesize name, didSave;
#end
First of all, with this line:
fooArray = [[NSMutableArray alloc] init];
fooArray will automatically have a retain count of 1.
Second, yes, it's 2. And your guess on the setter implementation is correct.
Third, the latter one is right
I have 1 NSString *abc = #"Hardik";
i have NSMutableArray *array;
now i had written [array addobject:abc];
then i'm printing,NSLog(#"array = %#", array);
but i'm getting NULL
why?
I have declared NSMutableArray *array; in a.h file
i had set #property(nonatomic,retain)NSMutableArray *array;
#synthesize array;
and i have synthesize it but getting value NULL
I'm not able to understand it?
You also need to initialise your array:
array = [[NSMutableArray alloc] initWithCapacity:10];
This is pretty fundamental stuff. Have you read the "Learning Objective C Primer" yet?
It sounds like you haven't actually allocated array. Generally, you would do this in your initializer. (Don't forget to add a release to your dealloc method, too.) #synthesize creates the getter and setter, but you still have to handle allocating/deallocating the object yourself.
It sounds like your NSMutableArray* array property may not have been initialised?
Can you post your class init method?
To trigger the synthesized accessor within a class itself, you must use self. If you don't, you access the attribute's address directly bypassing the accessor methods. You need:
NSString *abc = #"Hardik";
[self.array addobject:abc];
NSLog(#"array = %#", self.array);
The reason this is important is that the synthesized methods usually also initialize the property. The internals of the synthesize array method would look something like:
-(NSArray *) array{
if (array!=nil) {
return array;
}
array=[[NSMutableArray alloc] initWithCapacity:1];
return array;
}
self.propertyName is really just shorthand for [self propertyName] and self.propertyName=someValue is just shorthand for [self setPropertyName:someValue].
Until you call self.array at least once, the array property is not initialized.
However, just to confuse things, once you have called self.array once it is initialized so you can just call array directly. So...
[self.array addObject:abc];
NSLog(#"array = %#", array);
...works while the converse would return just an empty array.
So the rules are:
Within a class implementation
(including subclasses), calling just
propertyName gives you the address
of the property but does not call
the getter/setter accessor methods.
Within a class implementation
(including subclasses), using
self.propertyName calls the
getter/setter accessor methods but
does not access attribute directly.
From outside the class
implementation e.g.
myClass.propertyName calls the
getter/setter accessor methods.