Lets say I have local variable(not property) Obj *x = d, is d's reference count incremented? Or is it default a weak reference?
Apple's documentation (Variable Qualifiers section) said:
https://developer.apple.com/library/ios/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html
__strong is the default. An object remains “alive” as long as there is a strong pointer to it.
Say you write
__weak NSMutableArray* myArray = [[NSMutableArray alloc] init];
What happens? What happens is that the only reference to that array is in a weak variable, which means it gets deallocated immediately and myArray is set to nil. Now say you write
NSMutableArray* myArray = [[NSMutableArray alloc] init];
What would happen if the default is "weak"? Does that answer your question?
They are strong by default.
docs
Related
Is there a difference between the initializations [NSArray new] and [NSArray array]?
array seems to be part of the implementation of NSArray while new belongs to NSObject.
new = alloc + init
This method is a combination of alloc and init. Like alloc, it
initializes the isa instance variable of the new object so it points
to the class data structure. It then invokes the init method to
complete the initialization process.
NSObject Class Reference
+new is implemented quite literally as:
+ (id) new
{
return [[self alloc] init];
}
and new doesn't support custom initializers (like initWithObjects), so alloc + init is more explicit than new
So the question now is about:
[NSArray array] vs [[NSArray alloc] init]
The main difference between these is if you're not using ARC
(Automatic Reference Counting). The first one returns a retained and
autoreleased object. The second one returns an object that is only
retained. So in the first case, you would want to retain it if you
wanted to keep it around for longer than the current run loop. In the
second case, you would want to release or autorelease it if you didn't
want to keep it around.
Now that we have ARC, this changes things. Basically, in ARC code, it
doesn't matter which of these you use.
But keep in mind that [NSArray array] returns an empty immutable array, so using array with NSMutableArray makes more sense
For more information:
alloc, init, and new in Objective-C
Use of alloc init instead of new
Difference between [NSMutableArray array] vs [[NSMutableArray alloc] init]
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
In my iOS app ARC is disabled. I find some memory leak issues in my code when i inspect my code using instrument tool, it is described bellow.
Obj1 is a an object that declared in the .h file (its type is classA).
I set the value of Obj1 in .m file using the code:
self.Obj1 = [[classA alloc]init];
I release Obj1 in the dealloc method.
this code works fine. but shows a memory leak issue.
How can i avoid this memory leak issue.??
Use below code :
self.Obj1 = [[[classA alloc]init]autorelease];
Dealloc will only be called when the view is not in use or unload.
If you use NSZombieEnabled macros for handling work with released objects all objects (even released) will have at least 1 retain count and tools will show all object as "leaking". Just turn off this macro when you work with memory leaks.
See technote for references:
https://developer.apple.com/library/ios/technotes/tn2239/_index.html
If you make a property retain Obj1 means increment by 1 then after you alloc this object by increment 1, so it's value retain 2.
Use below code:
ClassA *objC = [[classA alloc]init];
self.Obj1 = objC;
[objC release];
There are many ways to handle this :
First,
self.Obj1 = [[[classA alloc]init]autorelease];
Second,
Obj1 = [[classA alloc]init];
...
// use self.Obj1 in the code
...
[Obj1 release];
Third,
self.Obj1 = [[classA alloc]init];
...
[self.Obj1 release];
Use any one out of these.
You can remove self., just Obj1 = [[classA alloc]init];.
Because when you call self.,you retain the object again.So after self.Obj1 = [[classA alloc]init];,object retain count is 2.
I have an object with a property that points to a block:
typedef void (^ThingSetter)();
#property(nonatomic, strong) ThingSetter setup;
I initialize the property with a block. Within the block I refer to the object instance:
Thing *thing = [[Thing alloc] init];
thing.setup = ^() {
plainOleCFunction(thing.number);
[thing doSomethingWithString:#"foobar"];
};
However I get compile warnings about a retain loop:
capturing 'thing' strongly in this block is likely to lead to a retain cycle
block will be retained by the captured object
What is the correct way to do this?
Thanks,
Doug
you have to assign thing as weak ref:
Thing *thing = [[Thing alloc] init];
__weak Thing *weakThing = thing;
thing.setup = ^() {
plainOleCFunction(weakThing.number);
[weakThing doSomethingWithString:#"foobar"];
};
or you could provide thing as Parameter to the block:
Thing *thing = [[Thing alloc] init];
thing.setup = ^(Thing *localThing) {
plainOleCFunction(localThing.number);
[localThing doSomethingWithString:#"foobar"];
};
thing.setup(thing);
Because you are using "thing" inside the block, block will maintain a strong pointer to "thing" until the block goes out of scope or the block itself leaves the heap (i.e. no one points strongly to the block anymore) - which is what you want because blocks are first traveled and then the code is executed at some later point so you obviously do not want the block to loose the pointer to "thing" after the block is first traveled without execution.
Now, you have the block maintaining a strong pointer to "thing" and you have "thing" maintaining a strong pointer to the block through its property "setup". Neither "thing" nor the block can ever escape the heap now. That’s because there will always be a strong pointer to both of them (each other’s pointer). This is called a memory “cycle.”
The answer is to declare "thing" as weak:
Thing *thing = [[Thing alloc] init];
__weak Thing *weakThing = thing;
And use "weakThing" in the block. This solves the problem because now the block only has a weak pointer to "weakThing" . "thing" still has a strong pointer to the block through its property setup, but that’s okay.
Hope this was helpful
This question already has answers here:
When to use -retainCount?
(11 answers)
Why retain count in negative value? [duplicate]
(1 answer)
Closed 10 years ago.
I have property:
#property(nonatomic, retain) NSMutableArray *myvar;
First case:
myvar = [[NSMutableArray alloc] init];
NSLog(#retainCount: %i:", [myvar retainCount]);
outputs:
retainCount: 1
Second case:
self.myvar = [[NSMutableArray alloc] init];
NSLog(#retainCount: %i:", [self.myvar retainCount]);
outputs:
retainCount: 2
My question is: why in the second case retain value is 2 ?
The only valid answer: never check, use, trust retainCount. it is not meant for debugging or use directly for memory management.
useful: whentouseretaincount.com
But in your case: As you are not using ARC (otherwise the compile wouldnt allow you to use retainCount anyway) you are over retaining.
it retain here #property(nonatomic, retain) NSMutableArray *myvar;
and here: self.myvar = [[NSMutableArray alloc] init];
do:
self.myvar = [[[NSMutableArray alloc] init] autorelease]; //will release once soon
or my favorite, as independent from ARC/MRC and short
self.myvar = [NSMutableArray array]; // identical to the first example
or more explicit
NSMutableArray *var = [[NSMutableArray alloc] init];
self.myvar = var;
[var release];
+1 because you alloc/init'd it
+1 because self.myvar retains it (as set out in your property declaration)
if you autorelease after alloc/init, it will go back down to 1... then if you set self.myvar to nil, it will hit 0 (if nothing else has retained it in the meantime)
But as vikingosegundo has said, you don't want to be messing with retain counts. The OS determines when to knock them back down, so you can't use them as a reliable measure of state.
Here's a rule that I used to go by before ARC came along:
'The NARC rule':
If you use New, Alloc, Retain or Copy, increase the count by one.
Your retain count is 2 in the second case because you are using alloc and retain on the instance property of the class (by using the self keyword). In the other case you are not using the synthesized setter to set the variable, and therefore not using retain. Explore what properties actually do for increased understanding.
vikingosegundo has explained well the correct way to do things in his answer.
Hope that helps!
See this answer: Question About Retain Counts & initializing member variables
First, you alloc init a new NSArray object. That's a retain count of
1. Second, your setter sends the object a retain message when assigning it to your instance var. That bumps the retain count up to
2.
Cheers.