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

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

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

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

【问题讨论】:

  • 尝试在主线程上调度。
  • 我会试着弄清楚为什么它在后台线程上被调用,谢谢你的提示......

标签: ios objective-c iphone uikit ios11


【解决方案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)
    }
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-01
    • 1970-01-01
    相关资源
    最近更新 更多