I'm declaring an NSString property in a class and objective-c is complaining that:
NSString no 'assign', 'retain', or 'copy' attribute is specified
It then casually lets me know that "assign is used instead".
Can someone explain to me the difference between assign, retain and copy in terms of normal C memory management functions?
I think it is drawing your attention to the fact that a assign is being used, as opposed to retain or copy. Since an NSString is an object, in a reference-counted environment (ie without Garbage Collection) this can be potentially "dangerous" (unless it is intentional by design).
However, the difference between assign, retain and copy are as follows:
assign: In your setter method for the property, there is a simple assignment of your instance variable to the new value, eg:
- (void)setString:(NSString*)newString
{
string = newString;
}
This can cause problems since Objective-C objects use reference counting, and therefore by not retaining the object, there is a chance that the string could be deallocated whilst you are still using it.
retain: this retains the new value in your setter method. For example:
- (void)setString:(NSString*)newString
{
[newString retain];
[string release];
string = newString;
}
This is safer, since you explicitly state that you want to maintain a reference of the object, and you must release it before it will be deallocated.
copy: this makes a copy of the string in your setter method:
- (void)setString:(NSString*)newString
{
if(string!=newString)
{
[string release];
string = [newString copy];
}
}
This is often used with strings, since making a copy of the original object ensures that it is not changed whilst you are using it.
Cocoa uses reference counting to manage memory. Objects with a reference count of 0 are deleted.
assign - does nothing to reference count simply points your variable to the data
retain - points your variable to data and adds 1 to reference count, data is guaranteed to be there while your variable is still alive
copy - makes a copy of data, points your variable at it and makes the retain count 1
More detail here, at Apple's own documentation.
assign - the ivar is set by doing a simple assignment. Implementation:
- (void) setFoo:(NSString *)newFoo {
foo = newFoo;
}
retain - the ivar is sent the retain message before doing the assignment. Implementation:
- (void) setFoo:(NSString *)newFoo {
if (foo != newFoo) {
[foo release];
foo = [newFoo retain];
}
}
copy - the ivar is sent the copy message before doing the assignment. Implementation:
- (void) setFoo:(NSString *)newFoo {
if (foo != newFoo) {
[foo release];
foo = [newFoo copy];
}
}
Related
I am trying to dynamically instantiate a c array of blocks, load it and then run them and could use some help.
// Definitions ===========================================
typedef void (^MorphC)(ScratchC* scratch);
#property (nonatomic) MorphC __strong * morphCs;
// Building up the Morph Registry ========================
static NSMutableDictionary* morphs_;
+ (void) initialize {
morphs_ = [[NSMutableDictionary alloc] init];
[MathC hydrate];
}
+ (void) hydrate {
[MathC registerMorph:#"sin" execute:^(ScratchC* scratch) {
AEScratchPush(scratch, sin(AEScratchPop(scratch)));
}];
}
+ (void) registerMorph:(NSString*)name execute:(MorphC)execute {
[morphs_ setObject:execute forKey:name];
}
+ (MorphC) morphFromKey:(NSString*)key {
return [morphs_ objectForKey:key];
}
// Loading up a temporary NSMutableArray* _compiling =====
- (void) applyTag:(NSString*)tag stack:(Stack*)stack {
[_compiling addObject:[MathC morphFromKey:tag]];
}
// Initializing C Array and loading from NSMutableArray ==
- (void) build {
_morphCs = (MorphC __strong *)malloc(_compiling.count*sizeof(MorphC));
i = 0;
for (MorphC morph in _compiling)
_morphCs[i++] = morph; // Currently, getting a bad ACCESS here
}
// Executing the Morphs ==================================
- (CGFloat) evaluateFloat:(VarsC*)vars {
if (![_morphs count]) return NAN;
AEScratchLoadVariables(_scratch, vars);
for (int i=0;i<[_morphs count];i++)
_morphCs[i](_scratch);
return AEScratchPop(_scratch);
}
I'm currently getting a EXC_BAD_ACCESS while building up the C Array, but I suspect I have a number of issues. I don't totally understand the need for the __strong at the morphCs definition, but the compiler complains with out. Should the property have a strong indicator also?
Do I need to be doing [morph copy] in one or more places?
Is there anything else I'm messing up?
You can't malloc an array of strong pointers.
Think about the semantics of a strong pointer: When it is declared, it's value is initialized to nil. When the variable goes out of scope, it releases its existing value. Therefore, the compiler must be able to keep track of strong pointers to be able to carry this out. If you have an array of strong pointers of unknown length, when it goes out of scope for example, how can the compiler know how many pointers to release? It can't.
In C++ terminology, strong references are "non-POD" types - they have nontrivial constructors and destructors. Therefore, they cannot be allocated with malloc.
It is mentioned here in the ARC specification:
It is undefined behavior if a managed operation is performed on a
__strong or __weak object without a guarantee that it contains a primitive zero bit-pattern, or if the storage for such an object is
freed or reused without the object being first assigned a null
pointer.
In other words, the only way you can use malloc and free is if you guarantee that every time after you call malloc you zero the memory of all the pointers you allocated, before using them. And every time before free you guarantee to first assign nil to each strong pointer in the array.
However, in Objective-C++, you can use new[] and delete[] to dynamically allocate arrays of strong pointers.
These requirements are followed automatically in Objective-C++ when
creating objects of retainable object owner type with new or new[] and
destroying them with delete, delete[], or a pseudo-destructor
expression.
Here is implement of a setter method:
- (void)setCount:(NSNumber *)newCount {
[newCount retain];
[_count release];
// Make the new assignment.
_count = newCount;
}
If retainCount of _count is <=0, how it can release ?
The only valid object that can ever have a retain count of 0 is nil. And sending any message to nil just returns 0 without doing anything else, so that case is covered.
If you mean "how can this work with a deallocated object" — well, it can't. And a deallocated object's retain count isn't really 0, because the object doesn't exist anymore — it's been destroyed and is now just a chunk of memory — so it doesn't have any attributes. Doing anything with a deallocated object is invalid and what will happen is undefined.
Imagine a class with a retainCount instance variable.
#implementation MyClass
{
NSUInteger retainCount;
}
- (id) retain {
retainCount++;
return self;
}
- (void) release {
if (retainCount > 1)
retainCount--;
else
[self dealloc];
}
...
#end
Once an object is deallocated, it is dead, gone, done for, etc... Thus, there is no point in ever decrementing the retainCount to 0 because, by definition, the object is going to be deallocated and working with a deallocated object is undefined behavior.
The above is the exact logic of NSObject, but a completely different implementation (you really wouldn't want to see NSObject's actual implementation -- it is quite painful).
The other source of confusion appears to be what a reference means.
NSObject *foo;
char *bar;
NSUInteger baz;
For all intents and purposes, the above three variable declarations behave identically [in manual retain/release].
When you say bar = "Hello, World!";, you are telling the compiler 'copy the address of the memory that holds the string "Hello, World!" into the memory named bar". Same for foo, only you are copying the address of memory that holds an instance of the class NSObject.
Now, baz may seem different. But it really isn't except that it holds numbers, not addresses. But, really, an address is a number!
So, in a setter::
- (void)setCount:(NSNumber *)newCount {
// increment newCount's retain count
[newCount retain];
// decrement the _count's retain count (which may cause it to be deallocated or not)
[_count release];
// copy the address of the memory that holds the NSNumber instance referenced
// by `newCount` into the instance variable `_count`.
_count = newCount;
}
There is nothing magical about that assignment [under manual retain release]. It is just copying a number from one variable to the other. The objects are not impacted at all by this.
As you know, in ARC, __block variables of object pointer type used in a block are retained by the block. So take the following simplified example:
__block id foo = getObject();
void (^aBlock)() = ^ {
NSLog(#"%#", foo);
foo = getObject();
}
runBlockAsynchronouslyMultipleTimes(aBlock);
The object pointed to by foo is retained by the block, so that when the block is run (asynchronously), the object is still valid and can be printed. When we do the assignment within the block, ARC manages it like any other strong reference (the old value is released and the new value retained). (The assignment forces us to use __block in the first place.) And when the block is not needed anymore, ARC somehow releases its retained object pointed to by foo at that point (it is not leaked).
Okay, now suppose I want to do the same thing under MRC (why is not important; this is an question about the language). As you know, __block variables of object pointer type used in a block are NOT retained by the block in MRC. Which is fine; we'll manage it ourselves (this is MRC, after all). So the attempt looks like this:
__block id foo = [getObject() retain];
void (^aBlock)() = ^ {
NSLog(#"%#", foo);
[foo release];
foo = [getObject() retain];
}
runBlockAsynchronouslyMultipleTimes(aBlock);
// where to release foo?
Most of it is straight-forward -- the object is retained by us initially manually; inside the block, when we re-assign the pointer, we release and retain the new value as appropriate.
But then comes the problem: How do we release the object when the block is not needed anymore? Since we manually manage the memory, we should ideally manually release the object when the block is deallocated. But there doesn't seem to be an easy way to do so.
I could think of maybe one way: using associative references to tie the object to the block. But then to re-assign the associative reference inside the block, the block would need a reference to itself, so the block variable would also need to be __block and the block needs to be copied prior to setting the variable. Which is all very ugly. Or, we put the object inside a mutable container object that is then retained by the block; but that is ugly too.
The mutable container is about as clean as you can get. You could create a simple wrapper with a single object property to clean it up a little, and then you would get memory management from the property accessors.
An approach which would look cleaner, but is actually kind of messy underneath, would be to have an immutable wrapper which took a pointer, and just released that pointer when it was deallocated.
#interface ObjectReleaser : NSObject {
id *objectPointer;
}
- (id)setObjectPointer:(id *)pointer;
- (void)captureMe;
#end
#implementation ObjectReleaser
- (void)setObjectPointer:(id *)pointer {
if(!objectPointer && pointer) {
objectPointer = pointer;
[*objectPointer retain];
}
}
- (void)dealloc {
if(objectPointer) [*objectPointer release];
[super dealloc];
}
- (void)captureMe {} // Blocks can call this to capture the object
#end
The block would catch and retain this object, since it is not __block. You would modify your __block object as usual, with all of the proper retains and releases. Then, when the block is deallocated, it will release the releaser, which will then be deallocated and release whatever your pointer currently points to.
__block id foo = getObject();
ObjectReleaser *releaser = [[ObjectReleaser alloc] init];
void (^aBlock)() = ^ {
[releaser captureMe];
NSLog(#"%#", foo);
[foo release];
foo = [getObject() retain];
}
aBlock = [aBlock copy];
[releaser setObjectPointer:&foo];
Note that you don't need to retain foo just for the block, because the releaser does that for you. You do have to set the releaser's pointer after copying the block, since the copy will change foo's pointer. This is also why it is safe to save the pointer of a stack variable after your function returns: the variable is not actually on the stack.
I can't figure out why my app is crashing after a few times I'm doing:
potionsT is nonatomic, retain, readonly.
-(void)First:(NSString*)Potions {
potionsT = [[NSString alloc] initWithString:Potions];
}
-(void)After:(NSString*)Potions {
[potionsT release];
potionsT = [[NSString alloc] initWithString:Potions];
You see, I'm first calling First and after that I'm calling a few times After: and wopes, it crashes. with ECX_BAD_ACCESS.. I'm pretty noob with all that memory manage thing, I know that... Thanks!
The point of retained property is it handles retain and release when you set it.
- (void)first:(NSString*)potions
{
self.potionsT = potions; // will automatically release old value and retain new
}
- (void)after:(NSString*)potions
{
self.potionsT = potions; // same as above
}
Also note how i renamed your Potions to potions, First: to first:, and After: to after:. Objective-C naming convention is to start variables and methods with lowercase letter, and class names with capital.
Did you #synthesize the property in the #implementation for the class? If so, then you should use:
self.potionsT = Potions;
if you use
potionsT = ...
then you are accessing the ivar, not the property. To access the property and let it do the memory management for you, you must precede it with an instance reference, and that can also be self.
If you use the property, you should not release potionsT manually, since the property already does that for you.
If you've set up potionsT as a property, you should access it that way:
-(void)first:(NSString*)potions {
self.potionsT = potions;
}
-(void)after:(NSString*)potions {
self.potionsT = potions;
}
In both cases, I changed your code to use the accessor for potionsT (that's what the self.potionsT means). I'm also not creating a new string, but just retaining the provided one. Since NSStrings are immutable, the result is the same. For best results, though, change the potionT property from retain to copy. That way, if a mutable string gets passed in, it'll be copied instead of retained (and immutable strings will still just be retained).
I am a little curious about the last lines in the two examples presented below (i.e. planetName = [value ??????]) My understanding is that the 1st example with the copy is best as that takes a copy of the string object to protect against the original string object being changed elsewhere.
I am also a little confused by the last line in the 2nd example, again my understanding was that the value object was being passed into the method, I guess I am confused as value is being retained with no associated release? Can someone set me straight?
- (void)setPlanetName:(NSString *)value {
if (planetName != value) {
[planetName release];
planetName = [value copy];
}
}
.
- (void)setPlanetName:(NSString *)value {
if (planetName != value) {
[planetName release];
planetName = [value retain];
}
}
Given:
- (void)setPlanetName:(NSString *)value {
if (planetName != value) {
[planetName release];
planetName = [value copy];
}
}
The -copy ensures that if someone passes in an instance of NSMutableString as value, then planetName won't change in your instances out from under you.
A good defensive programming pattern. Note that -copy is free on immutable strings; -copy just bumps the retain value and returns self (the instance of the string that was copied).
Now, consider your second example:
- (void)setPlanetName:(NSString *)value {
if (planetName != value) {
[planetName release];
planetName = [value retain];
}
}
Perfectly valid and works fine, just not as defensive.
In both cases, planetName must be released in your -dealloc method.
- (void) dealloc
{
[planetName release];
planetName = nil; // defensive
[super dealloc];
}
It doesn't matter if the string is copied, retained, or was originally a constant string that was passed into your setter. If you retain it (or implied retain it through copy), you must release it.
Note that you can think of this as "escape patterns". Whenever the existing value of planetName escapes your object, you must release it. That can happen when the object is deallocated or when a new value of planetName is set, hence the -release in the setters.
Or, if on Mac OS X, you could turn on garbage collection and be done with it. In any case, you should be using #property & #synthesize to automatically generate the getter/setter pair.
in the class's dealloc method, there should be another [planetName release] there, which will handle releasing of any instance variables. If that is present then there is no memory leak to worry about.
As for your other question, yes copy is used if you potentially have a mutable object that you don't want to allow other code to be able to modify what your class expects. You are expected to release any object that you call copy on, as it returns something with a retain count of 1. Also, in the case of immutable objects (like NSStrings vs. NSMutableStrings) copy just calls retain since there is no need to make a full copy of something that is immutable.