Xcode 更改未修改的故事板和 XIB 文件

从 git 工作流的角度来看,当多人合作时,情节串连图板是一个相当大的麻烦。例如,在。Storyboard 文件的起始 <document>标记的 toolsVersionsystemVersion属性被最近正在运行的文件操作器的任何配置所改变。精确地同步每个人的 Xcode 版本似乎对 toolsVersion有帮助,但无论如何,systemVersion都会发生变化,这取决于开发人员运行的特定 Mac 和/或 OS X 版本。

这很愚蠢,但基本上是无害的。但是,让我们担心的是,在其他时候,仅仅通过在 git pull之后打开它们,就会自动对故事板做出一些其他的更改。也就是说,Alice 对故事板进行更改,提交并将它们推送到存储库。然后,Bob 拉出 Alice 的更改并打开故事板以进行进一步的更改。当他打开情节串连图板的时候,文件图标立即变成了一个修改过但是没有保存的状态,并且一个 git status表明已经发生了许多奇怪的变化。所有这一切,鲍勃没有改变任何东西,也没有自己保存文件。

我们看到的最常见的自动化更改是在故事板文件末尾附近整个 <classes>标记层次结构的消失或重现。我们还不知道是什么引起的。我们可能有几个本地化版本的故事板在各种。当在 Interface Builder 中打开 lproj 目录时,类层次结构可能会自发地从一些目录中移除并添加到另一些目录中,或者在一些目录中独立存在。这会在 git diff中引起很多噪音,但是它实际上并没有破坏任何功能。我们通常会有选择地将实际的更改添加到 git 的索引中,提交这些更改,然后放弃自发的、无意义的 <classes>更改。这样做是为了保持提交的规模和质量,正如它们应该做的那样。然而,最终,Xcode 不断地重新做更改,而有人只是将它们与其他一些东西一起提交... ... 这很好,直到其他人的 Xcode 决定无缘无故地将它们修改回来。(我们的犯罪历史中有很多人对此发过誓。)

还有其他人看到这种行为吗?这是一个 Xcode 错误还是我们的一个或多个 Mac 开发人员的配置问题?在与 XIB 文件协作时,我们已经看到了一些类似的行为,但故事板似乎更容易受到这种影响。

25952 次浏览

这是 XCode 4.5 + 中的一个 bug,我希望能够修复它,是的,它是一个 PITA。

这是苹果公司的完整漏洞

如何避免 Xcode 对故事板文件进行无意义的编辑?

通过在 Xcode 生成的任何文件(包括情节串连图板、 XIBs、核心数据模型和项目文件)上非常明智地使用 git add -p,这个问题可以在一定程度上得到缓解,所有这些文件都经历了类似的短暂修改,对实际的界面/模型/项目没有影响。

我在故事板上看到的最常见的垃圾更改是系统版本号(正如您所提到的)以及对 <classes>部分的不断添加和删除,我从未见过因为遗漏而导致问题的情况。对于 XIBs,它是对 <reference key="NSWindow"/>的添加和删除,而 <reference key="NSWindow"/>甚至不是 CocoaTouch 中的一个类。只是惊叹。

把它想象成大海: 有高潮也有低潮。让它冲刷你。

就是这样。

在准备更改、重置垃圾更改并进行干净提交时,可以忽略这些修改。

从技术的角度来看,我所看到的故事板相对于 XIBs 的一个优势是,苹果还没有阉割 FileMerge 来拒绝合并冲突的故事板。(FileMerge 过去能够合并 XIBs,但是更新的版本打破了这一点。伙计们! ! !)

请在 http://bugreporter.apple.com/上对所有这些问题提交大量的 bug! 不要忘记在 OpenRadar上创建条目。

这不是 bug,这是 Xcode 处理故事板文件的结果。 我正在为故事板文件 (GitHub 链接)编写一个 diff 和 merge 程序,我花了几个小时分析故事板文件的逻辑和 Xcode 如何处理它。这是我发现的:

  • 为什么故事板文件中会发生奇怪的变化? Xcode 使用 NSXMLAPI 将故事板文件解析为某种基于 NSSet的逻辑树结构。当 Xcode 需要编写更改时,它会根据逻辑树结构创建一个 NSXMLDocument,清除故事板文件并调用 XMLDataWithOptions:再次填充该文件。因为集合不能保持其元素的顺序,即使是最轻微的修改也可能改变整个故事板 XML 文件。

  • 为什么类标签会随机消失或重新出现? <class>部分只不过是一个内部 Xcode 缓存。Xcode 使用它来缓存关于类的信息。缓存经常更改。当类 .h/.m文件被打开和删除时,Xcode 会怀疑它们已经过时(至少较老的 Xcode 是这样) ,就会添加元素。当您保存故事板时,缓存的 目前版本将被转储,这就是为什么 <class>部分经常更改甚至消失的原因。

我没有对 Xcode 进行逆向工程; 我是通过对 Xcode 和故事板文件进行实验来观察的。尽管如此,我几乎100% 肯定它是这样工作的。

结论 :

  • 缓存部分并不重要; 您可以安全地忽略其中的任何更改。
  • 与你在所有论坛上找到的相反,合并故事板文件并不是一项复杂的任务。例如,假设您在故事板文档中更改了 MyController1视图控制器。打开故事板文件,找到类似这样的内容 <viewController id=”ory-XY-OBM” sceneMemberID=”MyController1”>. 您可以安全地只提交本节中的更改,而忽略其他所有内容。如果您更改了接口或约束,也要提交内部包含 “ory-XY-OBM”的任何内容。很简单!

因为这种情况已经有了很大的改善,所以在这里抛出另一个答案。表示 StoryBoard 的 XIB 文件的 XML 已经大大简化。

我最近也咬紧牙关,开始在 Xcode 使用“源代码管理”界面。我已经使用命令行很多年了,在那里我很开心,但是界面很好,它允许分割提交,如果你使用链接到提交的票务系统,这一点非常重要。

无论如何,我今天注意到故事板上有一个变化,内置的 diff 向我展示了它是文档标记(systemVersion)中的一个单一属性。所以没什么大不了的。

我读过一些文章,其中有人说,由于合并问题,SBs 在他们的团队中是非法的。完全疯了。他们是如此令人惊讶,特别是现在他们有智能自动布局内置,你真的错过了,如果你不使用他们。

了解 为什么这种疯狂的事情正在发生是有帮助的,但是对于那些相信让他们的项目远离警告,并且只想快速而肮脏地让他们的项目回到健康状态的人来说:

  1. 在明确指示之前不要做任何事情。

  2. 打开 Xcode 并创建一个新的故事板(Command + N > iOS > User Interface > Storyboard)。我假设您将其称为 Storyboard.storyboard的默认名称。

  3. 打开 Xcode 违反的情节串连图板。我假设这是 Base.lproj/Main.storyboard

  4. 选择并复制故事板上的所有内容(Command + A 然后 Command + C)。

  5. 打开 Storyboard.storyboard

  6. 将所有内容复制粘贴到 Storyboard.storyboard

  7. 关闭 Xcode。

  8. 打开一个终端并将目录更改到存储库。

  9. Storyboard.storyboard(mv Storyboard.storyboard Base.lproj/Main.storyboard)代替 Main.storyboard

  10. git add Base.lproj/Main.storyboard; git commit -m "Fix Xcode's insanity."

  11. 忽略通过 git checkout -- project.pbxprojproject.pbxproj的改变。如果您使用 git diff文件,您将看到它刚刚添加了有关我们的临时故事板的信息(这个故事板已经不存在了)。

  12. 重新打开 Xcode 并查看警告已经消失。

  13. 深呼吸。

在同一个故事板上工作不是问题。但是在同一个视图控制器上工作会在拉取/合并时产生冲突,这是很可怕的。对于一个大型团队来说,我们无法真正避免在同一个视图控制器中工作。

好消息是,如果我们理解 xml 结构,大多数时候我们可以修复相同的视图控制器冲突。我在团队工作的时候从来没有失败过。假设您使用的是视图控制器。您的视图当前为空白。请查看 viewcontroller 的 xml 结构 from 源代码选项。

enter image description here

情节串连板是由文档类型标记限定的 xml。故事板中的所有内容都包含在场景 SceneID = tag 中。场景标签保存每个视图控制器。这是最基本的。

现在我们在视图中添加了 UILabel 和 UIButton。还要设置元素的自动布局。现在看来:

enter image description here

向视图控制器添加一个级别/按钮在视图的子视图标记中添加了一些新代码。对于进一步的元素添加或任何用户界面更改,也将采取同样的做法。仔细检查标记结构,这对于修复任何冲突都非常重要。

现在我们在故事板名称 Homeviewcontroller 中添加另一个视图控制器。添加一个新的视图控制器意味着在场景标签下添加一个新的场景。看看这个:

enter image description here

此时,我们将随机更改结构并观察问题/警告。我们更改第一个视图控制器标签结束标记并保存文件。现在运行它,看看警告。错误表示从第23行创建的结束标记不正确。在第23行中,我们看到没有设置结束标记的标签约束。这就是问题所在。现在我们放置结束标记并构建项目。在设置了结束标记之后,我们可以成功地查看故事板。

enter image description here

当面临任何冲突的警告,请与您以前的源和更改源进行比较。我们删除旧的/冗余的代码,保持新的代码以适当的标记开始-结束,并得到修复。

[注意,当有时间的时候,我会用更多的测试用例来更新答案]