How do you hold a reference to parameter in a block? - objective-c

I am passing a parameter to a function, and I need to hold its reference in a block. The block will be executed at a later time. If I dont hold this reference, I get invalid memory access crash when the function executes.
- (void)doSomethingWithParamter:(Foo *)foo
{
[Bar setCompletionHandler:^{
// access foo here.
}];
}
I tried using the strong reference to foo as __typeof(Foo) *strongFoo = weakFoo; where weakFoo is __weak __typeof(Foo) *weakFoo = foo;
Am I missing something?

You don't need any of that stuff you are doing. Just access as is, e.g.
- (void)doSomethingWithParamter:(Foo *)foo
{
[Bar setCompletionHandler: ^ {
[foo doSomething];
}];
}
That way the block will keep a strong reference to foo anyhow, you need not and should not do it.
I suspect, if you get memory trouble, it is something else, maybe the trouble is with Bar?

Related

Objective-C Passing address of non-local object to __autoreleasing parameter

How can I change this line of code [NgnAVSession releaseSession: &audioSession]; so that I will no longer get this error:
Passing address of non-local object to __autoreleasing parameter for
write-back
this is the whole method
- (void)viewWillDisappear:(BOOL)animated
{
[NgnAVSession releaseSession: &audioSession];
[UIDevice currentDevice].proximityMonitoringEnabled = NO;
}
Here is the declaration of releaseSession
Header
+(void) releaseSession: (NgnAVSession**) session;
Implementation
+(void) releaseSession: (NgnAVSession**) session{
#synchronized (kSessions){
if (session && *session){
if([(*session) retainCount] == 1){
[kSessions removeObjectForKey:[*session getIdAsNumber]];
}
else {
[(*session) release];
}
*session = nil;
}
}
}
You are using a very old library. Try getting a newer version.
Then read up how Cocoa use NSError*. You really need to do this, because otherwise you cannot possibly understand what's going on.
Long story short: The compiler assumes that you pass the address of an autoreleasing variable. If needed it can turn a local variable into an autoreleasing one. That cannot be done with a non-local variable.
What these guys are doing is just wrong, wrong, wrong, wrong, wrong. If they want to keep track of all sessions without counting references, the easiest way is to create a wrapper object holding a weak reference, putting the wrapper objects into the array, and in the dealloc method you can remove the object from the array.
I'd suggest that you throw away their releaseSession and do exactly what I said before.

Does block parameters need to specify ownership qualifiers when providing weak references?

I'm trying to use blocks in a way where I provide a reference to the object which retains the block, as follows:
typedef void(^RunBlock)(__weak Thing *block_owner, ThingFinishBlock finish);
where Thing has a property run_block, of the type RunBlock.
Thing *thing = [Thing thingWithBlock^(Thing *owner, ThingFinishBlock finish) { ... }];
Calling the run_block from within the Thing goes something like this:
__weak typeof(self) this = self;
_finish_block = ^(){ ... }
self.run_block(this, _finish_block);
So what I'm wondering now is, is it safe to define the run_block's first parameter Thing *owner without prefixing it with __weak, or will this cause a retain loop? I'm unsure, as the pointer is already defined as __weak in the typedef, and the given parameter is already __weak.
^(__weak Thing *owner ...){ ... }
As opposed to
^(Thing *owner, ...) { ... }
Thanks!
No, __weak in parameters is not part of the function type itself.
typedef void(^RunBlock)(__weak Thing *block_owner, ThingFinishBlock finish);
is the same as
typedef void(^RunBlock)(Thing *block_owner, ThingFinishBlock finish);
It's where you implement the block that the __weak in the parameter matters.
Also, I have no idea why you think this has anything to do with retain cycles.

capturing self strongly in this block is likely to lead to a retain cycle

How can I avoid this warning in xcode. Here is the code snippet:
[player(AVPlayer object) addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(0.1, 100)
queue:nil usingBlock:^(CMTime time) {
current+=1;
if(current==60)
{
min+=(current/60);
current = 0;
}
[timerDisp(UILabel) setText:[NSString stringWithFormat:#"%02d:%02d",min,current]];///warning occurs in this line
}];
The capture of self here is coming in with your implicit property access of self.timerDisp - you can't refer to self or properties on self from within a block that will be strongly retained by self.
You can get around this by creating a weak reference to self before accessing timerDisp inside your block:
__weak typeof(self) weakSelf = self;
[player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(0.1, 100)
queue:nil
usingBlock:^(CMTime time) {
current+=1;
if(current==60)
{
min+=(current/60);
current = 0;
}
[weakSelf.timerDisp setText:[NSString stringWithFormat:#"%02d:%02d",min,current]];
}];
__weak MyClass *self_ = self; // that's enough
self.loadingDidFinishHandler = ^(NSArray *receivedItems, NSError *error){
if (!error) {
[self_ showAlertWithError:error];
} else {
self_.items = [NSArray arrayWithArray:receivedItems];
[self_.tableView reloadData];
}
};
And one very important thing to remember:
do not use instance variables directly in block, use it as a properties of weak object, sample:
self.loadingDidFinishHandler = ^(NSArray *receivedItems, NSError *error){
if (!error) {
[self_ showAlertWithError:error];
} else {
self_.items = [NSArray arrayWithArray:receivedItems];
[_tableView reloadData]; // BAD! IT ALSO WILL BRING YOU TO RETAIN LOOP
}
};
and don't forget to do:
- (void)dealloc {
self.loadingCompletionHandler = NULL;
}
another issue can appear if you will pass weak copy of not retained by anybody object:
MyViewController *vcToGo = [[MyViewCOntroller alloc] init];
__weak MyViewController *vcToGo_ = vcToGo;
self.loadingCompletion = ^{
[vcToGo_ doSomePrecessing];
};
if vcToGo will be deallocated and then this block fired I believe you will get crash with unrecognized selector to a trash which is contains vcToGo_ variable now. Try to control it.
Better version
__strong typeof(self) strongSelf = weakSelf;
Create a strong reference to that weak version as the first line in your block. If self still exists when the block starts to execute and hasn’t fallen back to nil, this line ensures it persists throughout the block’s execution lifetime.
So the whole thing would be like this:
// Establish the weak self reference
__weak typeof(self) weakSelf = self;
[player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(0.1, 100)
queue:nil
usingBlock:^(CMTime time) {
// Establish the strong self reference
__strong typeof(self) strongSelf = weakSelf;
if (strongSelf) {
[strongSelf.timerDisp setText:[NSString stringWithFormat:#"%02d:%02d",min,current]];
} else {
// self doesn't exist
}
}];
I have read this article many times. This is an excellent article by Erica Sadun on
How To Avoid Issues When Using Blocks And NSNotificationCenter
Swift update:
For example, in swift a simple method with success block would be:
func doSomeThingWithSuccessBlock(success: () -> ()) {
success()
}
When we call this method and need to use self in the success block. We'll be using the [weak self] and guard let features.
doSomeThingWithSuccessBlock { [weak self] () -> () in
guard let strongSelf = self else { return }
strongSelf.gridCollectionView.reloadData()
}
This so-called strong-weak dance is used by popular open source project Alamofire.
For more info check out swift-style-guide
In another answer, Tim said:
you can't refer to self or properties on self from within a block that will be strongly retained by self.
This isn’t quite true. It’s OK for you to do this so long as you break the cycle at some point. For example, let’s say you have a timer that fires that has a block that retains self and you also keep a strong reference to the timer in self. This is perfectly fine if you always know that you will destroy the timer at some point and break the cycle.
In my case just now, I had this warning for code that did:
[x setY:^{ [x doSomething]; }];
Now I happen to know that clang will only produce this warning if it detects the method starts with “set” (and one other special case that I won’t mention here). For me, I know there is no danger of there being a retain loop, so I changed the method name to “useY:” Of course, that might not be appropriate in all cases and usually you will want to use a weak reference, but I thought it worth noting my solution in case it helps others.
Many times, this is not actually a retain cycle.
If you know that it's not, you need not bring fruitless weakSelves into the world.
Apple even forces these warnings upon us with the API to their UIPageViewController, which includes a set method (which triggers these warnings–as mentioned elsewhere–thinking you are setting a value to an ivar that is a block) and a completion handler block (in which you'll undoubtedly refer to yourself).
Here's some compiler directives to remove the warning from that one line of code:
#pragma GCC diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
[self.pageViewController setViewControllers:#[newViewController] direction:navigationDirection animated:YES completion:^(BOOL finished) {
// this warning is caused because "setViewControllers" starts with "set…", it's not a problem
[self doTheThingsIGottaDo:finished touchThePuppetHead:YES];
}];
#pragma GCC diagnostic pop
Adding two cents on improving precision and style. In most cases you will only use one or a couple of members of self in this block, most likely just to update a slider. Casting self is overkill. Instead, it's better to be explicit and cast only the objects that you truly need inside the block. For example, if it's an instance of UISlider*, say, _timeSlider, just do the following before the block declaration:
UISlider* __weak slider = _timeSlider;
Then just use slider inside the block. Technically this is more precise as it narrows down the potential retain cycle to only the object that you need, not all the objects inside self.
Full example:
UISlider* __weak slider = _timeSlider;
[_embeddedPlayer addPeriodicTimeObserverForInterval:CMTimeMake(1, 1)
queue:nil
usingBlock:^(CMTime time){
slider.value = time.value/time.timescale;
}
];
Additionally, most likely the object being cast to a weak pointer is already a weak pointer inside self as well minimizing or eliminating completely the likelihood of a retain cycle. In the example above, _timeSlider is actually a property stored as a weak reference, e.g:
#property (nonatomic, weak) IBOutlet UISlider* timeSlider;
In terms of coding style, as with C and C++, variable declarations are better read from right to left. Declaring SomeType* __weak variable in this order reads more naturally from right to left as: variable is a weak pointer to SomeType.
I ran into this warning recently and wanted to understand it a bit better. After a bit of trial and error, I discovered that it originates from having a method start with either "add" or "save". Objective C treats method names starting with "new", "alloc", etc as returning a retained object but doesn't mention (that I can find) anything about "add" or "save". However, if I use a method name in this way:
[self addItemWithCompletionBlock:^(NSError *error) {
[self done]; }];
I will see the warning at the [self done] line. However, this will not:
[self itemWithCompletionBlock:^(NSError *error) {
[self done]; }];
I will go ahead and use the "__weak __typeof(self) weakSelf = self" way to reference my object but really don't like having to do so since it will confuse a future me and/or other dev. Of course, I could also not use "add" (or "save") but that's worse since it takes away the meaning of the method.

Objective-C block "retain cycle" warning, don't understand why

I've seen several other questions of the same form, but I either a) can't understand the provided answers, or b) don't see how those situations are similar to mine.
I'm writing a Category on UIView to recursively evaluate all the subviews of a UIView and return an Array of subviews passing a test. I've noted where my compiler warning occurs:
-(NSArray*)subviewsPassingTest:(BOOL(^)(UIView *view, BOOL *stop))test {
__block BOOL *stop = NO;
NSArray*(^__block evaluateAndRecurse)(UIView*);
evaluateAndRecurse = ^NSArray*(UIView *view) {
NSMutableArray *myPassedChildren = [[NSMutableArray alloc] init];
for (UIView *subview in [view subviews]) {
BOOL passes = test(subview, stop);
if (passes) [myPassedChildren addObject:subview];
if (stop) return myPassedChildren;
[myPassedChildren addObjectsFromArray:evaluateAndRecurse(subview)];
// ^^^^ Compiler warning here ^^^^^
// "Capturing 'evaluateAndRecurse' strongly in this block
// is likely to lead to a retrain cycle"
}
return myPassedChildren;
};
return evaluateAndRecurse(self);
}
Also, I get a bad_access failure when I don't include the __block modifier in my block's declaration (^__block evaluateAndRecurse). If someone could explain why that is, that would be very helpful too. Thanks!
The problem here is that your block evaluteAndRecurse() captures itself, which means that, if it's ever to be copied (I don't believe it will in your case, but in slightly less-trivial cases it may), then it will retain itself and therefore live forever, as there is nothing to break the retain cycle.
Edit: Ramy Al Zuhouri made a good point, using __unsafe_unretained on the only reference to the block is dangerous. As long as the block remains on the stack, this will work, but if the block needs to be copied (e.g. it needs to escape to a parent scope), then the __unsafe_unretained will cause it to be deallocated. The following paragraph has been updated with the recommended approach:
What you probably want to do here is use a separate variable marked with __unsafe_unretained that also contains the block, and capture that separate variable. This will prevent it from retaining itself. You could use __weak, but since you know that the block must be alive if it's being called, there's no need to bother with the (very slight) overhead of a weak reference. This will make your code look like
NSArray*(^__block __unsafe_unretained capturedEvaluteAndRecurse)(UIView*);
NSArray*(^evaluateAndRecurse)(UIView*) = ^NSArray*(UIView *view) {
...
[myPassedChildren addObjectsFromArray:capturedEvaluateAndRecurse(subview)];
};
capturedEvaluateAndRecurse = evaluteAndRecurse;
Alternatively, you could capture a pointer to the block, which will have the same effect but allow you to grab the pointer before the block instantiation instead of after. This is a personal preference. It also allows you to omit the __block:
NSArray*(^evaluateAndRecurse)(UIView*);
NSArray*(^*evaluteAndRecursePtr)(UIView*) = &evaluateAndRecurse;
evaluateAndRecurse = ^NSArray*(UIView*) {
...
[myPassedChildren addObjectsFromArray:(*evaluateAndRecursePtr)(subview)];
};
As for needing the __block, that's a separate issue. If you don't have __block, then the block instance will actually capture the previous value of the variable. Remember, when a block is created, any captured variables that aren't marked with __block are actually stored as a const copy of their state at the point where the block is instantiated. And since the block is created before it's assigned to the variable, that means it's capturing the state of the capturedEvaluteAndRecurse variable before the assignment, which is going to be nil (under ARC; otherwise, it would be garbage memory).
In essence, you can think of a given block instance as actually being an instance of a hidden class that has an ivar for each captured variable. So with your code, the compiler would basically treat it as something like:
// Note: this isn't an accurate portrayal of what actually happens
PrivateBlockSubclass *block = ^NSArray*(UIView *view){ ... };
block->stop = stop;
block->evaluteAndRecurse = evaluateAndRecurse;
evaluteAndRecurse = block;
Hopefully this makes it clear why it captures the previous value of evaluateAndRecurse instead of the current value.
I've done something similar, but in a different way to cut down on time allocating new arrays, and haven't had any problems. You could try adapting your method to look something like this:
- (void)addSubviewsOfKindOfClass:(id)classObject toArray:(NSMutableArray *)array {
if ([self isKindOfClass:classObject]) {
[array addObject:self];
}
NSArray *subviews = [self subviews];
for (NSView *view in subviews) {
[view addSubviewsOfKindOfClass:classObject toArray:array];
}
}

ARC __block behavior equivalent in MRC?

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.