Interface Builder会降低storyboard的质量,使视图以小增量进行调整大小和重新定位。

73

我们有很多 iOS 应用程序,由几个不同的开发人员贡献。我一直注意到的一个问题是,在我们的 storyboard 中,视图会移动或缩小,导致原来为适应文本大小的标签突然出现了截断文本的情况。

我注意到这些视图的退化出现在提交到我们 Git 存储库中的提交中,而开发人员并没有直接对 storyboard 进行任何编辑。他们可能在 Interface Builder 中查看了 storyboard,但没有对 storyboard 进行任何实际更改。尽管如此,更改仍然被保存并与他们正在处理的内容一起提交。

当我在受影响的提交前后的 storyboard 文件之间进行文本比较时,我看到了视图框架的小变化,例如:

<rect key="frame" x="203" y="8" width="362" height="29"/>
                             |
                             V
<rect key="frame" x="203" y="7.5" width="362" height="29"/>

<rect key="frame" x="446.00000170260091" y="7" width="302" height="30"/>
                      |
                      V
<rect key="frame" x="446" y="7" width="302" height="30"/>

<rect key="frame" x="364" y="3" width="200" height="38"/>
                      |
                      V
<rect key="frame" x="363" y="3" width="200" height="38"/>

<rect key="frame" x="284" y="7" width="97" height="30"/>
                      |                |
                      V                V
<rect key="frame" x="283" y="7" width="96" height="30"/>

<rect key="frame" x="384.00001078580522" y="7" width="101" height="30"/>
                      |                                |
                      V                                V
<rect key="frame" x="383.00000530853856" y="7" width="100" height="30"/>

大多数情况下,帧尺寸的数字只会轻微变化,要么整数值会发生一次变化,要么浮点值会被截断或小数部分略微改变。

但有时候,这些值会有几个点的变化,比如:

<rect key="frame" x="334" y="3" width="200" height="38"/>
                      |
                      V
<rect key="frame" x="331" y="3" width="200" height="38"/>

<rect key="frame" x="251" y="7" width="223" height="30"/>
                                        |
                                        V
<rect key="frame" x="251" y="7" width="220" height="30"/>

<rect key="frame" x="478" y="3" width="274" height="38"/>
                      |                 |
                      V                 V
<rect key="frame" x="475" y="3" width="276" height="38"/>
请注意,这些示例帧更改都是从同一个提交中获取的,当开发人员没有意图对Storyboard进行任何更改时。两个文件版本之间的XML有269个差异,所有这些差异都是框架大小或位置的轻微更改。Storyboard XML大约有9000行。
看起来问题可能与IB使用的浮点数和舍入误差有关,而变得不同的几个像素可能是在多次打开、解析和重新序列化数据的过程中这些舍入误差的聚合。这只是一种理论,因为我还没有能够确定不想要的更改的确切原因。通常,提交根本不会对框架产生任何重大更改,只会产生微不足道的浮点更改,例如446.00000055262581->446.00000112002783。但是当发生严重更改时,它们似乎会大量发生。
更改发生在同一开发人员使用相同版本的Xcode和Interface Builder创建的提交之间。在此示例提交中获取此数据时,文档标记在Storyboard文件的两个版本中都为``。
除了确保不提交对Storyboard文件的微不足道或意外更改之外,我希望缩小是什么导致了我们故事板视图中这些不想要的更改。如果有什么我们可以避免做,从而导致此问题,我们就可以意识到原因。
更新: 正如Tim热心地指出的那样,使用视网膜显示器在Interface Builder上使用时会导致此问题。所有造成问题的开发人员都有视网膜MacBook Pro。没有视网膜显示器的人没有遇到过这个问题。

5
Xcode 9.4.1仍有问题。每当我打开一个Storyboard时,就会出现数百个差异需要提交。 - Daniel Asher
3
Xcode 11.3.1仍存在问题。2014年至2020年间,Xcode打开storyboard后仍会生成大量的diffs。 - some.birdie
3个回答

26
这个谜团中最有趣的线索是,当你在Retina显示器上打开相同的Storyboard时,情况似乎特别糟糕,而非Retina显示器则没有这种情况。
起初我在一台4k iMac和一台未用Retina屏幕的Macbook Pro之间来回切换,每次都会有大量的更改(每次约300行)。
然后我简单地将Xcode窗口从我的主显示器(4k/Retina)拖到了我的第二个显示器(2560x1440,非Retina)- 虽然窗口大小相同,但Xcode调整了所有元素,并且出现了约50个错位视图的错误。我将其移回Retina显示器,大约一半的“错位”错误消失了,但还有一半留了下来。如你所说,重新缩放会降低底层数据的质量。
如果你有多个开发人员在同一个文件上工作,这种情况很可能经常发生。
解决方案?这可能完全取决于苹果公司的改正 - 我还没有遇到任何可以减轻此问题的设置。

Pradeep K已经找到了设置,让Xcode忽略Retina显示模式https://dev59.com/O18d5IYBdhLWcg3woDcZ#36124980,尽管正如他所指出的那样,这违背了使用Retina显示器的初衷。我禁用了该设置,因为我大多数时间都在外部显示器上进行开发。 - Martin

8
这似乎是与Interface Builder对CGFloat值的序列化相关的错误。视图框架的大小和位置值是浮点数,但它们的值始终为整数。对于变换运算需要将它们设置为浮点数,但所有内容都以四舍五入的整数点值来表示。
当这些浮点数值序列化到Storyboard XML时,IB经常将值序列化为整数,但偶尔也会将其序列化为浮点数。我不确定为什么它要这样决定,但这种情况不太常见。在我的示例框架中,有3个值最终成为了浮点数,而其他值则为整数。
正如我所提供的示例中所看到的那样,通常会将浮点表示法更改为将其序列化为整数。我认为这就是错误所在。
我注意到一个问题是视图框架的更改趋向于向左移动或缩小。因此,这些值大多数情况下会变小。从我提供的示例中可以看出,这通常是这种情况。
浮点数没有精确地表示整数值的能力,但在几个小数位上是准确的。因此,有时整数被表示为比整数值略高(例如:384.00001078580522),而其他时候则表示为略低于整数值。以下是IB所做的框架更改示例:
<rect key="frame" x="457" y="7" width="291" height="30"/>
                      |
                      V
<rect key="frame" x="456.99999985252464" y="7" width="291" height="30"/>

虽然这个特定的更改似乎没有直接修改框架的值。两个数字基本上都等于457。我认为正在发生的是,当故事板再次打开时重新解析此XML文件时,它可能会截断456.99999985252464的值并将其读作456。这随后导致值逐渐变小,缩小帧的尺寸或将其位置向左或向上移动。
当然,这只是一种理论,并不能说明Interface Builder为什么这样做。自最近的Xcode 6发布以来似乎已经开始。此外,它无法解释为什么在一个示例中从8变为7.5,甚至上一个示例中它从274变为276的原因。但是大部分更改 tend to be in the downward direction。
我正在向苹果提交错误报告以进行研究。

谢谢你详细的解释,Jeff。我们也遇到了这个问题。你找到了任何避免这种情况的方法吗? - celiker
1
正如Tim所指出的那样,这似乎与在视网膜显示器上使用Interface Builder有关。我们所有导致问题的开发人员都使用视网膜显示器,而没有视网膜显示器的人没有遇到这个问题。解析和重写XML的内部实现似乎没有正确处理像素精度。因此,在Apple修复此错误之前,避免在视网膜显示器上使用IB是唯一的解决方法。 - Jeff Lockhart
这仍然让我疯狂,使用Xcode 9.1...你提交了一个bug吗? - Sébastien

3
我可能有一个解决该问题的答案。这是一个不太知名的功能,即在低分辨率模式下打开应用程序。最近我们遇到了一个类似的问题,其中表格视图单元格的内容视图在分隔线设置为默认或单个时高度会多出0.5。当它被设置为None时,这个问题就不存在了。
步骤: 1. 在Storyboard中拖动一个默认的Table View Controller(TVC)。检查表视图单元格的内容视图的高度,它将是43.5。 2. 将表视图的分隔线设置为None。单元格的内容视图高度变为44。
现在退出Xcode并在Finder的获取信息窗口中将其设置为“以低分辨率模式打开”。如果按照上述相同的步骤进行操作,则表视图单元格的内容视图高度将显示为43。
当有不同的团队成员在视网膜和非视网膜显示器上工作时,仅仅因为你在视网膜显示器上打开了Storyboard文件,就会使得Storyboard文件被修改过。其中一种解决方法是打开低分辨率模式来工作。但这违背了使用视网膜显示器的目的,不过与未更改任何内容却标记Storyboard文件为已修改相比,这种方法要好些。

当我在低分辨率模式下打开Xcode 8.2.1并打开我的storyboard文件时,仍然看到0.5的增量。 - sethfri

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