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
}];
Better version
So the whole thing would be like this:
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:
When we call this method and need to use
self
in the success block. We'll be using the[weak self]
andguard let
features.This so-called strong-weak dance is used by popular open source project
Alamofire
.For more info check out swift-style-guide
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:
I will see the warning at the [self done] line. However, this will not:
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.
And one very important thing to remember: do not use instance variables directly in block, use it as a properties of weak object, sample:
and don't forget to do:
another issue can appear if you will pass weak copy of not retained by anybody object:
if
vcToGo
will be deallocated and then this block fired I believe you will get crash with unrecognized selector to a trash which is containsvcToGo_
variable now. Try to control it.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. Castingself
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 ofUISlider*
, say,_timeSlider
, just do the following before the block declaration: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 insideself
.Full example:
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: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
.The capture of
self
here is coming in with your implicit property access ofself.timerDisp
- you can't refer toself
or properties onself
from within a block that will be strongly retained byself
.You can get around this by creating a weak reference to
self
before accessingtimerDisp
inside your block:In another answer, Tim said:
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:
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.