What does #propert(retain) do? it doesn't actually retain my object by my tests:
id obj = getObjectSomehow();
NSLog(#"%d", [obj retainCount]);
propertyWithRetain = obj;
NSLog(#"%d", [obj retainCount]);
// output:
// 1
// 1
How can I make a property that will really retain the object?
You're not using your property there, that's why it's not retaining!
Try this :
id obj = getObjectSomehow();
NSLog(#"%d", [obj retainCount]);
self.propertyWithRetain = obj; // Note the self. :)
NSLog(#"%d", [obj retainCount]);
Using self. will use the property. Just using the variable name won't.
EDIT especially for #bbum (who raises a very fair point in the comments)
Don't rely on using retainCount - you don't know what else has retained your object and you don't know if some of those retains are actually scheduled autoreleases so it's usually a misleading number :)
propertyWithRetain = obj;
That just sets the ivar backing the property directly. When an #property is synthesized, if there is no instance variable declared, then one is generated automatically. The above is using that ivar directly.
self.propertyWithRetain = obj;
That would actually go through the #synthesized setter and bump the retain count.
Which is also why many of us use #synthesize propertyWithRetain = propertyWithRetain_; to cause the iVar to be named differently.
Note that, even in this, calling retainCount can be horribly misleading. Try it with [NSNumber numberWithInt: 2]; or a constant string. Really, don't call retainCount. Not ever.
Related
Similar things have been asked before, but I was unable to solve my current problem with any of these answers.
Situation:
CustomType *Object;
BOOL (^doAverage)(CustomType *, int, int) = ^(CustomType *Trigger, int Total, int Pulse) {
//Calculate Average from Total and Pulse
Total /= Pulse;
[Trigger setValue:Total];
};
Object = [CustomType CreateObject]; //Autoreleased Object
[Object addCallback:^{ return doAverage(Object, 56, 32); }];
[Array addObject:Object]; //Adds to collection.
The issue at hand is a retain cycle as you probably already figured.
Object keeps a reference to the block in addCallback, and the block doAverage retains the reference to Object.
Using an instance variable is out of the question, because I want to reuse the variable Object for multiple objects. (Temporary variable).
Using a local variable results in the retain count.
And using __block CustomType *Object doesn't work either, because for whatever reason Trigger ends up as nil once the callback is actually called.
Any ideas?
I have a makeshift solution, but it seems rather...hacky.
Several things. First, I would like to see your addCallback: method. It's possible that you've implemented it incorrectly. For example, if you store a block for use later, you must copy it. If it's incorrect, all bets are off on the rest of the stuff.
And using __block CustomType *Object doesn't work either, because for
whatever reason Trigger ends up as nil once the callback is actually
called.
So if it's nil, then that means you assigned nil to Object somewhere.
As already stated, this answer is rather hacky and I'd be very happy if someone could point me in a better direction.
Apparently a primitive datatype in combination with a __block variable does the trick, though this is a bit complicated.
void *Ptr; //Variable for Block.
__block CustomType *Obj; //Function variable, mutable by block.
BOOL (^doAverage)(void *, int, int) = ^(void *Trigger, int Total, int Pulse) {
CustomType *T = (CustomType *)Trigger; //Conversion
//Calculate Average from Total and Pulse
Total /= Pulse;
[T setValue:Total];
};
//Convenience method.
CustomObject *(^Add)(CustomObject *) = ^(CustomObject *)NewObject {
[Array addObject:NewObject];
Obj = NewObject; //Assigns to the local block-Variable.
return Obj;
};
Ptr = Add([CustomObject CreateObject]); //Creates the Object, and adds it to the array.
[Obj addCallback:^{ return doAverage(Ptr, 56, 32); }];
Since Ptr is a primitive type, it will NOT be retained and does not have to be released. At the same time, it assumes the address of the Object in question and thereby doubles as it.
Once the object is released, so is the block with the pointer and everything is good.
Once the block is called, the pointer needs to be cast to the type in question, but that's only a minor problem.
Add is optional of course, but I don't like the syntax Ptr = Obj = [CustomObject CreateObject];
CustomType *Object;
BOOL (^doAverage)(CustomType *, int, int) = ^(CustomType *Trigger, int Total, int Pulse) {
//Calculate Average from Total and Pulse
Total /= Pulse;
[Trigger setValue:Total];
};
Object = [CustomType CreateObject]; //Autoreleased Object
[Object addCallback:^{ return doAverage(Object, 56, 32); }];
Taylor said -> "What I want however is a 'non-retained copy of the object' in question, which will be 'lost' once the corresponding object is deallocated."
This code doesn't seem to cause a retain-cyle unless you use copy on or inside of addCallback([^{}copy]);..
Where is it exactly the copy is used in your code? Inside of addCallback? if this is like:
addCallback(o) {
o = [o copy];
o();
then do a [o release]; when you done with a block object.. do not release it in dealloc()
}
if you have never used copy anywhere, nothing to be worried about.. It all happens in the stack that means no retain cyles at all unless it is not a global one!
In case there is a retail-cyle, do not use __block __weak etc instead do release whatever object it is in the end of the block.. and bear in mind that no copy no retain cycle..
If your deployment target is at least iOS 5 (or OS X 10.7), you can use "zeroing weak references":
CustomType *object = [CustomType makeObject];
__weak CustomType *weakObject = object;
[object addCallback:^{
CustomType *strongObject = weakObject;
if (strongObject)
return doAverage(weakObject, 56, 32);
else
return 0;
}];
(I have used a makeObject instead of CreateObject for the name of the "factory method", because methods with "create" in their name are expected to return a (+1) retain count object, not an autoreleased object.)
The __weak reference does not increment the retain count, therefore no retain cycle is created. If the object is destroyed because the last strong reference to it is gone, then weakSelf is set to nil. Inside the block a strong reference is created, which either points to the object, if it still exists, or is nil, if it does not exist anymore.
If I understand you code correctly, the callback will not be called if the object has been released. In that case a __unsafe_unretained reference is sufficient (which works also on iOS 4):
CustomType *object = [CustomType makeObject];
__unsafe_unretained CustomType *unsafeObject = object;
[object addCallback:^{
return doAverage(unsafeObject, 56, 32);
}];
Try declaring the Object as
__weak CustomType *Object
I'm currently developing an iOS application which was started by another developer.
Usually, I make a property for every instance variable (assign for int, bool etc. / retain for all classes).
So in my projects, this line causes a leak:
myVar = [[NSString alloc] init]; (alloc/init +1, retain in setter +1, release in dealloc -1 => +1)
So I use:
NSString *tmpMyVar = [[NSString alloc] init];
[self setMyVar: tmpMyVar];
[tmpMyVar release];
Or:
NSString *tmpMyVar = [[[NSString alloc] init] autorelease];
[self setMyVar: tmpMyVar];
In this new project, the previous developer didn't use #property/#synthesize so I'm wondering what will be the result of the previous line of code in this context (it doesn't call setter I guess)? Memory Leak?
The previous developer releases variable in dealloc method, just like me.
Thank you very much!
Since it directly assigns the instance variable to the allocated object it's retain count is 1 (because, like you said, a setter isn't called).
And because it's released in dealloc, it's all balanced out. So no memory leaks.
So in my projects, this line causes a leak:
myVar = [[NSString alloc] init]; (alloc/init +1, retain in setter +1, release in dealloc -1 => +1)
No,it wouldn't even in your projects, because, as you pointed out, no setter is used.
Also, when using properties, it is the recommended way to access instance variables directly in the init method, instead of using setters.
To inspect for questionable memory-leaks like your example, also use the clang static analyzer or instrument's leak tool.
You need to look at the other developer's setter implementation. Make sure they release the existing value and retain the new value; something like:
- (void)setMyString:(NSString *)string
{
[string retain];
[_string release]; // ivar
_string = string;
}
The only advantage to implementing your own setter/getter methods is to do something (other than setting the ivar) when a value is set. If the methods don't do anything like this then why not change all implementations to #property/#synthensize?
I wrote a little convenience method on NSArray which works like PHP's list() function for "unpacking" an array into distinct objects:
- (void)unpackInto:(__strong id *)obj1, ...
{
__strong id *idPtr;
va_list args;
va_start(args, obj1);
idPtr = obj1;
NSUInteger idx = 0;
NSUInteger count = [self count];
while (idPtr != NULL && idx < count) {
*idPtr = [self objectAtIndex:idx];
// Increment the args and idx count
idx++;
idPtr = va_arg(args, __strong id *);
}
}
I originally had __autoreleasing id * but ran into a EXC_BAD_ACCESS issue when this method was called (twice actually, if it matters) on a thread with it's own autorelease pool to unpack the contents into temporary local stack vars. When the main thread came around and attempted to autorelease the contents (again), EXC_BAD_ACCESS was thrown.
Can anyone help me follow the logic with these bridging parameters in this case? I'm concerned that __strong will lead to the slightly less obvious but equally evil twin cousin: memory leak...
I haven't seen your source code, but answer to most ARC problems can be solved if you think in terms of ownerships than retain/release/auto-release pools. Try to answer, who owns the array and who owns the unpacked pointers. If I understand you correctly, your calling method looks something like this
NSArray *arr = [NSArray arrayWithObjects:#"a", #"b", #"c", #"d", nil];
NSString *a, *b, *c, *d;
[arr unpackInto:&a, &b, &c, &d, nil];
Is your array deallocated before you access the unpacked variables? Remember that __autoreleasing doesn't "retain" the values onto your variable argument pointers. So if your array is deallocated, your pointers become garbage.
My guess, your EXC_BAD_ACCESS is because, your main array gets deallocated.
__strong shouldn't be used when you return by reference. It will not increase the retain count. There is no way to let ARC know that, these variables are to be released in the calling method. So ARC releases them after its scope. The only way to pass an allocated object to a calling method and let the calling method deallocate, is by returning it from a method that belongs to a init- family. When you return values across method boundaries, ARC uses method family (or the macros NS_RETURNS_RETAINED/NS_RETURNS_NON-RETAINED) to determine who "owns" the pointer.
You can use __strong for passing by reference if you pass a const pointer (non-writeback pointers) In fact, for const pointers without ownership qualifiers, __strong is implied.
More on this on LLVM documentation here
http://clang.llvm.org/docs/AutomaticReferenceCounting.html#ownership.restrictions.pass_by_writeback
I'm a little confused about Objective-C and allocating/releasing objects.
If I do this:
NSString *myString;
if([someString isEqualToString: #"test1"]){
myString = #"got 1";
}else{
myString = #"got 2";
}
Do I have to release myString after that?
And the same with self-defined objects:
myOwnObject *someObject = [someArray objectAtIndex: 1];
myButton.label1.text = someObject.name;
Do I have to release someObject?
The reason why I'm asking is that I get memory-leaks in a method and I can't find where it is. So I'm trying to figure out whether I do the alloc/release stuff correctly.
The leak occurs on a NSPlaceholderString (I guess that's somewhere hidden in my NIB-File).
Also - if I have an object, allocate it, but only use some of the properties, but DO a release of every property on dealloc - will this cause memory leaks?
Sorry - hope my questions do make at least some sense :)
Thanks for any help!
Listen to me. THIS IS THE ONLY RULE THAT MATTERS.
If you use a method with "copy", "alloc", "new", or "retain" in the name
You own the object and MUST later release or autorelease it.
If you don't:
Don't!
But don't expect the object to stick around outside of that scope, because you don't own it.
It's that simple.
MyClass *foo = [[MyClass alloc] init];
[array addObject:foo];
[foo release];
Did you use "copy", "retain", "new", or "alloc"? Yes. Release it.
MyClass *someObject = [someArray objectAtIndex:0];
Did you use "copy", "retain", "new", or "alloc"? No. Don't release it.
BUT
If you have an instance variable which you need to access in other methods:
ivar = [[someArray objectAtIndex:0] retain];
Then you're guaranteed it will stick around because you own it.
(Another way to handle this is with #property (retain) properties, because then you can do self.ivar = someObject and it'll retain it for you.)
But remember to release them in -dealloc!
No, you don't have to release either of those. I usually release only objects that I alloc, such as this snippet:
NSString *string = [[NSString alloc] initWithFormat:#"%#", something];
// yadda yadda yadda some code...
[string release];
To answer your first question, you don't need to release strings created with the #"" syntax.
On your second example, you should not have to release someObject. However, a problem could arise if your dealloc method in your myOwnObject class does not correctly release all of its instance variables.
Here is code I am referring to.
// Person.h
#interface Person : NSObject {
NSString *firstName;
NSString *lastName;
}
#end
// Person.m
#implementation Person
- (id)init {
if (![super init]) return nil;
firstName = #"John";
lastName = #"Doe";
}
#end
// MyClass.m
#implementation MyClass
.....
- (NSArray *)getPeople {
NSMutableArray *array = [[NSMutableArray alloc] init];
int i;
for (i = 0; i < 10; i++) {
Person *p = [[Person alloc] init];
[array addObject:p];
}
return array;
}
.....
#end
Now, I know there is no memory-management going on in this sample code. What would be required?
In the getPeople loop, I am alloc'ing a Person (retainCount 1), then adding it to array. The retain count is now 2, right? If it is two, should I be [p release]'ing after adding it to the array, bringing the retainCount back down to 1?
Am I right in that it is the caller's responsibility to release the array returned by the method? (Which would also free the memory of the Person's, and their instance variables, assuming their counts are at 1).
I have read Apple's memory management document, but I guess what I am most unclear about, is what increases an objects retain count? I think I grasp the idea of who's responsibility it is to release, though. This is the fundamental rule, according to Apple:
You take ownership of an object if you create it using a method whose name begins with “alloc” or “new” or contains “copy” (for example, alloc, newObject, or mutableCopy), or if you send it a retain message. You are responsible for relinquishing ownership of objects you own using release or autorelease. Any other time you receive an object, you must not release it.
bobDevil's sentence "only worry about the retain counts you add to the item explicitly" made it click for me. After reading the Ownership policy at Apple, essentially, the object/method that created the new object, is the one responsible for releasing /it's/ interest in it. Is this correct?
Now, let's say I a method, that receives an object, and assigns it to a instance variable. I need to retain the received object correct, as I still have an interest in it?
If any of this is incorrect, let me know.
You are correct that the retain count is 2 after adding it to an array. However, you should only worry about the retain counts you add to the item explicitly.
Retaining an object is a contract that says "I'm not done with you, don't go away." A basic rule of thumb (there are exceptions, but they are usually documented) is that you own the object when you alloc an object, or create a copy. This means you're given the object with a retain count of 1(not autoreleased). In those two cases, you should release it when you are done. Additionally, if you ever explicitly retain an object, you must release it.
So, to be specific to your example, when you create the Person, you have one retain count on it. You add it to an array (which does whatever with it, you don't care) and then you're done with the Person, so you release it:
Person *p = [[Person alloc] init]; //retain 1, for you
[array addObject:p]; //array deals with p however it wants
[p release]; //you're done, so release it
Also, as I said above, you only own the object during alloc or copy generally, so to be consistent with that on the other side of things, you should return the array autoreleased, so that the caller of the getPeople method does not own it.
return [array autorelease];
Edit:
Correct, if you create it, you must release it. If you invest interest in it (through retain) you must release it.
Retain counts are increased when you call alloc specifically, so you'll need to release that explicitly.
factory methods usually give you an autoreleased object (such as [NSMutableArray array] -- you would have to specifically retain this to keep it around for any length of time.).
As far as NSArray and NSMutableArray addObject:, someone else will have to comment. I believe that you treat a classes as black boxes in terms of how they handle their own memory management as a design pattern, so you would never explicitly release something that you have passed into NSArray. When it gets destroyed, its supposed to handle decrementing the retain count itself.
You can also get a somewhat implicit retain if you declare your ivars as properties like #property (retain) suchAndSuchIvar, and use #synthesize in your implementation. Synthesize basically creates setters and getters for you, and if you call out (retain) specifically, the setter is going to retain the object passed in to it. Its not always immediately obvious, because the setters can be structured like this:
Person fart = [[Person alloc] init];
fart.firstName = #"Josh"; // this is actually a setter, not accessing the ivar
// equivalent to [fart setFirstName: #"Josh"], such that
// retainCount++
Edit:
And as far as the memory management, as soon as you add the object to the array, you're done with it... so:
for (i = 0; i < 10; i++) {
Person *p = [[Person alloc] init];
[array addObject:p];
[p release];
}
Josh
You should generally /not/ be worried about the retain count. That's internally implemented. You should only care about whether you want to "own" an object by retaining it. In the code above, the array should own the object, not you (outside of the loop you don't even have reference to it except through the array). Because you own [[Person alloc] init], you then have to release it.
Thus
Person *p = [[Person alloc] init];
[array addObject:p];
[p release];
Also, the caller of "getPeople" should not own the array. This is the convention. You should autorelease it first.
NSMutableArray *array = [[[NSMutableArray alloc] init] autorelease];
You'll want to read Apple's documentation on memory management: http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html