gpt4 book ai didi

swift - Swift 和 Interface Builder 中的单例

转载 作者:搜寻专家 更新时间:2023-10-31 22:04:07 24 4
gpt4 key购买 nike

背景

我的应用程序中有一个单例类,根据 this blog post 中的一行单例(带有私有(private) init())声明。 .具体来说,它看起来像这样:

@objc class Singleton {
static let Singleton sharedInstance = Singleton()
@objc dynamic var aProperty = false

private init() {
}
}

我想将 aProperty 的状态绑定(bind)到菜单项是否隐藏。

我是如何尝试解决问题的

以下是我执行此操作所遵循的步骤:

  1. 转到 Interface Builder 中的对象库,然后将通用“对象”添加到我的应用程序场景。在身份检查器中,将“类”配置为 Singleton

  2. 通过按住 Ctrl 从 Interface Builder 中的单例对象拖动到我的 App Delegate 代码,在我的 App Delegate 中创建一个引用导出。它最终看起来像这样:

@IBOutlet weak var singleton: Singleton!
  1. 转到菜单项的绑定(bind)检查器,在“可用性”下选择“隐藏”,选中“绑定(bind)到”,在其前面的组合框中选择“Singleton”,然后键入 aProperty 在“模型关键路径”下。

问题

不幸的是,这不起作用:更改属性对相关菜单项没有影响。

调查原因

问题似乎是,尽管将 init() 声明为私有(private),但 Interface Builder 正在设法创建我的单例的另一个实例。为了证明这一点,我将 NSLog("singleton init") 添加到私有(private) init() 方法,并将以下代码添加到 applicationDidFinishLaunching() 在我的应用委托(delegate)中:

NSLog("sharedInstance = \(Singleton.sharedInstance) singleton = \(singleton)")

当我运行该应用程序时,日志中会输出以下内容:

singleton init
singleton init
sharedInstance = <MyModule.Singleton: 0x600000c616b0> singleton = Optional(<MyModule.Singleton: 0x600000c07330>)

因此,确实存在两种不同的情况。我还在我的应用程序委托(delegate)中的其他地方添加了这段代码:

NSLog("aProperty: [\(singleton!.aProperty),\(String(describing:singleton!.value(forKey: "aProperty"))),\(Singleton.sharedInstance.singleton),\(String(describing:Singleton.sharedInstance.value(forKey: "aProperty")))] hidden: \(myMenuItem.isHidden)")

有一次,这会产生以下输出:

aProperty: [false,Optional(0),true,Optional(1)] hidden: false

显然,作为一个单例,所有值都应该匹配,但是 singleton 产生一个输出而 Singleton.sharedInstance 产生一个不同的输出。可以看出,对 value(forKey:) 的调用与其各自的对象相匹配,因此 KVC 应该不是问题。

问题

我如何在 Swift 中声明一个单例类并将其与 Interface Builder 连接起来以避免它被实例化两次?

如果这不可能,我还能如何解决将全局属性绑定(bind)到 Interface Builder 中的控件的问题?

是否需要 MCVE?

我希望描述足够详细,但如果有人觉得 MCVE 是必要的,请发表评论,我会创建一个并上传到 GitHub。

最佳答案

我只是想通过说明单例不应该用于共享全局状态来开始我的回答。虽然它们在开始时看起来更容易使用,但它们往往会在以后产生很多麻烦,因为它们几乎可以从任何地方更改,有时会使您的程序变得不可预测。

话虽这么说,实现您的需求并非不可能,但需要一点仪式感:

@objc class Singleton: NSObject {
// using this class behind the scenes, this is the actual singleton
class SingletonStorage: NSObject {
@objc dynamic var aProperty = false
}
private static var storage = SingletonStorage()

// making sure all instances use the same storage, regardless how
// they were created
@objc dynamic var storage = Singleton.storage

// we need to tell to KVO which changes in related properties affect
// the ones we're interested into
override class func keyPathsForValuesAffectingValue(forKey key: String) -> Set<String> {
switch key {
case "aProperty":
return ["storage.aProperty"]
default: return super.keyPathsForValuesAffectingValue(forKey: key)
}

}

// and simply convert it to a computed property
@objc dynamic var aProperty: Bool {
get { return Singleton.storage.aProperty }
set { Singleton.storage.aProperty = newValue }
}
}

关于swift - Swift 和 Interface Builder 中的单例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54400618/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com