0

Can you modify self from an instance method called from a weak self pointer within a block?

-(void)someMethod:(AnotherClassName *)anObject {

    __weak MyClassName *weakSelf = self;

    [anObject requestSomethingWithCompletion:^{
        [weakSelf updateSomething];
    }];
}

-(void)updateSomething {
    self.something = @"update"; // Will this cause a memory leak?
}

So basically I am calling an instance method from the same class I am in, but I am doing it from a weak pointer and then changing self.

According to Apple's Programming with Objective-C Guide this is how to call a method on self within a block but it isn't clear weather I can directly modify self in that method.

If you know the answer based on something you've read before please include the source.

Thanks!

Korey Hinton
  • 2,532
  • 2
  • 25
  • 24
  • 1
    Nitpicking but important distinction: you are not "modifying" `self`, nor do you "change" `self` - where `self` is a _pointer to an object_ (and not the _object_ itself). Instead, you are sending methods to the _object_ where _self_ points to and possibly modifying the object. This distinction is important to understand the subtleties when object pointers are involved in Blocks ;) – CouchDeveloper Feb 26 '14 at 15:36
  • @CouchDeveloper Wouldn't calling the setter of a property, or more specifically sending the message `[self setSomething:@"update"]` be modifying the object self points to? – Korey Hinton Feb 26 '14 at 15:40
  • Ok, I think I understand now. The class itself can implement its own setter and that might or might not modify the underlying instance variable and make a change to self. – Korey Hinton Feb 26 '14 at 15:45
  • 1
    A setter property will (likely) modify the object - however, _self_ **itself** - which is a pointer to that object remains the same. In fact, if a block captures a strong pointer to any object (not just self), it cannot "modify" that pointer, e.g.: `obj = anotherObject;` within the block would issue a compiler error something like "Cannot modify variable 'obj'" – CouchDeveloper Feb 26 '14 at 15:46
  • Ok thanks, I was just thinking along the same lines. – Korey Hinton Feb 26 '14 at 15:47
  • OK, then you need to know what the `__block` modifier will do: if the block captures a variable with a `__block` modifier, the block actually captures a _reference_ to that variable. Within the block you can now modify that variable which actually exists *outside* the block. Sure you need to ensure that this "outside" variable is still existing when the block gets executed. – CouchDeveloper Feb 26 '14 at 15:51
  • Ok, so I would want to use that for local variables that are not properties and for properties I would use a weak self to modify them – Korey Hinton Feb 26 '14 at 15:54
  • 1
    Korey, the whole topic is more complex and a thorough explanation won't fit into comments. I've written an answer recently which may help, too: http://stackoverflow.com/questions/21987067/using-weak-self-in-dispatch-async-function/21988407#21988407 – CouchDeveloper Feb 26 '14 at 16:03
  • That's very thorough, thanks! – Korey Hinton Feb 26 '14 at 17:18

1 Answers1

4

You can modify properties and call methods. There will be no memory leaks.

But your block is not thread safe now. If requestSomethingWithCompletion will run block asynchronously your class (self) could be deallocated during block execution and weakSelf will become nil. This could cause problems (depends on what does your block do). Good practice to avoid this is to write it following way

-(void)someMethod:(AnotherClassName *)anObject {

    __weak MyClassName *weakSelf = self;

    [anObject requestSomethingWithCompletion:^{
        MyClassName *strongSelf = weakSelf;
        [strongSelf updateSomething];
    }
}

-(void)updateSomething {
    self.something = @"update"; // No leaks here!
}
Avt
  • 16,927
  • 4
  • 52
  • 72
  • 1
    Actually, the way a weak pointer is implemented, guarantees in the OP's case that you don't need to worry about whether _self_ has been deallocated. In that case, _dereferencing_ (means _using_ it) the weak pointer returns a `nil` value - and it is safe to send messages to `nil`. However, your suggested Idiom is actually the preferred one, since it actually avoids such subtle issues that when having multiple _dereferences_ of the weak pointer return first an object then subsequently `nil` - since it has been deleted in the meantime. Getting a strong pointer again safely retains that object. – CouchDeveloper Feb 26 '14 at 15:57
  • Your code is exactly the same as the OP's code. See http://clang.llvm.org/docs/AutomaticReferenceCounting.html#semantics "Reading occurs when performing a lvalue-to-rvalue conversion on an object lvalue. For __weak objects, the current pointee is retained and then released at the end of the current full-expression. This must execute atomically with respect to assignments and to the final release of the pointee." – newacct Feb 26 '14 at 22:55