David Gagnon
David Gagnon

Reputation: 149

How to get UIView size in drawRect

I am using self.bound to get the UIView size in drawRect method. But now, with XCode 9, I get this warning:

Main Thread Checker: UI API called on a background thread: -[UIView bounds]

What is the right way to get the view size in drawRect method?

Upvotes: 3

Views: 794

Answers (3)

Abhi Beckert
Abhi Beckert

Reputation: 33359

Use the "barrier" feature of Grand Central Dispatch to allow concurrent read operations while blocking those operations during a write:

class MyTileView: UIView
{
  var drawBounds = CGRect(x: 0, y: 0, width: 0, height: 0)
  let drawBarrierQueue = DispatchQueue(label: "com.example.app",
                                             qos: .userInteractive, // draw operations require the highest priority threading available
                                             attributes: .concurrent,
                                             target: nil)

  override func layoutSubviews() {
    drawBarrierQueue.sync(flags: .barrier) { // a barrier operation waits for active operations to finish before starting, and prevents other operations from starting until this one has finished
      super.layoutSubviews();

      self.drawBounds = self.bounds

      // do other stuff that should hold up drawing
    }
  }

  override func draw(_ layer: CALayer, in ctx: CGContext)
  {
    drawBarrierQueue.sync {
      // do all of your drawing

      ctx.setFillColor(red: 1.0, green: 0, blue: 0, alpha: 1.0)
      ctx.fill(drawBounds)
    }
  }
}

Upvotes: 0

matt
matt

Reputation: 535231

Like this:

override func drawRect(rect: CGRect)
    let bds = DispatchQueue.main.sync {
        return self.bounds
    }
    // ....
}

But the fact that drawRect is being called on a background thread in the first place is a bad sign — unless you're using CATiledLayer or some other built-in architecture that does this. You should be worrying first and foremost about that.

Upvotes: 7

David Gagnon
David Gagnon

Reputation: 149

I finally found a solution for the problem. I am now overriding layoutSubviews of UIView to keep the view bounds in a class member:

- (void)layoutSubviews
{
    [super layoutSubviews];
    m_SelfBounds = self.bounds;
}

After that, I am just using m_SelfBounds in drawRect method.

Upvotes: 5

Related Questions