Der Interface Builder verschlechtert Storyboards, ändert die Größe und positioniert Ansichten in kleinen Schritten neu


71

Wir haben eine Reihe von iOS-Apps, zu denen verschiedene Entwickler beitragen. Ein Problem, das ich weiterhin bemerke, ist, dass Ansichten in unseren Storyboards aus der Position verschoben werden, in der sie platziert wurden, oder die Größe geändert werden, sodass sie kleiner sind plötzlich kürzen sie ihren Text.

Ich stelle fest, dass diese Verschlechterungen unserer Ansichten in Commits für unser Git-Repository angezeigt werden, wenn der Entwickler keine direkten Änderungen am Storyboard vorgenommen hat. Möglicherweise haben sie das Storyboard in Interface Builder angezeigt, aber keine wirklichen Änderungen am Storyboard vorgenommen. Die Änderungen wurden dennoch gespeichert und zusammen mit dem, woran sie arbeiteten, festgeschrieben.

Wenn ich vor und nach den verantwortlichen Commits einen Textvergleich zwischen den Storyboard-Dateien durchführe, werden kleine Änderungen an den Ansichtsrahmen angezeigt, z.

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

und

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

und

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

und

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

und

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

Meistens ändern sich die Zahlen für die Rahmenabmessungen nur geringfügig, entweder ändert sich ein ganzzahliger Wert um eins oder ein Gleitkommawert wird abgeschnitten oder der Dezimalteil wird geringfügig geändert.

In anderen Fällen ändern sich die Werte jedoch um einige Punkte wie folgt:

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

und

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

und

<rect key="frame" x="478" y="3" width="274" height="38"/>
                      |                 |
                      V                 V
<rect key="frame" x="475" y="3" width="276" height="38"/>

Beachten Sie, dass alle diese Beispiel-Frame-Änderungen aus demselben Beispiel-Commit übernommen wurden, als der Entwickler nicht beabsichtigte, eine einzige Änderung am Storyboard vorzunehmen. Es gab 269 Unterschiede im XML zwischen den beiden Versionen der Datei, allesamt geringfügige Änderungen der Frame-Größen oder -Positionen. Das Storyboard-XML besteht aus ~ 9000 Zeilen.

Es scheint, dass das Problem möglicherweise etwas mit der Verwendung von Gleitkommazahlen und Rundungsfehlern durch IB zu tun hat. Die Unterschiede, die sich um einige Pixel verringern, könnten eine Aggregation dieser Rundungsfehler über einen Zeitraum von mehrmaligem Öffnen, Parsen und erneuter Serialisierung sein die Daten.

Dies ist jedoch nur eine Theorie, da ich die genaue Ursache der unerwünschten Änderungen nicht genau bestimmen konnte. Oft nehmen Commits überhaupt keine wesentlichen Änderungen an den Frames vor, sondern nur unbedeutende Gleitkommaänderungen wie 446.00000055262581 -> 446.00000112002783. Aber wenn die gravierenden Veränderungen eintreten, scheinen sie in großer Zahl aufzutreten.

Die Commits, zwischen denen die Änderungen vorgenommen werden, werden ebenfalls von demselben Entwickler mit derselben Version von Xcode und Interface Builder vorgenommen. In diesem Beispiel-Commit, in dem diese Daten erfasst wurden, befindet sich das Dokument-Tag beispielsweise <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">in beiden Versionen der Storyboard-Datei.

Abgesehen davon, dass Sie sicherstellen, dass keine unbedeutenden oder unbeabsichtigten Änderungen an Storyboard-Dateien vorgenommen werden, möchte ich eingrenzen, was diese unerwünschten Änderungen an unseren Storyboard-Ansichten verursacht. Wenn wir vermeiden können, dass dies das Problem verursacht, können wir uns der Ursache bewusst sein.

Update: Wie Tim hilfreich bemerkte, scheint dieses Problem bei der Verwendung von Interface Builder auf einem Retina-Display verursacht zu werden. Alle Entwickler, die das Problem verursacht haben, haben Retina MacBook Pros. Diejenigen von uns ohne Retina-Displays haben das Problem nicht erlebt.


3
Xcode 9.4.1 NOCH GEBROCHEN. Jedes Mal, wenn ich ein Storyboard öffne, kann ich Hunderte von Unterschieden festlegen.
Daniel Asher

3
Xcode 11.3.1 - Fehler lebt noch. 2014-2020 (...) Xcode generiert nach dem Öffnen von Storyboards immer noch Tonnen von Unterschieden.
Anastasia

Antworten:


24

Der interessanteste Hinweis in diesem Rätsel ist, dass es besonders schlimm erscheint, wenn Sie dasselbe Storyboard auf einem Retina-Display öffnen, im Gegensatz zu einem Nicht-Retina-Display.

Zuerst pendelte ich zwischen einem 4k iMac und einem Pre-Retina Macbook Pro hin und her und bekam eine große Menge an Änderungen (~ 300 Zeilen wurden jedes Mal geändert).

Dann zog ich einfach das xcode-Fenster von meinem Hauptmonitor (4k / Retina) auf meinen zweiten Monitor (2560x1440, keine Retina) - und während das Fenster dieselbe Größe hatte, änderte xcode die Größe aller Elemente und beschwerte sich über ~ 50 falsch platzierte Ansichten . Ich habe es zurück zum Retina-Display verschoben und ungefähr die Hälfte der "verlegten" Fehler ist verschwunden, aber die Hälfte ist geblieben. Die Neuskalierung verschlechtert - wie Sie vorschlagen - die zugrunde liegenden Daten.

Wenn mehrere Entwickler an derselben Datei arbeiten, tritt dies häufig auf.

Die Lösung? Dies ist wahrscheinlich alles auf Apple zu korrigieren - ich habe keine Einstellungen getroffen, die es sonst mildern würden.


Pradeep K hat die Einstellung gefunden, dass Xcode den Retina-Anzeigemodus stackoverflow.com/a/36124980/2064473 ignorieren kann, obwohl dies, wie er betonte, den Sinn der Verwendung eines Retina-Displays zunichte macht . Ich habe die Einstellung deaktiviert, weil ich sowieso meistens auf einem externen Display entwickle.
Martin

8

Dies scheint ein Fehler im Zusammenhang mit der Serialisierung von CGFloat-Werten durch Interface Builder zu sein. Die Größen- und Positionswerte für Ansichtsrahmen sind Gleitkommazahlen. Aber ihre Werte sind immer ganze Zahlen. Die interne grafische Manipulation erfordert, dass sie Gleitkommawerte sind, damit die Transformationsmathematik funktioniert, aber alles wird immer in runden ganzzahligen Punktwerten ausgedrückt.

Wenn diese Gleitkommawerte in das Storyboard-XML serialisiert werden, serialisiert IB die Werte häufig als Ganzzahlen, gelegentlich aber auch als Gleitkommazahlen. Ich bin mir nicht sicher, warum es die Entscheidung trifft, es so zu machen, wenn es so ist, aber es ist weniger verbreitet. In meinen obigen Beispielrahmen waren 3 der Werte Gleitkommawerte, während die anderen Ganzzahlen sind.

In meinen Beispielen wird auch häufig die Gleitkommadarstellung geändert, um stattdessen als Ganzzahl serialisiert zu werden. Hier wird meiner Meinung nach der Fehler gefunden.

Eine Sache, die mir bei der Veränderung der Ansichtsrahmen auffiel, war, dass sie sich tendenziell nach links bewegten oder kleiner wurden. Die Werte werden also meistens kleiner. Sie können in den von mir bereitgestellten Beispielen sehen, dass dies meistens der Fall ist.

Gleitkommazahlen haben nicht die Genauigkeit, um ganzzahlige Werte genau auszudrücken, sind jedoch auf mehrere Dezimalstellen genau. Während manchmal ganze Zahlen als die in meinen Beispielen als etwas höher als der ganzzahlige Wert (dh 384.00001078580522) ausgedrückt werden, werden andere als etwas niedriger als der ganzzahlige Wert ausgedrückt. Hier ist ein Beispiel für eine Rahmenänderung, die IB vorgenommen hat:

<rect key="frame" x="457" y="7" width="291" height="30"/>
                      |
                      V
<rect key="frame" x="456.99999985252464" y="7" width="291" height="30"/>

Diese spezielle Änderung schien den Wert des Frames nicht direkt zu ändern. Beide Zahlen sind im Wesentlichen gleich 457. Ich denke, wenn dieses XML beim erneuten Öffnen des Storyboards erneut analysiert wird, wird möglicherweise der Wert 456.99999985252464 abgeschnitten und als 456 gelesen. Dadurch werden die Werte progressiv kleiner, verkleinert die Größe oder verschiebt die Position der Rahmen nach links oder oben.

Dies ist natürlich nur eine Theorie und gibt keinen Grund an, warum Interface Builder dies tut. Es scheint seit der letzten Veröffentlichung von Xcode 6 begonnen zu haben. Außerdem wird nicht erklärt, wie es in einem Beispiel von 8 auf 7,5 oder in meinem letzten Beispiel sogar von 274 auf 276 gestiegen ist. Aber zum größten Teil tendieren die meisten Änderungen nach unten.

Ich melde mich bei Apple, um dies zu untersuchen.


Danke für die lange Erklärung Jeff, das passiert uns auch. Haben Sie einen Weg gefunden, dies zu vermeiden?
Celiker

1
@celiker Wie Tim hilfreich bemerkte, scheint dies mit der Verwendung von Interface Builder auf Retina-Displays verbunden zu sein. Alle Entwickler, die das Problem verursacht haben, haben Retina-Displays, während diejenigen von uns ohne Retina-Displays das Problem nicht hatten. Die interne Implementierung, das Parsen und Umschreiben von XML scheint die Pixelgenauigkeit nicht richtig zu handhaben. Die Vermeidung der Verwendung von IB auf einem Retina-Display ist derzeit die einzige Problemumgehung, bis Apple diesen Fehler behebt.
Jeff Lockhart

Das macht mich immer noch verrückt, mit Xcode 9.1 ... Hast du einen Fehler gemeldet?
Sébastien

3

Ich könnte eine Antwort auf dieses Problem haben. Das Öffnen der Apps im Modus mit niedriger Auflösung ist weniger bekannt. Wir hatten kürzlich ein ähnliches Problem, bei dem die Inhaltsansicht der Tabellenansichtszellen einen zusätzlichen Wert von 0,5 für die Höhe hatte, wenn die Trennlinie auf Standard oder Einzel gesetzt ist. Wenn es auf None gesetzt ist, war dieses Problem nicht vorhanden. Schritte 1. Ziehen Sie einen Standard-TVC auf das Storyboard. Überprüfen Sie die Höhe der Inhaltsansicht der Tabellenansichtszelle. Es wird 43,5 sein. 2. Setzen Sie die Trennlinie für die Tabellenansicht auf Keine. Die Inhaltsansicht der Zelle ändert sich zu 44.

Beenden Sie nun Xcode und stellen Sie im Finder Get Info-Fenster für die Xcode-App den Modus Im niedrigen Auflösungsmodus öffnen. Wenn Sie nun dieselben Schritte wie oben ausführen, wird die Höhe der Inhaltsansicht für die Tabellenansichtszelle als 43 angezeigt.

Wenn verschiedene Teammitglieder an Retina- und Nicht-Retina-Displays arbeiten, werden die Storyboard-Dateien einfach geändert, nur weil Sie das Storyboard in der Retina-Anzeige geöffnet haben. Eine Problemumgehung besteht darin, das Öffnen im Modus mit niedriger Auflösung zu aktivieren und zu arbeiten. Aber dann hat es den Zweck, ein Retina-Display zu haben, aber besser als Storyboards, die als modifiziert markiert sind, obwohl Sie nichts geändert haben.


Ich sehe immer noch das Inkrement von 0,5, wenn ich Xcode 8.2.1 im Modus mit niedriger Auflösung öffne und dann meine Storyboard-Datei öffne.
Sethfri
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.