🍎

Interface Builderを使わずにMacアプリケーション作成 - nib検証篇 2

2020/09/20に公開

Xcode 4で作成したプロジェクトに最初から用意されているMainMenu.xibには何が定義されているのか。それがわかれば、nibの読み込み時の処理がつかめるかもしれない。

xibの基礎構造

xibファイルはそもそもXMLである(xib = XML Interface Builderの頭文字)。必要な定義が全て記述されており、そのままでは解析するにも膨大であることから、分解して小分けにした。

まず、Interface Builder上のDocument Outlineから以下のオブジェクトを取り除いていく。

  • MainMenu(NSMenuのインスタンス)
  • window(NSWindowのインスタンス)
  • AppDelegate(NSObjectのサブクラスAppDelegateのインスタンス)
  • Font Manager(NSFontManagerのインスタンス)

この状態にすると142KBもあったMainMenu.xibが4KBになっており、いかに定義が多かったかがわかる。

この状態でMainMenu.xibを開くと次のXMLが記述されている。(要約と整形をしています)

MainMenu.xib
<?xml version="1.0" encoding="UTF-8"?>
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="8.00">
	<data>
		<int          key="IBDocument.SystemTarget">1080</int>
		<string       key="IBDocument.SystemVersion">11D50</string>
		<string       key="IBDocument.InterfaceBuilderVersion">2457</string>
		<string       key="IBDocument.AppKitVersion">1138.32</string>
		<string       key="IBDocument.HIToolboxVersion">568.00</string>
		<object     class="NSMutableDictionary" key="IBDocument.PluginVersions"></object>
		<array        key="IBDocument.IntegratedClassDependencies"></array>
		<array        key="IBDocument.PluginDependencies"></array>
		<object     class="NSMutableDictionary" key="IBDocument.Metadata"></object>
		<array      class="NSMutableArray"      key="IBDocument.RootObjects" id="1048"></array>
		<object     class="IBObjectContainer"   key="IBDocument.Objects"></object>
		<object     class="IBClassDescriber"    key="IBDocument.Classes"/>
		<int          key="IBDocument.localizationMode">0</int>
		<string       key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
		<bool         key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
		<int          key="IBDocument.defaultPropertyAccessControl">3</int>
		<dictionary class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes"></dictionary>
		<bool         key="IBDocument.UseAutolayout">YES</bool>
	</data>
</archive>

Versionsに関する記述はさほど重要では無いので、IBDocument.IntegratedClassDependencies以降の行で何を定義しているかを調べてみる。

IBDocument.IntegratedClassDependencies

MainMenu.xib
<array key="IBDocument.IntegratedClassDependencies">
	<string>NSCustomObject</string>
</array>

直訳するとIntegrated Class Dependenciesは統合クラスの依存関係。Interface Builder内で定義された各インスタンスのクラスについて記述しているのだろうか。これはMac Developer Libraryには載っていない。

数々のオブジェクトを取り除く前はこう。

MainMenuOriginal.xib
<array key="IBDocument.IntegratedClassDependencies">
	<string>NSWindowTemplate</string>
	<string>NSView</string>
	<string>NSMenu</string>
	<string>NSMenuItem</string>
	<string>NSCustomObject</string>
</array>

ここで確認できるNSWindowTemplateNSCustomObjectといったクラスも公開されていない。

IBDocument.PluginDependencies

MainMenu.xib
<array key="IBDocument.PluginDependencies">
	<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
</array>

次はプラグインの依存関係。CocoaPluginはInterface Builder Pluginのことで/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Interface Builder/Plug-insに格納されていた。おそらくウインドウ右下のObject libraryパレットに表示されている内容のことだろう。

IBDocument.Metadata

MainMenu.xib
<object class="NSMutableDictionary" key="IBDocument.Metadata">
	<string key="NS.key.0">PluginDependencyRecalculationVersion</string>
	<integer value="1" key="NS.object.0"/>
</object>

これは様々なメタデータが格納されるようだが、あまり重要では無さそうだ。

IBDocument.RootObjects

ここからどうも具体的な定義に入っているようだ。冒頭でオブジェクトを取り除かない場合、ここには非常の多くの記述が集中する。今回は全て取り除いたのでとても短い。

MainMenu.xib
<array class="NSMutableArray" key="IBDocument.RootObjects" id="1048">
	<object class="NSCustomObject" id="1021">
		<string key="NSClassName">NSApplication</string>
	</object>
	<object class="NSCustomObject" id="1014">
		<string key="NSClassName">FirstResponder</string>
	</object>
	<object class="NSCustomObject" id="1050">
		<string key="NSClassName">NSApplication</string>
	</object>
</array>

NSApplicationが2度記述されていたりと、まだここだけではよくわからないが、この記述をごっそり削除してからXcode上で開いてみるとその正体がわかる。

Xcodeは次のようなエラーを出してきた。

The document "MainMenu.xib" could not be opened. This archive contains a reference to an object with the identifier "1048" but does not contain an object with a matching identifier.

ここで'the identifier "1048" but does not contain'と言っている点に注目。どこかに対応する記述があるということか。

IBDocument.Objects

MainMenu.xib
<object class="IBObjectContainer" key="IBDocument.Objects">
	<array class="NSMutableArray" key="connectionRecords"/>
	<object class="IBMutableOrderedSet" key="objectRecords">
		<array key="orderedObjects">
			<object class="IBObjectRecord">
				<int key="objectID">0</int>
				<array key="object" id="0"/>
				<reference key="children" ref="1048"/>
				<nil key="parent"/>
			</object>
			<object class="IBObjectRecord">
				<int key="objectID">-2</int>
				<reference key="object" ref="1021"/>
				<reference key="parent" ref="0"/>
				<string key="objectName">File's Owner</string>
			</object>
			<object class="IBObjectRecord">
				<int key="objectID">-1</int>
				<reference key="object" ref="1014"/>
				<reference key="parent" ref="0"/>
				<string key="objectName">First Responder</string>
			</object>
			<object class="IBObjectRecord">
				<int key="objectID">-3</int>
				<reference key="object" ref="1050"/>
				<reference key="parent" ref="0"/>
				<string key="objectName">Application</string>
			</object>
		</array>
	</object>
	<dictionary class="NSMutableDictionary" key="flattenedProperties">
		<string key="-1.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
		<string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
		<string key="-3.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
	</dictionary>
	<dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
	<nil key="activeLocalization"/>
	<dictionary class="NSMutableDictionary" key="localizations"/>
	<nil key="sourceID"/>
	<int key="maxID">535</int>
</object>

いた。 <reference key="children" ref="1048"/>という記述がある。ここが互いに対応している。

ここでは、Interface Builder上では削除できないFile's Owner, First Responder, Applicationという見慣れた表記が見つかる。File's OwnerはNSApplicationクラス、Application自体ももちろんNSApplicationクラスなので、上で2度記述されていたのも納得できる。

flattenedProperties以下にはInterface Builder特有であろう表記が見える。

疑問

ここでInterface Builder上でオブジェクトを追加したらxibにはどう反映していくのだろうか?

次回は、Interface Builder上の操作にxibがどう反映していくか調べていきます。

リンク

Discussion