如何在drawRect中获取UIView大小

Posted

技术标签:

【中文标题】如何在drawRect中获取UIView大小【英文标题】:How to get UIView size in drawRect 【发布时间】:2017-09-04 00:27:17 【问题描述】:

我正在使用self.bounddrawRect 方法中获取 UIView 大小。但是现在,使用 XCode 9,我收到了这个警告:

主线程检查器:在后台线程上调用的 UI API:-[UIView 界限]

drawRect 方法中获取视图大小的正确方法是什么?

【问题讨论】:

尝试在主线程上调度。 我会试着弄清楚为什么它在后台线程上被调用,谢谢你的提示...... 【参考方案1】:

像这样:

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

但是 drawRect 首先在后台线程上被调用的事实是一个不好的迹象 - 除非您使用的是 CATiledLayer 或其他一些执行此操作的内置架构。你应该首先担心那个

【讨论】:

我在这个视图中使用的是CATiledLayer,所以后台调用drawRect是正常的。 好的,如果你看看我的评论和我的回答,这正是我要你确认的!在那种情况下,是的,这是解决问题的方法。事实证明,我们一直都在做错事;直到现在主线程检查器才出现并打倒了我们。它已经证明了它的价值! 您认为在drawRect中进行同步操作会减慢绘图速度吗?您如何看待覆盖 layoutSubviews 并将大小保留在类成员中? 我认为这是一个伟大的想法,并且正准备自己提出建议。 :) 很酷,但一定要在 Thread Sanitizer 下运行,以确保您没有引入竞争条件。【参考方案2】:

我终于找到了解决问题的方法。我现在覆盖 UIView 的 layoutSubviews 以将视图边界保留在类成员中:

- (void)layoutSubviews

    [super layoutSubviews];
    m_SelfBounds = self.bounds;

之后,我只是在drawRect方法中使用m_SelfBounds

【讨论】:

这并没有解决您的线程安全错误——您所做的只是以编译器不够聪明而无法警告您的方式创建相同的错误。 m_SelfBounds 值可以在 drawRect 操作中途改变。【参考方案3】:

使用 Grand Central Dispatch 的“屏障”功能允许并发读取操作,同时在写入期间阻止这些操作:

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)
    
  

【讨论】:

以上是关于如何在drawRect中获取UIView大小的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 drawRect 覆盖在 UIView 子类的某些区域中获得透明度

如何转换 UIView 坐标以在 drawRect 中使用?

调整 UIView 的大小并在 drawRect 中动态调整绘图的大小

调整 UIView 的大小,但 drawRect 完成的绘图也会改变大小

我正在使用 drawRect 实现 UIView 子类:如何绘制按钮?

自定义 UI 视图更改帧大小