iOS 12,Xcode 10:UIView setNeedsDisplay(_:)似乎出现了问题

3
在升级到Xcode 10后,我发现我的自定义UIView(从UIView派生的类)中的draw(_ rect:CGRect)例程在应用程序中以错误的rect调用。事实上,它始终使用rect作为底层UIView的完整框架进行调用,而不是使用setNeedsDisplay(_ rect:CGRect)指定的rect
以下代码片段可以作为playground运行,在我的设置中,它至少显示了上述错误行为的最简设置:
import Foundation
import UIKit
import PlaygroundSupport

class CustomView: UIView {
    override func draw(_ rect: CGRect) {
        print("rect = \(rect)")
    }
}

let customView = CustomView(frame: CGRect(origin: CGPoint.zero, size: CGSize(width: 200.0, height: 200.0)))
PlaygroundPage.current.liveView = customView
print("test")
customView.setNeedsDisplay(CGRect(origin: CGPoint.zero, size: CGSize(width: 100.0, height: 100.0)))

我得到的输出为:

rect = (0.0, 0.0, 200.0, 200.0)
test
rect = (0.0, 0.0, 200.0, 200.0)

在打印“rect”后的第一个输出是视图的标准完全重绘,但在打印“test”之后的第二个输出会出现问题。此处的输出是由于调用customView.setNeedsDisplay而导致重新绘制,应该是较小的指定矩形(0.0, 0.0, 100.0, 100.0)
因此,我的明显问题是:
  • 您能否重现此行为?
  • 我是否遗漏了明显的内容?
  • 这是一个错误吗?
2个回答

7
这实际上是iOS 12新的动态后备存储功能。后备存储是存储绘制视图所需的内存,需要分配内存才能完成。该内存量取决于视图的大小,因为它实质上是颜色和像素之间的映射。
如果您要绘制灰度图像,但已经为广色域分配了内存,则会导致大量空的分配内存(灰度比RGBA具有更低的占用空间)。为了解决这个问题,动态后备存储功能通过绘制视图的整个内容,然后计算出它需要多少内存,而不是从一开始就假定所有内容都需要广色域支持。
这样做的副作用是,您无法重新绘制视图的较小子部分,因为那可能会改变此存储。
如何解决:
这是一个很棒的新功能,但如果您真的需要解决它,可以在视图上禁用动态后备存储。您可以通过显式设置视图的层的contentsFormat属性来实现这一点。
有三个选项可供选择,涉及灰度、RGBA 8位和RGBA 16位(广色域)。
只需调用:
layer.contentsFormat = .RGBA16Float

如果您想使setNeedsDisplay(_ rect: CGRect)正常工作,可以参考这里的属性:https://developer.apple.com/documentation/quartzcore/calayer/1792104-contentsformat

此外,WWDC 18有一个非常好的讲解新动态后备存储技术的演讲,并且(非常轻声地)提到了这种技术。

https://developer.apple.com/videos/play/wwdc2018/219/?time=1451


不支持 iOS 15。 - Deepak Sharma

2

我在Xcode 9、10和10.1中测试过这个问题。

iOS 11和iOS 12 / 12.1之间的行为明显有所不同。

文档或头文件中没有任何迹象表明这是有意为之的。

在我看来,这似乎是一个bug。


我不同意这是一个错误。这只是行为上的改变,但我找不到任何文件说明setNeedsDisplay(_:)的参数将用于下一次调用draw(_:) - Mats
2
文档确实强烈暗示了这一点。对于 setNeedsDisplay(_:): "标记接收器的指定矩形需要重新绘制",对于 draw(_:):"在随后的绘图操作中,该矩形可能仅指定视图的一部分"。 - Pete Morris
1
我认为setNeedsDisplay(_ rect: CGRect)是绝对必要的功能。我也认为这是进行“部分”视图更新的预期方式。当然,一个人可以直接调用draw,但那会破坏更新设计模式。 - Wizard
也许值得在苹果开发者论坛上询问,看看是否有来自苹果的人回复。 - Ashley Mills
我已经在苹果开发者论坛上发布了。让我们看看吧。 - Wizard
1
这也曾让我困扰,因此我在下面添加了一个答案,解释了原因和意图,以防仍在寻找完整答案的人。 - Jon Hocking

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接