1

Let's say I want to do @synchronized(self) within a block. I suppose this will lead to a retain cycle, so normally we would re-write it like this:

-(void)myMethod
{
    __weak TheClass * weakSelf = self;
    dispatch_async(dispatch_get_main_queue(),
    ^{
        TheClass * strongSelf = weakSelf;
        if(strongSelf == nil)
        {
            return;
        }

        @synchronized(strongSelf)
        {
            //mutex code
        }
    }
}

My question is, when you use the @synchronized directive this way, is it equivalent to @synchronized(self)?

mfaani
  • 33,269
  • 19
  • 164
  • 293
yano
  • 4,095
  • 3
  • 35
  • 68

1 Answers1

6

Short answer: No

Longer answer:

Background

For there to be a cycle involving a block the block must reference another object, and that object must (directly or via a longer chain) reference the block.

A cycle in of itself is not bad, it is only bad if it results in the lifetime of objects in the cycle being extended past the point those objects are required. It is fine to create a cycle as long as cycle is broken - by breaking one of the links forming the cycle - at some point.

A construct like:

__weak TheClass * weakSelf = self;
...
self.blockVar = ^{
    TheClass * strongSelf = weakSelf;
    ...

prevents a static cycle being created as (the object referenced by) self strongly references (the object referenced by - you get the idea, the variable isn't important but the thing being referenced by it) blockVar but blockVar only has a weak reference back to self.

However every time the block is executed it creates a strong reference (stored in strongSelf) to self and so creates a dynamic cycle - which is automatically broken when the block finishes executing.

Your code

  1. Look at your code, you create a block and pass it directly to dispatch_async - you never store a reference to the block in self. So there never is any cycle here, no need to mess with weak references at all.

  2. Once the block creates strongSelf there is a cycle, then using @synchronized(strongSelf) doesn't create a second one, it just takes a lock on the object. When the synchronized statement exits the lock goes, when the block exits the strong cycle goes.

HTH

CRD
  • 52,522
  • 5
  • 70
  • 86
  • 1
    Your short answer answers the question in the subject, but the last sentence in the question is also a yes/no question. Might want to clarify which you're answering. Also, you didn't answer that last question: yes, `@synchronized(strongSelf)` is the same as `@synchronized(self)`. – Ken Thomases Jan 23 '15 at 04:03
  • @KenThomases 's comment should be incorporated. Both are important points. – yano Jan 23 '15 at 19:38
  • can you show a static cycle being created? I thought it's always about instances – mfaani Sep 28 '19 at 03:19
  • @Honey – I maybe didn't pick the best words here, there are only so many to go around ;-) You are correct it is about instances. In the answer the term *static cycle* is used for one created along with the block, as in `self.blockVar = ^{ ... self ... }`; such a cycle exists from creation of the block and might otherwise be termed *long lived* (if there is a programmed way to break it) or *fixed*. The term *dynamic cycle* is used when there is defined creation and break, as in the use of `strongSelf` where the block call & return creates & breaks a cycle; this could be termed *transient*. – CRD Sep 28 '19 at 04:59