In apples example
MyViewController *myController = [[MyViewController alloc] init…];
MyViewController * __weak weakMyController = myController;
myController.completionHandler = ^(NSInteger result) {
MyViewController *strongMyController = weakMyController;
if (strongMyController) {
[strongMyController dismissViewControllerAnimated:YES completion:nil];
}
else {
// Probably nothing...
}
};
What is happening here? I'm confused about:
MyViewController *strongMyController = weakMyController;
Does that mean weakMyController has a strong reference to it, so it would be like weakMyController's retain count + 1? What happens when you create a strong reference to a weak iVar?
Does that mean weakMyController has a strong reference to it, so it
would be like weakMyController's retain count + 1?
The retain count for myController is the same for all the variables that have its reference. It's a value of the object, not of the variables pointing to it. And it tells the runtime ho many strong references there exist pointing to the object.
So, the line
MyViewController *strongMyController = weakMyController;
will increment that count by 1, and ensure that as long as we have that variable in scope, that view controller won't be released.
In most cases it's enough to call methods on the weak reference inside the block (weakMyController in your example). I think that in this case they use a strong reference because there's an animation involved (so the view controller needs to exist for the duration of the animation, which would not be guaranteed if we used a weak reference).
To respond to the other part of your question, all the strong and weak references to an object hold the same value (the memory address of the object). The difference between strong and weak is what happens when they get their values. In the case of a weak reference, the retain count stays the same, while with a strong reference it gets incremented.
Related
vc2.h
#interface vc2 : UIViewController
#property (nonatomic, strong) NSDictionary *dict;
#end
vc2.m
- (instancetype)init
{
self = [super init];
if (self) {
self.dict = #{#"self":self};
}
return self;
}
Root VC
- (void)viewDidLoad {
[super viewDidLoad];
vc = [[vc2 alloc]init];
}
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:YES];
vc = nil;
}
vc2 strong NSDictionary property holds self and I am setting vc2 to nil in root VC but when I check this in instruments vc2 instance still exists.
When I set weak NSDictionary property vc2 instance gets released after setting it to nil, but Xcode gives me this warning Assigning dictionary literal to a weak property; object will be released after assignment
What is going on regarding this memory management?
Well, if the reference to dictionary is strong, vc2 creates a retain cycle - it references itself through the dictionary. So dropping the reference to it from root won't help, there will still be at least one reference existing - the one from dictionary.
It's simple - if there is a reference to an object, it has to be retained, you cannot release it. Since vc2 holds a reference to the dictionary, the dictionary cannot be released while vc2 exists. However, the dictionary itself holds a reference to vc2, therefore vc2 cannot be released until the dictionary exists. This is the retain cycle - vc2 keeps the dictionary alive, and the dictionary keeps the vc2 alive.
You can break this cycle by using weak reference type - weak means that this reference will not be used to determine if the object has to be retained. From the viewpoint of retaining/releasing the weak references don't count. So when you make the dictionary property weak, you are saying that the vc2 should not keep the dictionary alive. In other words, you are saying that if no other object has a reference to this dictionary, vc2 should not be a reason for retaining it and in such a case the dictionary can be released. BUT, since when you create the dictionary in vc2 the ONLY reference to it is the one in vc2, the weak one, there is no strong reference to it that would prevent releasing it. This results in following:
// here you create a dictionary and assign it to your weak dict property
self.dict = #{#"self":self};
// but right here, after executing it, the only reference to the created dictionary
// is the weak one - that means that the dictionary can be released!
// thus, if you try to print dict right on the next line, it will be nil
// because it was released right after creation
That's the problem with using weak reference to the dictionary. Every object is retained (exists) only when there is at least one strong reference to it. But in this case the poor dictionary will not get a single strong reference to it.
What you want here is a strong reference to a dictionary. That will make sure that the dictionary will exist while the vc2 exists. But you need to break the retain cycle somewhere. To identify what is supposed to be weak is pretty easy: just ask which object is supposed to be dependent on which:
Can the dictionary be released, while the vc2 exists?
No, it cannot, dictionary should be retained while the vc2 exists.
Can the vc2 be released, while the dictionary exists?
Yes it can! In fact, when vc2 is released, that's the point when dictionary can be released too.
This means that the dictionary is dependent on the vc2, not vice versa. So you want a strong reference from vc2 to dictionary - that will make sure that while vc2 exists, the dictionary exists. But you don't want the existence of the dictionary to keep the vc2 retained - when other objects release vc2, the dictionary must not hold the vc2 alive. Therefore you need a weak reference from the dictionary to the vc2, not a strong one. That should point you in the right direction - the self reference that you are adding to the dictionary is the one that should be weak.
Check for example this SO question for some advices on how to approach weak entries in a dictionary.
I have the following setter defined in my class that extends UICollectionView:
// #interface ClipsDataSource : NSObject <UICollectionViewDataSource>
- (void)setProject:(Project *)project
{
_project = project;
ClipsDataSource *dataSource = [[ClipsDataSource alloc] initWithCollectionView:self];
dataSource.delegate = self;
dataSource.fetchedResultsController = project.clipsResultsController;
self.dataSource = dataSource;
}
When I run my application I get the following exception:
-[CALayerArray numberOfSectionsInCollectionView:]: unrecognized selector sent to instance 0x174245490
I realised that the instance pointer is the address of the local variable I had used in my setter; the class name is obviously random. From this "discovery" I reasoned that the object was released after assignment.
Normally Xcode will warn me about these issues by saying:
Assigning retained object to unsafe property; object will be released after assignment.
And, sure enough, I see that warning if I change my code to this:
self.dataSource = [[ClipsDataSource alloc] initWithCollectionView:self];
I have two questions:
Why doesn't Xcode show a warning?
Why is .dataSource considered an unsafe property? It's defined as (nonatomic, assign).
1) Why doesn't Xcode show a warning?
Because clang is not intelligent enough to figure out that your datasource instance will not be retained elsewhere; only this obvious case will be reported:
self.dataSource = [[ClipsDataSource alloc] initWithCollectionView:self];
2) Why is .dataSource considered an unsafe property? It's defined as (nonatomic, assign).
This is done to prevent retain cycles with self referential constructs, which happens quite often in ViewController code.
Imagine that your CollectionViewController is the datasource of CollectionView,
self.collectionView.dataSource = self;
This means:
CollectionViewController retains .collectionView, because View Controllers retain their views by default.
CollectionView retains it's datasource (which is CollectionViewController).
This will cause a retain cycle and therefore Apple decided to use unsafe unretained pointer for .datasource.
Note that both assign and weak pointers will not retain the object that they are pointing. The difference between them is that weak will be automatically nullified when the referenced object is deallocated.
But assign pointer will NOT be nullified, so it will continue pointing to address of memory. Further dereference of that pointer (after deallocation) will probably cause EXC_BAD_ACCESS, or you will get another object (as another object can be written in that address after deallocation).
I am new to blocks in iOS and had a quick question regarding their use. Say I have the following setup:
viewController.rowLabels = #[#"Hello", #"World"];
viewController.testBlock = ^(NSInteger itemIndex) {
// here i want to access another property of the viewController called foo
};
So, as seen above, I want to access another property of the view controller within the block itself. Do i need to do a *__weak -> strong assignment to achieve this or can i simply access it like NSLog(viewController.foo)?
The simple, but possibly problematic answer, is just to access it as you do the other properties:
viewController.rowLabels = #[#"Hello", #"World"];
viewController.testBlock = ^(NSInteger itemIndex) {
... viewController.foo ...
};
From your fragment we cannot know what viewController is - e.g. it could be a local variable from the method this fragment is in or a global variable etc. If you are just reading the value in viewController, as you are here, this does not matter[1].
The above works but there might be a problem: you probably have a strong reference cycle. The viewController instance references the block through it's testBlock property, and the block references the viewController instance. If both these references are strong (likely) then you have a circular dependency and the viewController instance and the block can never be freed by the system. You can break this cycle using a weak reference:
viewController.rowLabels = #[#"Hello", #"World"];
__weak ViewController *weakViewController = viewController; // make a weak reference to the instance
viewController.testBlock = ^(NSInteger itemIndex)
{
// temporarily make a strong reference - will last just as long as the block
// is executing once the block finishes executing the strong reference is
// removed and no strong reference cycle is left.
ViewController *myController = weakViewController;
// only execute if the `ViewController still exists
if (myController != nil)
{
... myController.foo ...
}
};
HTH
[1] note that the value you are reading is a reference to a ViewController instance and you can modify properties of that instance, what you cannot do (and are not trying to do) is modify which instance the viewController references if viewController is a local variable.
Declare a __block variable containing the view controller object, like so:
__block __weak ViewController *blockVC = viewController;
viewController.testBlock = ^(NSInteger itemIndex) {
NSLog(#"%#", blockVC.foo);
};
I've used both __block and __weak since __block is implicitly strong, but adding __weak as a reference can help break the strong reference cycle while still using __block's strong reference to prevent deallocation.
As of iOS 5.0, it seems as if you can just create a __weak reference as opposed to using a __block variable to access a variable and its properties within a block:
__weak ViewController * weakVC = viewController;
viewController.testBlock = ^(NSInteger itemIndex) {
ViewController * strongVC = weakVC;
if (strongVC) {
NSLog(#"%#", strongVC.foo);
}
};
But note that unlike using __weak in combination with the __block storage type, __weak specifies a reference that might not keep the object alive, i.e. may deallocate, so even within the block, weakVC may be nil before you actually need it. (This is why the if (strongVC) conditional is required when just using a __weak variable alone.)
I want to use weak self in blocks, but in block this weakSelf become nil
Just created, before block (try to use different variants) - looks like all ok
But later in block - each variant nil
Whats done wrong? Can anyone explain?
EDIT
SPHVideoPlayer *videoPlayer = [[SPHVideoPlayer alloc] initVideoPlayerWithURL:urlToFile];
[videoPlayer prepareToPlay];
Initialization
#pragma mark - LifeCycle
- (instancetype)initVideoPlayerWithURL:(NSURL *)urlAsset
{
if (self = [super init]) {
[self initialSetupWithURL:urlAsset];
}
return self;
}
- (void)initialSetupWithURL:(NSURL *)url
{
NSDictionary *assetOptions = #{ AVURLAssetPreferPreciseDurationAndTimingKey : #YES };
self.urlAsset = [AVURLAsset URLAssetWithURL:url options:assetOptions];
}
And also method that use block
- (void)prepareToPlay
{
__weak typeof(self) weakSelf = self;
__weak SPHVideoPlayer *weakSealf2 = self;
NSArray *keys = #[#"tracks"];
[self.urlAsset loadValuesAsynchronouslyForKeys:keys completionHandler:^{
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf startLoading];
});
}];
}
As rckoenes suggested, this SPHVideoPlayer is falling out of scope and is getting released. Assuming you don't want it to be released, you just have to choose a scope that keeps it around (e.g. making it a property of the view controller that is showing the video).
You describe your use of weakSelf to prevent a "retain cycle" (now often called a "strong reference cycle"). Yes, the weakSelf pattern is used to prevent strong reference cycles. Technically, it's not entirely clear that you necessarily had a strong reference cycle at all. It depends upon the details of the loadValuesAsynchronousForKey... implementation (e.g. is this block loaded into some class property, thus creating strong reference cycle from the class, to a block class property references of self, which in turn maintains a strong reference back to self).
But that's all a bit academic: The weakSelf pattern is prudent nonetheless, because it accurately reflects the appropriate object graph (the block has no business "owning" and/or maintaining a strong reference to the video player). Coincidentally, though, when you use weakSelf, it also eliminates the potential risk of strong reference cycle.
The real issue is that you presumably want to keep the video player in scope not just while the assets are loaded, but while the video plays, too, so you'd want to change the scope of the video player regardless (presumably to match the view controller that is presenting the video player.
That's the idea of weak variables: Weak variables do not hold a reference count, so if a weak variable is the only thing left that holds on to an object, the object will be deallocated and the weak variable will be nil. That's 100% the way how weak variables are supposed to work and supposed to be used.
If you had used a strong reference, then your block would be the only bit of code still holding on to self, and all the work that you do with self would be pointless because nobody else will ever take notice of it. Since you are using a weak variable, you can avoid this by checking whether the variable is nil.
In a multithreaded environment, the last strong reference could go away at any time and your weak reference might become nil at any time. You avoid this by copying the weak variable into a strong one as the very first thing in your block, so you know the weak variable might have disappeared before you entered the block, but it won't disappear while your block is executing.
The reason to have a weak reference for blocks is to not retain the class with the block.
Weak references get nil when the instance does not exist anymore, so you need to take care of handling the weak reference accordingly (which you do in your code).
If that is not what you want to achieve, you need to make sure your instance is not deallocated, but that is not related to your block ...
I have a class that creates an object lazily and stores it as a weak property. Other classes may request this object, but must obviously keep a strong reference to it to keep the object from being deallocated:
// .h
#interface ObjectManager
#property(nonatomic, weak, readonly) NSObject *theObject;
#end
// .m
#interface ObjectManager ()
#property(nonatomic, weak, readwrite) NSObject *theObject;
#end
#implementation ObjectManager
- (NSObject *)theObject
{
if (!_theObject) {
_theObject = [[NSObject alloc] init];
// Perform further setup of _theObject...
}
return _theObject;
}
#end
When the scheme is Xcode is set to build for Debug, things work just fine - an object can call objectManagerInstance.theObject and get back theObject.
When the scheme is set to build for Release, theObject returns nil:
// Build for Debug:
NSObject *object = objectManagerInstance.theObject;
// object is now pointing to theObject.
// Build for Release:
NSObject *object = objectManagerInstance.theObject;
// object is now `nil`.
My guess is that the compiler is optimising my code by seeing that _theObject is not used further in the accessor method itself, so the weak variable is being set to nil before returning. It seems that I would have to create a strong reference before actually returning the variable, which I can only think to do using a block, but would be messy and I'd rather avoid it!
Is there some kind of keyword I can use with the return type to stop the ivar from being nilled so soon?
Most likely, DEBUG builds cause the object to sit in the autorelease pool long enough to cause it to "work" whereas a RELEASE build causes the optimizer to do a bit more control flow analysis which subsequently eliminates the autorelease chatter.
Frankly, that the compiler isn't spewing a warning in the release build saying that the code can never work is a bug (please file it as you have a great, concise, example)!
You'll need to maintain a strong reference somewhere to the object until whatever needs a strong reference has an opportunity to take a reference.
I'm wondering if something like this might work:
- (NSObject *)theObject
{
NSObject *strongObject;
if (!_theObject) {
strongObject = [[NSObject alloc] init];
_theObject = strongObject;
// Perform further setup of _theObject...
} else {
strongObject = _theObject;
}
return strongObject;
}
I.e. the above would be more akin to a factory method that returns an autoreleased object while also maintaining a weak reference internally. But the optimizer might be too clever by half and break the above, too.
You're being bitten by the optimizer.
Since _theObject is a weak reference, the system is free to get rid of it, and zero out your weak reference, whenever it's not retained. But it's not required to do it right away.
In your lazy instantiator, the newly-created object is never retained. The optimizer sees this, and says "Wow! I can zero this reference at any time! Why don't I do it...right now!" And before you know it, you're returning nil.
What you want to do is assign the lazily-instantiated object to a local variable, for an implicitly strong reference that lasts for the scope of the function. You also want to tell the compiler that you really do want the full scope, using the objc_precise_lifetime annotation.
For details from the standard, see this page.