Weak and strong self usage, blocks memory management - ios

There are a bunch of questions about all these weak and strong selves but I want that you guys took a look at my particular example:
- (void)getItemsWithCompletionHandler:(void (^)(NSArray*items))completionHandler {
__weak __typeof__(self) weakSelf = self;
[self doWorkWithCompletionHandler:^(Response *response) {
// this completion is not on main thread
dispatch_async(dispatch_get_main_queue(), ^{
...
[weakSelf doAnotherWorkWithCompletionHandler:^(Response *response) {
// this completions is not on main thread either
dispatch_async(dispatch_get_main_queue(), ^{
__typeof__(self) strongSelf = weakSelf;
NSArray *itemsIds = [strongSelf doWorkOnMainThread1];
NSArray *items = [strongSelf doWorkOnMainThread2];
completionHandler(items);
});
}];
});
}];
}
Is everything correct here or not? Also you are welcome to suggest a refactoring

If you turn all warnings on, then you will get a warning for
[weakSelf doAnotherWorkWithCompletionHandler... ];
You shouldn't send messages to weak objects. A weak object could disappear while the method that is called is running. Store the weak object into a strong one, the result is either nil or not. If you then call
[strongSelf doAnotherWorkWithCompletionHandler... ];
you know that either strongSelf == nil and nothing happens, or strongSelf is and stays not nil while the method is executing.

You should check if completionHandler is not NULL and then call it.
if (completionHandler) {
completionHandler(items);
}
Otherwise you'll crash if completionHandler is NULL
You may also reconsider if you want to call completionHandler(items) at all if self == nil at any point. I say that, because there is a slight inconsistency.
In line
[weakSelf doAnotherWorkWithCompletionHandler:^(Response *response) {
if weakSelf is nil already, then it's completionHandler will not be called and in result completionHandler(items) will also not be called.
But in here:
__typeof__(self) strongSelf = weakSelf;
NSArray *itemsIds = [strongSelf doWorkOnMainThread1];
NSArray *items = [strongSelf doWorkOnMainThread2];
completionHandler(items);
if self == nil then completionHandler will in fact be called.
Of course I don't see the whole picture and maybe it's completely irrelevant, but something you might want to take under consideration.
Going further, I assume you'd rather have completionHandler called in each and every scenario, even if self == nil at any point. Or add an error parameter to it in case of anything going wrong.
And if you want to be super pedantic, you might want to put __weak after the type, as such:
__typeof__(self) __weak weakSelf = self;
It's the preferred way: https://developer.apple.com/library/ios/releasenotes/objectivec/rn-transitioningtoarc/Introduction/Introduction.html#//apple_ref/doc/uid/TP40011226-CH1-SW4 (look for "You should decorate variables correctly.")

Related

Retain Cycles for Blocks Inside of Blocks

Do I have to continuously declare weak references to break retain cycles for blocks inside of blocks?
__weak typeof(self) weakSelf = self;
[self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {
typeof(self) strongSelf = weakSelf;
[strongSelf doSomething];
[strongSelf setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {
//do I need to create another weak reference to strongSelf for this block?
[strongSelf doSomething];
}];
}];
I'm afraid so. [strongSelf setMyBlock:<inner block>] will cause self to retain the inner block. If the inner block has a strong reference to self, that's a cycle. The fact that the strongSelf variable was assigned from a __weak qualified variable originally does not make a difference.
As some other users mentioned, you can use the original weakSelf rather than creating a new one. The reason you create a strongSelf reference in the block is that otherwise self might be deallocated while the block is running. strongSelf will either end up nil (if self was deallocated before strongSelf was assigned, but this causes no harm) or else self will not be deallocated while the block is executing, because you have a strong reference. During the time that you have a strong reference to self, the original weakSelf is also safe to use, because self will not be deallocated.

Is it correct to use local variable name "self" in blocks?

I`ve found that construction __strong typeof(self)self = weakSelf.
It allows remove NSAssert macro self catching, but I am in doubt is it right to use it in that way?
__weak typeof(self)weakSelf = self;
self.signupBlock = ^{
__strong typeof(self)self = weakSelf;
NSLog (#"%d", self.property)
NSAssert((self.property > 5), #"Some message");
}
Pls advice.
Sorry, I had to say first that using of
__strong typeof(self)strongSelf = weakSelf;
construction results to warnings and I suppose to mem cycle, when NSAssert macro used, because it contains self in.
self is just an variable name, so it's perfectly fine to redefine it locally. It might be even preferred to
__strong typeof(weakSelf) strongSelf = weakSelf;
because
it makes for easily readable code
it prevents you for mistakenly referencing "real" self and potentially creating retain cycles.
Additionally, you might want to look at answers to this question for discussion when to use weak / strong self in blocks, and libextobjc library for neat #weakify / #strongify macros.
Change the code to, so that it´s clear that you are referring only to strongSelf in the block:
__weak typeof(self) weakSelf = self;
self.signupBlock = ^{
typeof(weakSelf) strongSelf = weakSelf;
if strongSelf {
NSLog (#"%d", strongSelf.property)
NSAssert((strongSelf.property > 5), #"Some message");
}
}
Your code sets up a weak connection to self __weak typeof(self) weakSelf = self;. Then when it needs to call self later, it sets up a strong connection to self typeof(weakSelf) strongSelf = weakSelf; and checks if self is still around (has not been released) if strongSelf {. If so the strong connection will keep it alive while the rest of the code is run, which might in many instances involve another block to call on the main thread (i.e. hence the strong connection).
NSAssert is only supposed to be used in Objective-C methods, and as such it uses self and _cmd. A block is not an Objective-C method, and so you should not use NSAssert in it. You should probably use NSCAssert instead.
Yeah using self as variable name in ObjC is fine.
I made a fancy macro for such cases where you need to break a retain cycle caused by a stored block:
#define StrongSelf __strong __typeof__((__typeof__(self))self)
#define WeakSelf __weak __typeof__((__typeof__(self))self)
#define RecoverSelf for (BOOL _continue_loop = YES; _continue_loop; _continue_loop = NO) \
for (StrongSelf this = self; this != nil && _continue_loop; _continue_loop = NO) \
for (StrongSelf self = this; _continue_loop; _continue_loop = NO)
#define WeakenSelf for (BOOL _continue_loop = YES; _continue_loop; _continue_loop = NO) \
for (WeakSelf this = self; _continue_loop; _continue_loop = NO) \
for (WeakSelf self = this; _continue_loop; _continue_loop = NO)
which you can use like that:
WeakenSelf {
_signupBlock = ^{
RecoverSelf {
NSLog (#"%d", self.property)
NSAssert((self.property > 5), #"Some message");
}
}
}

Confusion over how I should use weakSelf in blocks

I have a lot of blocks in my code. I have a process for initialising a user upon login, I am using Parse.com as my backend:
PFQuery *messageBankQuery = [PFQuery queryWithClassName:#"messageBank"];
[messageBankQuery whereKey:#"username" equalTo:[PFUser currentUser].username];
[messageBankQuery getFirstObjectInBackgroundWithBlock:^(PFObject *object, NSError *error) {
if(!error){
[self setupUserWithMessageBank:object];
}//end no error if
else{
NSLog:(#"error");
}
}];
The messageBank is a parse object that holds references to all the messages the user has. If that object is found setupUserWithMessageBank is called in the block. setupUserWithMessageBank also does more block work:
-(void)setupUserWithMessageBank: (PFObject *)object{
__weak FriendsViewController *weakSelf = self;
//2.)Init the user
weakSelf.currentUser = [[appUser alloc] initWithParseUser:[PFUser currentUser] andMessageBank:object];
//3.) Setup that message array
[weakSelf.currentUser setupMessagedTodayWithHandler:^(BOOL successful) {
if(successful){
//4.)Add friends to the array
[weakSelf.currentUser populateFriendsArrayWithCompletionHandler:^(BOOL successful, NSError *error, BOOL addSelf, BOOL alreadyFriends) {
if(successful){
[self.indicator stopAnimating];
[self.indicator removeFromSuperview];
[self.tableView reloadData];
__weak FriendsViewController *weakSelf = self;
[weakSelf.currentUser refreshMessagesArrayWithCompletionHandler:^(BOOL successful, BOOL newMessages) {
if(successful) {
//set the button
[self.navigationItem.rightBarButtonItem setAction:#selector(showMessages)];
}
else{
[weakSelf displayGeneralError];
}
}];//end fill messages
}
else{
[weakSelf displayGeneralError];
}
}];//end populate method call
}
else{
[weakSelf displayGeneralError];
}
}];
}
I am a little confused over the use of weakSelf. Is it okay to declare weakSelf inside the start of the setupUserWithMessageBank method? Because his method is called inside another block so technically it's being created inside a block. Do I need to pass weakSelf inside the method instead?
I'm also not completely sure where I should be using weakSelf. Do I need to use it to turn off activity indicators ? Any pointers about my usage of this would be really appreciated. Thanks!
you will probably only need to use a weakSelf if you actually keep a reference to the block within self (or maybe transitively, a block being kept in an object that is kept within self), which in this case, doesnt look like you are doing. the only reason really to use a weakSelf within a block is to avoid retain cycles.
if both blocks have short life cycles then its probably safe to just use self within the block. (if you have any control over the life cycle of the blocks, make sure they are set to nil after executing or cleaned up if they dont get executed because of some failure so they dont hang around)

weak variable with a strong reference in a block: does not create a retain cycle?

why does it work when we pass the weak reference to a strong reference inside the block? If a local variable in a block is retained, this should add a retain to self and thus create this bad retain cycle?
Here is the example :
__weak id weakSelf = self;
[self.operationQueue addOperationWithBlock:^{
NSNumber* result = findLargestMersennePrime();
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
MyClass* strongSelf = weakSelf;
strongSelf.textLabel.text = [result stringValue];
}];
}];
When you create or copy a block (it could be copied when you, for example, schedule it to gcd), referenced variables are captured (unless declared with __block specifier). Strong references are retained, weak references are not.
When you create local strongSelf variable it keeps self alive while block executes (i.e. while it's not executed and sits in a property there's no strong reference). When you reference self directly - self is captured and retained, now it keeps self while block is alive.
__weak id weakSelf = self;
[self.operationQueue addOperationWithBlock:^{
NSNumber* result = findLargestMersennePrime();
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
MyClass* strongSelf = weakSelf; // strong reference when block executes
[self foo]; // strong reference when block created/copied
strongSelf.textLabel.text = [result stringValue];
}];
}];
See the difference? If you kill all strong pointers to object with direct self reference there is still one strong reference inside the block, the one which was captured and retained. At the same time local strongSelf pointer only holds strong reference to self while block is executed, so, if self was already dead, weakSelf would be nil and strongSelf will get nil value.
no it doesn't create a cycle since self isn't captured as strong! :)
strongSelf is a strong reference that retains self BUT since strongSelf is a local var, it is released when the block is done and the retain count drops fine

Retain cycle with an operation queue

While reading a blog about concurrency in iOS, I stumbled upon the next code:
__weak id weakSelf = self;
[self.operationQueue addOperationWithBlock:^{
NSNumber* result = findLargestMersennePrime();
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
MyClass* strongSelf = weakSelf;
strongSelf.textLabel.text = [result stringValue];
}];
}];
The author explains that the use of weakref is needed since:
we need to make a weak reference to self, otherwise we create a retain
cycle (the block retains self, the private operation queue retains the
block, and self retains the operation queue). Within the block we
convert it back to a strong reference to make sure it doesn’t get
deallocated while running the block.
I can understand why the block would have retained self, but I don't understand why (and where exactly) the private operation queue retains the block and when/where self retaind the opeation queue. Any explanation would be much appreciated.
try to write this code without weak reference:
[self.operationQueue addOperationWithBlock:^{
NSNumber* result = findLargestMersennePrime();
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.textLabel.text = [result stringValue];
}];
}];
to make this code work - compiler retains reference to self in operationQueue to avoid situation when self is deleted from memory and self.textLabel.text = .. is executed, so it tries to guarantee that object will be alive.
This is where cycle is actually created:
self retains operationQueue (this means that operationQueue cannot be deleted while self is alive)
operationQueue retains self (this means that self cannot be deleted while operationQueue is alive)
to avoid this - you're creating week reference, so you're eliminating 2nd retention
PS. "block" is part of operationQueue, so we can assume just 2 items in this scheme.

Resources