如何将我的 .xib 文件替换为纯 Swift 3?



我正在制作一个只在菜单栏中运行的macOS Cocoa应用程序。当我最初创建项目时,Xcode 给了我一个名为MainMenu.xib的文件。这个MainMenu.xib文件似乎不包含与我的菜单栏应用程序相关的任何内容,所以我希望删除它。

Cocoa入口点,函数NSApplicationMain,"从应用程序的主包加载主笔尖文件"。我在其他地方读到,Cocoa 通过查阅我Info.plist中的键NSMainNibFile找到了"主笔尖文件",该键设置为字符串MainMenu。我删除了密钥NSMainNibFile,我的程序仍然行为相同。由此,我假设Cocoa看到了这个键的缺失,所以它跳过了它的nib/xib加载步骤。

由于我的MainMenu.xib文件不再从任何地方引用,因此我删除了它(从我的project.pbxproj中删除了一些看起来无辜的引用)。但是,删除MainMenu.xib后,我的应用程序不再工作。我的AppDelegate类上的applicationDidFinishLaunching方法没有被调用!

这意味着两件事。首先,这意味着即使 Cocoa 不存在NSMainNibFileCocoa 仍然神奇地找到我的MainMenu.xib文件(如果我将其重命名为Foo.xib,Cocoa 仍然会找到该文件)。更重要的是,这意味着我的应用程序仍然需要MainMenu.xib中的某些内容才能运行。以下是完整的MainMenu.xib

<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11762"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
<connections>
<outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="Foo" customModuleProvider="target"/>
</objects>
</document> 

我认为问题在于我的MainMenu.xib引用了我的AppDelegate类,Cocoa 使用它来实例化AppDelegate类,然后在对象上调用applicationDidFinishLaunching。这很令人困惑,因为我认为AppDelegate课上的@NSApplicationMain注释就足够了。

因此,我有几个问题:

  1. 可可怎么样(即NSApplicationMain) 找到我的MainMenu.xib文件?可可的搜索程序是什么?如何告诉可可跳过此加载步骤?
  2. 我的MainMenu.xib文件在做什么?也就是说,Cocoa 如何解释MainMenu.xib文件,结果又做了什么?具体来说,此文件如何导致我的AppDelegate类被实例化?
  3. 如何在 Swift 3 中纯粹以编程方式重新创建此逻辑,以便删除MainMenu.xib文件?我需要使用哪些 API?

回答问题 #3:

  • 创建一个 Swift 文件main.swift
  • main.swift中的代码替换为

    import Cocoa
    let appDelegate = AppDelegate()
    NSApplication.shared().delegate = appDelegate
    _ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
    
  • 删除AppDelegate中的@NSApplicationMain
  • 删除Info.plist中的键/值对NSMainNibFile
  • 删除 .xib 文件。
  1. XIB 文件的名称存储在 Info.plist 中。 您可以通过选择 Xcode 项目文件并单击"信息"选项卡直接对其进行修改,也可以从"主界面"下的"常规"选项卡进行更改。

  2. 在每个默认的 MainMenu.xib 的顶层都有一个AppDelegate对象。 此对象是接收所有应用委托消息的对象。 它连接到占位符应用程序对象的delegate出口。

  3. 要复制此行为,您需要子类NSApplication并修改目标的"主体类"Info.plist 设置以反映新的子类。 在子类中,可以重写类似finishLaunching()的内容来创建应用委托对象并进行设置。 但是,请记住,在这样做时,您需要确保您的新委托在某处具有强引用,因为它不再归 nib 文件所有。 我建议在你的子类中添加一个强大的属性,也许是像strongDelegate这样的东西。

最新更新