3
votes

I am trying to set a flag using a BOOL within a block.

I declare the BOOL like this:

@property(nonatomic) BOOL flag;

And within the block:

__strong typeof(self) strongSelf = weakSelf;
if(strongSelf->_flag)

My question is, if I do:

__weak typeof(self) weakSelf = self;
if(weakSelf->_flag)

I would get an error:

"dereferencing a __weak pointer is not allowed die to possible null value caused by a race condition, assign it to strong variable first"

Can someone explain to me what this means?

In addition, it seems funny to me I have to reference the BOOL using __strong (i.e. strongSelf->_flag), would that be the same as using self->_flag, because I would be using a strong self here?


More over, if I declare the BOOL as an ivar instead of a property:

BOOL flag;

It would give me a warning also when I use it within the block:

if(flag)

And so I would need to do the following as well:

__strong typeof(self) strongSelf = weakSelf;
if(strongSelf->flag)

This baffles me, because normally we reference an ivar without self, just flag, but the above case seems to me that it is accessing the ivar like self->_flag.

??

I could have use something else such as a NSNumber and good riddance to all this, but my curiosity urges me not to turn a blind eye on it.

2

2 Answers

4
votes

I assume you scheduling the block operation in some operation queue or so when the block executes later in the future.

You should not assign self to weakSelf inside the block. You should do this outside the block

__weak typeof(self) weakSelf = self;
if(weakSelf->_flag)

__weak specifies a reference that does not keep the referenced object alive. A weak reference is set to nil when there are no strong references to the object. Apple arc docs.

You actually want your weakSelf be not null to do some stuff with it. To do so you must declare assign it to a variable with strong ownership qualifier. Sketch:

__weak id weakSelf = self;
schedule_block(^{
// at this point the object pointed by weakSelf may or may not be deallocated
id strongSelf = self; // after this point the object referenced by `strongSelf` will not be deallocated at least `strongSelf` to the end of current block
//You may safely work with `strongSelf` and be sure the object will live at least to the end of current block
});

To sum up: to be sure the object will not be deallocated while you work with it you should obtain a strong reference to it. On the other hand to prevent memory leaks you should use weak references. The algorithm looks like this:

  1. obtain weak reference to object of interest
  2. schedule block
  3. at the start of block obtain a strong reference
    1. if object still live - do whatever you need
    2. if object was deallocated earlier - skip operations in block

iVar is just a member of C-structure the compiler creates for the class at compile time. All references to ivars will be compiled to self-><ivar_name>.

You may refer to Apple's docs for details or to LLVM specs on ARC or LLVM specs on blocks

0
votes

You start with a weak pointer to an object. The object can disappear at any time, setting the weak pointer to nil. Once you assign it to a strong pointer, the strong pointer may have been set to nil if the weak pointer was nil at the time, but once it is set to non-nil, it stays non-nil because it holds a reference keeping the object alive.

if (strongSelf->_flag)

is dangerous, because strongSelf could be nil, leading to a crash.

if (strongSelf != nil && strongSelf->_flag)

is safe because the flag will not be tested unless strongSelf is not nil.

if (weakSelf->_flag)

is obviously also dangerous. But perhaps surprising is that

if (weakSelf != nil && weakSelf->_flag)

is also dangerous, because just because weakSelf was not nil when you checked it, doesn't mean it's not nil a nanosecond later when you try to access _flag.