Interface Builder 以小的增量降低故事板、调整大小和重新定位视图

我们有几个不同的开发者贡献的许多 iOS 应用程序。我不断注意到的一个问题是,我们故事板中的视图会偏离原来的位置,或者调整大小,使其更小,这在标签上的大小适合文本,最初变得痛苦地明显,当标签突然截断他们的文本。

我注意到,当开发人员没有直接对故事板进行任何编辑时,我们的视图的这些退化就会出现在对 Git 存储库的提交中。他们可能已经在 Interface Builder 中查看了故事板,但是并没有对故事板做出任何真正的改变。然而,这些更改与它们正在进行的工作一起被保存和提交。

当我在提交之前和之后对故事板文件进行文本比较时,我发现视图框架有一些小的变化,比如:

<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"/>

请注意,所有这些示例框架更改都来自同一个示例提交,当开发人员不打算对故事板进行单一更改时。这两个版本的文件在 XML 中有269处不同,所有这些都是在帧大小或位置上的细微变化。故事板 XML 大约有9000行。

看起来这个问题可能与 IB 使用浮点数和舍入错误有关,几个像素之间的差异可能是这些舍入错误在数次打开、解析和重新序列化数据期间的聚合。

这只是一个理论,因为我还不能准确地指出不必要的变化的原因。通常情况下,提交根本不会对帧做出任何重大更改,只会对浮点数做出微不足道的更改,如446.0000055262581-> 446.0000112002783。但是,当严重的变化发生时,它们似乎大量出现。

更改之间的提交也是由同一开发人员使用相同的 Xcode 版本和 Interface Builder 进行的。在这个示例中,提交数据所在的位置,例如,在故事板文件的两个版本中,document 标记都是 <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6250" systemVersion="14A389" targetRuntime="iOS.CocoaTouch.iPad" propertyAccessControl="none" initialViewController="JAD-vj-VfC">

除了确保不要对故事板文件进行无关紧要或意外的更改之外,我还想缩小导致故事板视图发生这些意外更改的原因。如果是我们可以避免做的事情导致了这个问题,我们可以意识到原因。

更新: 正如提姆指出的那样,这个问题似乎确实是在视网膜显示器上使用 Interface Builder 时引起的。所有导致这个问题的开发者都有 Retina MacBook Pro。我们这些没有视网膜显示器的人没有经历过这个问题。

3611 次浏览

这似乎是一个与 Interface Builder 序列化 CGFloat 值有关的 bug。视图框架的大小和位置值是浮点数。但它们的值总是整数。内部的图形操作要求它们是浮点数,以便转换数学工作,但是所有内容总是以圆形整数点值表示。

当这些浮点值序列化为故事板 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的。但在大多数情况下,大多数变化往往是向下的方向。

我正在向苹果公司申请调查这个漏洞。

这个谜团中最有趣的线索是,当你在视网膜显示器上打开同一个故事板,而不是在非视网膜显示器上打开同一个故事板时,情况似乎特别糟糕。

起初,我在一台4k 的 iMac 和一台预装 Retina 的 Macbook pro 之间来回移动,得到了大量的改动(每次改动大约300行)。

然后我简单地将 xcode 窗口从我的主显示器(4k/retina)拖到我的第二个显示器(2560x1440,非 retina)——虽然窗口大小相同,但 xcode 调整了所有元素的大小,并抱怨大约50个错误的视图。我把它移回到视网膜显示屏上,大约一半的“放错地方”的错误消失了,但一半仍然存在。正如您所建议的那样,重新缩放会降低底层数据的质量。

如果有多个开发人员在处理同一个文件,这种情况肯定会经常发生。

解决办法?这可能都是苹果要纠正的-我还没有遇到任何设置,否则会减轻它。

我可能知道这个问题的答案。在低分辨率模式下打开应用程序是一个鲜为人知的特性。我们最近遇到了一个类似的问题,当分隔符行设置为默认或单行时,表视图单元格的内容视图的高度有0.5个额外值。当它设置为 Nothing 时,这个问题就不存在了。 步骤 1.拖动一个默认的 TVC 到故事板。检查表视图单元格的内容视图的高度。43.5美元。 2. 将表格视图的分隔线设置为“无”。单元格的内容视图更改为44。

现在退出 Xcode,并在 FinderGetInfo 窗口中为 Xcode 应用程序设置 Open in Low Resolution 模式。现在,如果您执行上面的相同步骤,它将显示表视图单元格的内容视图高度为43。

当有不同的团队成员工作在视网膜和非视网膜显示器,你只需要得到故事板文件修改,只是因为你打开故事板在视网膜显示。解决这个问题的一个方法是以低分辨率模式打开并工作。但是这样就违背了视网膜显示屏的初衷,但是这比在没有改变任何东西的情况下把故事板标记为修改版要好得多。