0

I have been using blocks and familiar with the memory management when using self inside blocks in Non-ARC environment

But I have two specific questions:

1) I understand I can use __block to avoid the retain cycle a retained block which in turn using self can create, like below:

__block MyClass *blockSelf = self; 
self.myBlock = ^{  
     blockSelf.someProperty = abc;  
     [blockSelf someMethod]; 
};

This will avoid the retain cycle for sure but I by doing this I have created a scope for self to be released and eventually deallocated by someone else. So when this happen self is gone and blockSelf is pointing to a garbage value. There can be conditions when the block is executed after the self is deallocated, then the block will crash as it is trying to use deallocated instance. How do we can avoid this condition? How do I check if blockSelf is valid when block executes or stop block from executing when self is deallocated.

2) On the similar lines suppose I use block like below:

__block MyClass *blockSelf = self; 
self.myBlock = ^{  
         [blockSelf someMethod:blockSelf.someProperty]; 
    };

// I am taking someProperty in an method argument
-(void) someMethod:(datatype*)myClassProperty
{
  myClassProperty = abc;
}

Now there can be situations where self is not released but someProperty is released before someMethod's execution starts (This could happen when there are multiple threads). Even if I do self.someProperty = nil; when it is release, myClassProperty is not nil and pointing to some garbage, hence when someMethod is executed the first line will lead to crash. How do I avoid this?

4
  • 1) Shouldn't that be __weak, not __block? Commented Nov 3, 2014 at 11:09
  • have a look to dhoerl.wordpress.com/2013/04/23/… (you need to declare it __weak not __block) Commented Nov 3, 2014 at 11:11
  • 2
    I am in a non-arc environment, so can't use __weak. Commented Nov 3, 2014 at 11:20
  • Who calls myBlock if self is deallocated? Commented Nov 3, 2014 at 11:35

2 Answers 2

3
  1. This is the same issue as non-zeroing weak references everywhere else in non-ARC code, e.g. delegates etc. (MRC doesn't have zeroing weak references; so these are the only kind of weak reference in MRC. Yet people were still able to write safe code in the pre-ARC days.)

    Basically, the solution is that you need a clear map of ownership. Either self is responsible for keeping the block alive; or some other object is responsible for keeping the block alive.

    For example, with delegates, usually, a "parent" object is the delegate of a "child" object; in this case the "parent" object is responsible for keeping the "child" object alive, so the "parent" object will outlive the "child" object, thus the back reference can be weak and is safe (because the child object's methods could only possibly be called by the parent object while the parent object is alive).

    On the other hand, if you have an asynchronous operation, and the block is given to the operation as a callback, then usually the operation is responsible for holding onto the block. In this case, self would not hold onto the block. And the block would hold a strong reference to self, so that when the operation is done, it can still safely do whatever it is that it needs to do on self. In fact, whatever object self is, it doesn't even need to be retained by whoever uses it, since it is indirectly retained by the asynchronous operation -- it can just be a create, fire, and forget kind of thing.

    If you have something where the block is sometimes kept alive by self, and sometimes kept alive by something else, then you should re-think your design. You say "There can be conditions when the block is executed after the self is deallocated"; well, you should describe your whole design and how this can happen. Because usually, for something that is executed asynchronously, self need not hold onto the block.

  2. Your code is really confusing and doesn't make sense. For example, why would you assign to a parameter (myClassProperty)? What's the point of passing an argument when the parameter is going to be overwritten anyway? Why would you name a local variable "myClassProperty"?

    What I think you are asking about is accessing a property that can be changed on different threads, and how to deal with the memory management of that. (This question is unrelated to blocks or ARC/MRC. It is equally an issue in ARC.)

    The answer is that you need an atomic property. You can make a synchronized property atomic, or implement an atomic property manually if you know how. What an atomic property of object pointer type needs to do is its getter needs to not just return the underlying variable, but also retain and autorelease it, and return the result of that. The retrieval and retaining in the getter occurs in a critical section that is synchronized with a critical section in the setter that includes the release of the old value and retaining of the new. Basically, this synchronization guarantees that the value will not be released in the setter in between retrieving the value and retaining it in the getter. And the value returned from the getter is retained and autoreleased, so it is guaranteed to be alive for the duration of the scope.

Sign up to request clarification or add additional context in comments.

8 Comments

you didn't get the point.He don't need slowdown and synchronize app with synch properties. May be when method someMethod is performing he don't need value in someProperty any more, but variable myClassProperty should have existing value or nil, what his code on MRC can't guarantee in multithreading environment. And my solution is much safer, because it's the same code, that performed in ARC: variable p will have retained value or nil in any case.
@Cy-4AH: No, your code is not safe if his code is not safe. (If the property is nonatomic, both are unsafe; if it is atomic, both are safe.)
I see you came to Objective-C from Java. May be this code unsafe for java, because calling methods from null will throw exception. But in Objective-C it's safe to send messages to nil. And it's common practice.
@Cy-4AH: Stop trying to insult people. I did not "come to Objective-C from Java". I am an expert in Objective-C. I never said it was unsafe to send messages to nil. Sending messages to nil does nothing. It is unsafe to send messages to a deallocated instance.
@Cy-4AH: Basically, you keep resorting to personal attacks, without addressing, like an educated person, that your answer and all your comments are fundamentally wrong. "variable p will have retained value or nil in any case" is false. It can point to a deallocated instance, if someProperty is a nonatomic property, just like in the OP's code it can point to a deallocated instance if it is a nonatomic property.
|
-2

Solution for 2)

__block MyClass *blockSelf = self; 
self.myBlock = ^{
         datatype* p = [blockSelf.someProperty retain];
         [blockSelf someMethod:p]; 
         [p release];
    };

// I am taking someProperty in an method argument
-(void) someMethod:(datatype*)myClassProperty
{
  myClassProperty = abc;
}

For 1) don't know how you use myBlock. If it's used only by self, then all will be fine. And if it's used by some other object, then it's also should have retained reference at self and then there is also all will be fine.

3 Comments

This is obvious and probably correct also, but what if my method uses other properties also, say it uses 5 properties, then retaining each property and then releasing doesn't make sense, right?
@tarun_sharma, Why doesn't make sense? Arc do the same. It adds retain-release code for you. And do you have method with five arguments? Don't you find it's ugly? In that case you should work direct with properties without passing them as arguments to someMethod.
Your solution for (2) is no safer than the OP's code. If the OP is worried about the value being released in between accessing the property and passing it to the method, then in your code you similarly have the issue of the value being released in between accessing the property and retaining it. The solution for both is an atomic property.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.