#interface
#property (strong) void(^myPropertyBlock)(void);
#end
#implementation
self.myPropertyBlock = ^{[self anyMethod];};
#end
Now the compiler shows a warning regarding 'strong reference cycle' which is what it should be doing.Now if I make 'self' to weak property,it works perfectly fine because as expected,it will break the strong reference cycle.
MyViewController * __weak _self = self;
Now here is the problem:
#interface
#property (weak) void(^myPropertyBlock)(void);
#end
#implementation
self.myPropertyBlock = ^{[self anyMethod];};
#end
1) If I make a block as weak property,it should break the strong reference cycle as well.But ,to my surprise, it doesn't.
I have searched the net but found nothing relevant.
You must declare block as copy otherwise it won't be copied in the heap and when you execute it you will get nasty sigsegv error. It doesn't matter even if you set it implementation and call it on next line. So you must always define it with copy and break retain cycle as needed.
Block itself will keep a strong reference to any objects it references. Declare __weak pointers outside the block and then reference this pointer within the block to avoid retain cycles.
Blocks in and of themselves that create these retain cycles.The block retains self, but self doesn't retain the block. If one or the other is released, no cycle is created and everything gets deallocated as it should.
At block "execution" time, the block copies the "value of weakSelf" (which will be nil if self has been dealloc'ed in the mean time) into strongSelf which ARC then applies a retain to. Thus, for the duration of the block, the object referenced by strongSelf will remain alive, if it was alive to begin with. If you had only relied on weakSelf, it could go nil at any time during the execution of the block.
Hope this helps you: Breaking retain cycle with strong/weak self
Statement Block property, you first need to use the copy modifier, because only after Block copy will exist in the heap.
Related
I have a property defined like this:
#property (nonatomic, retain) MyClass *someObject;
I'm currently using this assignment statement:
someObject = [[MyClass alloc] init];
In terms of memory managment is the above assignment statement equivalent to:
self.someObject = [[[MyClass alloc] init] autorelease];
Assume #synthesize someObject; is in the #implementation section. Also I'm not using ARC.
Note: The following is based on the EDITED version of the original post, where "assign" has been replaced with "retain" ---
Yes, the two are "equivalent", in that they will both result in leaving the MyClass object (properly) retained with a retain count of 1 in the property. The second version goes through some extra work, which may or may not be an issue, depending on how performance-sensitive you are.
Some people argue you should never use the property reference (ie, self.propname) from within the class, but instead reference the instance variable, especially for initialization and deallocation. Others argue just the opposite. I generally favor always using the property reference, except during initialization where (as in this case) using it might result in an extraneous retain/autorelease.
Consider:
typedef void (^select_block_t)(UIView *) ;
(1) #property (copy, nonatomic) select_block_t myBlockProperty ;
(2) #property (strong, nonatomic) select_block_t myBlockProperty ;
(3) #property (assign, nonatomic) select_block_t myBlockProperty ;
and:
(A) self.myBlockProperty = ^(UIView *) {NSLog(#"Hi");} ;
(B) self.myBlockProperty = [^(UIView *) {NSLog(#"Hi");} copy] ;
I am trying to understand what is the correct way to map which property declaration with which block copy semantics
I have seen examples here on S.O. that would favor[1:B]
But then I get confused by how redundant the 'copy' operation is.
My limited understanding is that [1:A] should be correct, because I want
the block to be copied once when I assign the property, not once at block creation and then once again at property assignment time.
[3:B] would also make sense according to my rationale. So, what am I misunderstanding?
[1:A] is correct, yes. [3:B] is incorrect because:
it's not clear that the class owns the property, so should release it in dealloc (but it should)
the setter (B) looks like a leak, and the static analyser might flag it as such, because the block is copied, handed to a property, then leaves the scope with retain count +1.
using (3) means that it only works if you set a heap-block (a copied block) with a retain count of one. This leaves plenty of margin for error when using the property. (1) works with both stack-blocks and heap-blocks, and will also correctly retain auto-released blocks.
EDIT: I see you're using ARC. In that case, it's not possible to use [3:B] at all. The compiler will release an object (even when copyed) once it's out of scope, and this property setter won't have retained it. Therefore the property will contain a bad pointer, it's an EXC_BAD_ACCESS waiting to happen.
I have been working with Objective-C for a month approximately but regretfully I'm still a complete dummy in memory management so I need your advice. I pass an array from one file to the other like this
BidView *bidView = [[[BidView alloc] init] autorelease];
NSLog(#"%i",[bidView.seatsForTableCreated retainCount]);
bidView.seatsForTableCreated = [NSArray arrayWithArray:seats];
NSLog(#"%i",[bidView.seatsForTableCreated retainCount]);
[self.navigationController pushViewController:bidView animated:YES]; `
NSLog tells me that retain count of seatsForTableCreated has raised from zero to two. Then, when I quit the BidView screen (without doing anything with seatsForTableCreated array) I' m doing the following:
NSLog(#"%i",[seatsForTableCreated retainCount]);
[seatsForTableCreated release];
NSLog(#"%i",[seatsForTableCreated retainCount]);
it's quite unclear for me. Now NSLog tells me (both times) that retain count is 1. Then I repeat this procedure (running the same application I mean) and each time things are the same:0-2-1-1. So my questions are:
1)Why 0 to 2? Why retain count increases to 2 not to 1?
2)why then it drops to 1 without being impacted in any way?
3)Why it still remains 1 after i've released it?
4)How would you manage the memory in such a case?
Great thanks in advance
First and foremost. Don't call nor use retainCount for nothing, think about this property as private and only the OS can call. To check if you have a memory leak you should use Instruments.
Seems like you've created an autoreleasing ([NSArray arrayWithArray:seats]) object, so you can't manually release it.
And use the Allocations Instrument to really check if you have a memory leak.
My advice assumes you are using Xcode 4+ and you are not using ARC,
command+shift+B will analyse your memory management (and dead stores and such). I think you got it right. Don't worry about the retain counts so much until you get a complaint from Analyze or find leaks with Instruments. I am not sure how reliable retain counts are. I have seen comments on SO saying not to rely on them.
You are following the rules well
New, Alloc, Copy, Retain --> You will need to release this object when you are done with it.
I am also assuming in BidView.h your property is declared as
#property(nonatomic, retain) NSArray * seatsForTableCreated;
So releasing that in the dealloc method in BidView.m is good memory management
EDIT
It works when even though you don't allocate seats for table created because.
self.seatsForTableCreated = ... will retain whatever object you are setting there.
So if you have a property with (retain) in the declaration, you can consider
self.property = object;
as setting property and retaining it. The properties were added to objective-C to reduce similar code being in every class.
A property in .h
#property (nonatomic,retain) NSObject * property; // don't name your properties property..
Compiler will create 2 methods for you automatically when you #synthesize in the .m
-(void)setProperty:(NSObject*)newP
{
[newP retain]; // retains the new object so it sticks around for line 3
[property release]; // releases previous property
property = newP; // set the property to the object retained in line 1
// property is now same as newP and you are responsible for releasing it
// -(void) dealloc is where you should release it
}
// Note, the compiler may not create the exact same code as above when creating the //setProperty method. If it does, it could be subject to change.
-(NSObject*)property
{
return property;
}
I tried to figure out why Analyze isn't catching the issue when you don't release your property, but haven't. That is confusing and I want to explore it further.
Suppose that i have UIView viewLoading declared in .h. and i do not directly initialize it (in the first code).
The first Code.
UIView *viewLoading2 = [[[UIView alloc] initWithFrame:CGRectMake(75 , 155, 170.0, 170.0)]];
viewLoading = viewLoading2;
[viewLoading2 release]
The second code:
viewLoading = [[[UIView alloc] initWithFrame:CGRectMake(75 , 155, 170.0, 170.0)]];
The third Code:
- (void) viewLoad:(UIView *) viewLoading2
{
viewLoading = viewLoading2;
//do i need to retain, alloc, or release something here?
}
2In the first code, do i need to release viewLoading in dealloc ? And what happen if i do not declare its property?
In the second code, does it have same effect from the first code? (need to dealloc or not).
For the third code, does it have same effect from the first code? and what should i do after i code that? (see the comment)
Do iPhone Code always need to have release for variable declared in .h? Or only if the variable declared in .h is allocated? if like in the first code, do i need to dealloc viewLoading?
what is the different between
self.viewloading = viewLoading2;
and
viewloading = viewLoading2;
Thanks
In the first example, you allocated the object (once), and you released it (once), so you don't need to do anything else. On the other hand, viewLoading is invalid as soon as you send the release to viewLoading2, so it's not very useful code.
In the second, you have not released viewLoading yet, so it does need to be done eventually.
In the third, whatever code allocated the object that was passed into this method via the parameter is responsible for releasing it. It should be valid for the duration of this method, but if you're saving it for later use you need to retain it here, then release it when you're done.
Edit:
I'm not sure I understand your question 4. A declaration in the interface (.h) file is just reserving space for a pointer. It's not an object declaration, so there's no release required until you actually do an object allocation.
self.viewloading = viewLoading2 is using the properties setter method to do the assignment. If the #property statement has "retain" in it, then a retain is done as part of that assignment. `viewloading = viewLoading2" is a straight assignment, no retain.
What is the difference between the following 2 ways to allocate and init an object?
AController *tempAController = [[AController alloc] init];
self.aController = tempAController;
[tempAController release];
and
self.aController= [[AController alloc] init];
Most of the apple example use the first method. Why would you allocate, init and object and then release immediately?
Every object has a reference count. When it goes to 0, the object is deallocated.
Assuming the property was declared as #property (retain):
Your first example, line by line:
The object is created by alloc, it has a reference count of 1.
The object is handed over to self's setAController: method, which sends it a retain message (because the method doesn't know where the object is coming from), incrementing its reference count to 2.
The calling code no longer needs the object itself, so it calls release, decrementing the reference count to 1.
Your second example basically does steps 1 and 2 but not 3, so at the end the object's reference count is 2.
The rule is that if you create an object, you are responsible for releasing it when you're done with it. In your example, the code is done with tempAController after it sets the property. It is the setter method's responsibility to call retain if it needs that object to stick around.
It's important to remember that self.property = foo; in Objective-C is really just shorthand for [self setProperty:foo]; and that the setProperty: method is going to be retaining or copying objects as needed.
If the property was declared #property (copy), then the object would have been copied instead of retained. In the first example, the original object would be released right away; in the second example, the original object's reference count would be 1 even though it should be 0. So you would still want to write your code the same way.
If the property was declared #property (assign), then self isn't claiming ownership of the object, and somebody else needs to retain it. In this case, the first example would be incorrect. These sorts of properties are rare, usually only used for object delegates.
As others have noted, the two code snippets you show are not equivalent (for memory management reasons).
As to why the former is chosen over the latter:
The correct formulation of the latter would be
self.aController= [[[AController alloc] init] autorelease];
Compared with the former, this adds additional overhead through use of the autorelease pool, and in some circumstances will lead to the lifetime of the object being unnecessarily extended (until the autorelease pool is released) which will increase your application's memory footprint.
The other "possible" implementation (depending on where the example is from) is simply:
aController = [[AController alloc] init];
However, setting an instance variable directly is strongly discouraged anywhere other than in an init or dealloc method. Elsewhere you should always use accessor methods.
This brings us then to the implementation shown in sample code:
AController *tempAController = [[AController alloc] init];
self.aController = tempAController;
[tempAController release];
This follows best practice since:
It avoids autorelease;
It makes the memory management semantics immediately clear;
It uses an accessor method to set the instance variable.
Note also that your desire to cut the code down to one line is why many people use Autorelease:
self.aController = [[[AController alloc] init] autorelease];
Though in theory on the iPhone autorelease is somehow more expensive (never heard a clear explanation why) and thus you may want to explicitly release right after you assign the object elsewhere.
If you're using Xcode, it can help you detect such code with the static analyzer.
Just hit Build >> Build and Analyze
This will show you a very helpful message at such pieces of code.
One other thing to note is that your example depends on the #property definition of aController also.
If it were defined as #property (readwrite, retain) id aController; then your example works, while if it is defined as #property (readwrite, assign) id aController; then the extra call to release would cause your object to be deallocated.
You could also do
#property (nonatomic, retain)AController *aController;
...
self.aController= [[AController alloc] init];
[aController release];
with a retaining property, and it would function the same way, but its better to use the other way (for retaining properties) because it's less confusing, that code makes it look like you assign aController and then it gets deleted from memory, when actually it doesn't because setAController retains it.