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

时间:2012-11-05 13:32:14

标签: ios xcode interface-builder storyboard xib

当多人合作时,故事板从git工作流角度来看是一种巨大的痛苦。例如,.storyboard文件中的XML的起始<document>标记的toolsVersionsystemVersion属性由最近的文件操作符正在运行的任何配置更改。正确地同步每个人的Xcode版本似乎对toolsVersion有帮助,但systemVersion无论如何都会发生变化,具体取决于开发人员运行的特定Mac和/或OS X版本。

这是愚蠢的,但大多是无害的。但令我们担心的是,在其他时候,只需在git pull之后打开它们,就会自动对故事板进行一些其他更改。也就是说,Alice对故事板进行了更改,提交并将它们推送到存储库。然后鲍勃拉出爱丽丝的变化并打开故事板进行进一步的更改。在他打开故事板的那一刻,文件图标立即变为修改但未保存的状态,git status表示发生了任何数量的奇怪变化。所有这一切都没有鲍勃改变任何东西或自己保存文件。

我们看到的最常见的自动更改是故事板文件末尾附近整个<classes>标记层的消失或重新出现。我们还没弄清楚造成这种情况的原因。我们可能在各种.lproj目录中有几个本地化版本的故事板,当在Interface Builder中打开它们时,类层次结构可能会自动从某些层次结构中删除并添加到其他版本中,或者单独留在某些层次结构中。这会在git diff中产生很多噪音,但实际上并没有破坏任何功能。我们通常会有选择地将我们所做的实际更改添加到git的索引中,提交这些更改,然后放弃自发的,无意义的<classes>更改。这是为了保持提交小而好,因为它们应该是。然而,最终,由于Xcode不断重新进行更改,它变得太麻烦了,有人只是愤怒地提交它们以及其他一些东西......这很好,直到其他人的Xcode决定要将它们更改为否明显的原因。 (我们的提交历史对此很多咒骂。)

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

6 个答案:

答案 0 :(得分:76)

这不是错误,这是Xcode处理故事板文件的结果。 我正在为故事板文件(GitHub link)编写差异和合并程序,我花了几个小时分析故事板文件逻辑以及Xcode如何处理它。这就是我发现的:

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

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

我没有反向设计Xcode;我通过试验Xcode和storyboard文件来做出这些观察。尽管如此,我几乎100%确定它是这样工作的。

<强>结论

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

答案 1 :(得分:17)

这是XCode 4.5+中的一个错误,我希望它得到修复,是的,它是一个PITA。

这是Apple的完整错误

How to avoid Xcode gratuitous edits to storyboard files?

答案 2 :(得分:11)

通过在任何Xcode生成的文件(包括故事板,XIB,核心数据模型和项目文件)上非常谨慎地使用git add -p来解决这个问题,所有这些文件都遭受类似的瞬态修改对实际界面/模型/项目的影响。

我在故事板上看到的最常见的垃圾更改是系统版本号(正如您所提到的)以及<classes>部分的不断添加和删除,我从未见过的遗漏会导致问题。对于XIB,它是<reference key="NSWindow"/>的添加和删除,它甚至不是Cocoa Touch中的类。哇。

把它想象成大海:既有高潮又有低潮。让它洗过你。

稀释。就是这样。

在暂存更改,重置垃圾更改以及进行干净提交时,您可以忽略这些修改。

从技术角度来看,我在XIB上看到的故事板的唯一优势是,Apple还没有扼杀FileMerge以拒绝合并冲突的故事板。 (FileMerge曾经能够合并XIB,但更新的版本打破了.Thxxxx家伙!!!)

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

答案 3 :(得分:6)

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

我最近也咬了一口子弹并开始使用Xcode中的界面来源代码控制。我已经在命令行上工作多年并且很开心,但界面很好,它允许你拆分提交,如果你使用链接到提交的票务系统,这非常重要。

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

我读过一些文章,人们说SB因为合并问题而被禁止参加他们的团队。完全疯狂。他们是如此惊人,特别是现在他们内置了智能自动布局,如果你不使用它们,你真的错过了。

答案 4 :(得分:3)

了解为什么这种疯狂正在发生是有帮助的,但是对于那些相信保持项目没有警告并且只想快速和肮脏让他们的项目恢复健康的人状态:

  1. 在明确指示之前不要提交任何内容。

  2. 打开Xcode并创建一个新的故事板(Command + N&gt; iOS&gt;用户界面&gt;故事板)。我假设您将其称为默认名称Storyboard.storyboard

  3. 打开Xcode违反的故事板。我假设这是Base.lproj/Main.storyboard

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

  5. 打开Storyboard.storyboard

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

  7. 关闭Xcode。

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

  9. Main.storyboard替换为Storyboard.storyboardmv Storyboard.storyboard Base.lproj/Main.storyboard)。

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

  11. 通过project.pbxproj忽略对git checkout -- project.pbxproj的更改。如果您git diff该文件,您会看到它刚刚添加了有关我们的临时故事板(不再存在)的信息。

  12. 打开Xcode备份,看到警告消失了。

  13. 呼吸

答案 5 :(得分:0)

在相同的情节提要板上工作不是问题。但是在同一个viewcontroller上进行操作会在拉/合并时产生冲突,这令人恐惧。我们真的不能避免为大型团队在同一ViewController中工作。

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

enter image description here

故事板是xml格式的文档类型标签。情节提要中的所有内容都包含在场景sceneID =标签中。场景标签包含每个ViewController。多数民众赞成在最基本的。

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

enter image description here

向viewcontroller添加级别/按钮会在视图的subview标签内添加一些新代码。进一步添加元素或更改UI也会采用相同的方法。仔细检查标签结构,这对于解决任何冲突非常重要。

现在,我们在故事板名称Homeviewcontroller中添加另一个viewcontroller。添加一个新的viewcontroller意味着它将在场景标签下添加一个新场景。看这个:

enter image description here

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

enter image description here

遇到任何冲突警告时,请与您以前的来源进行比较并更改来源。我们删除了旧的/多余的代码,使用正确的标签start-end保留了新代码,并进行了修复。

[N.B,我会在获取时间时用更多测试用例更新答案]