AppDelegate 属性还是单例对象?

Posted

技术标签:

【中文标题】AppDelegate 属性还是单例对象?【英文标题】:AppDelegate property or Singleton Object? 【发布时间】:2015-04-18 09:08:26 【问题描述】:

这更像是一个设计最佳实践问题:

当您设计一个基于位置的应用程序的结构时。位置管理器显然是一个重要的实例,应该可以轻松访问其他对象。

您应该将它作为 appDelegate 的属性吗?还是单例?

在哪种情况下,您更喜欢其中一种?

我知道两者都可以,但我想确保我以正确的方式做事,而不仅仅是将所有内容整合在一起。

非常感谢您的意见!

【问题讨论】:

我喜欢我的 appdelegate 类包含的代码很少,所以我更喜欢创建像单例这样的位置管理器 【参考方案1】:

两者都没有。

通过自定义 init 方法或属性传入位置管理器对象,无论您需要什么。

这将符合SOLID principalsS、O 和D(单责任、开闭、依赖倒置)。

还可以更轻松地使用模拟进行测试。

【讨论】:

我看不出它是怎么回事!将其作为具有所有位置管理器责任并使用观察者模式或委托的单例对象既不违反开放-关闭也不违反依赖倒置原则! 当然是紫罗兰色开闭,好像你想使用一个子类而不是你必须改变使用单子的类。而且它显然违反了依赖倒置,因为这表明依赖必须从类外部处理。 对于开闭,是的,一般意义上你是对的,而且我知道单例通常有其问题,人们不喜欢它。但是关于手头的案例,我看到很多教程都以这种方式使用它作为最佳实践,因为你为什么要继承位置管理器?它的职责应该只是获取/观察位置更新。除此之外的任何事情都应该在它之外完成。 许多教程都是可继承的,因为它们专注于他们想要教授的细节。最好的例子是几乎所有的苹果代码,因为它们都与单一责任原则相冲突:视图控制器只实现了一切。 Apple 意识到了这一点,请参阅 wwdc 视频“收藏视图中的进步”或类似内容。 «Advanced User Interfaces with Collection Views»。这段视频揭示了苹果的大部分教程都存在架构问题。虽然它没有命名单例及其处理方法,但它证明了你不应该将教程中的所有内容都视为“最佳实践”——这个流行词对你来说意味着什么。【参考方案2】:

IMO 最糟糕的选择是将内容存储在应用程序委托中。有关更多信息,请参阅What describes the Application Delegate best? How does it fit into the whole concept?。简而言之,应用委托就是应用委托。它不是“全球事物的应用程序垃圾场”。

Singleton 是 ObjC 中一种由来已久的方法,通过 shared... 模式。经过几十年的流行,并在核心 Cocoa 框架中广泛使用(NSUserDefaultsNSNotificationCenterNSApplicationNSFontManagerNSWorkspaceUIDevice 等),它们最近多年来陷入了一些无视其他技术的问题,特别是“依赖注入”,这就是说“分配给一个属性”。

在 ObjC 中使用单例数年之后,我开始转向 DI 的思维方式。可测试性的改进和依赖项清晰度的改进非常好。也就是说,有时 DI 会导致尴尬的过渡,尤其是在处理情节提要时。

所以,我想说:

实际情况下,只需构造对象并将它们分配给需要它们的对象的属性即可。 如果您有很多东西要传递,请考虑将它们收集到一个“配置”对象中并传递(但这会在一定程度上损害模块化)。 如果 DI 造成混乱(特别是如果它导致大量将对象传递给事物,以便他们可以将对象传递给其他事物),或者如果它强制使用大量故事板 segue 代码,否则您可以避免这些代码,单例在 Cocoa 中是一个成熟且受人尊敬的模式,并且没有错。他们是Cocoa Core Competency。 如果您发现自己打电话给(MyAppDelegate *)[[UIApplication sharedApplication] delegate],那么您做错了什么。

【讨论】:

【参考方案3】:

为位置管理制作另一个单例。 Single responsibility 是SOLID 的第一原则。

【讨论】:

又违反了SOLID的O&D 你能解释一下你的意思吗?我真的认为他不应该对 AppDelegate 这样做,因为它还有另一个角色。单一职责原则只是描述了我的想法。 看我的回答。都没有。 我认为位置管理的单例并不违反 O 和 D 原则。它不会修改 CLLocationManager,只是提供对其属性的简单访问并实现一些有用的功能。它不会反向依赖,因为这个单例不依赖于应用程序的任何其他模块。他的功能很简单:配置一个 CLLocationManager 实例(我不知道为什么我需要另一个),关注授权状态并提供对当前位置实例的访问权限。请告诉我为什么这个解决方案不好?我真的很想知道。 单例本身不违反任何 SOLID 原则,从类内部访问它就可以了。 Breyer 的一个例子是使用 nsuserdedaults:当我在课堂上需要它时,我会将它传入,即使我可能总是使用标准默认值。但这让我可以选择传入一个模拟版本进行测试。【参考方案4】:

想想你在 AppDelegate 中真的需要它吗?

例如,对于位置管理器,不,您不需要。您最好将位置管理器及其所有相关方法保存在一个单独的类中,以保持 @vladimir 所说的奇异性原则,并能够在以后重用它。

AppDelegate 负责处理应用启动和/或进入后台时发生的事情、初始化核心数据、注册推送通知和其他 3rd 方库,如 parse、...

向 appDelegate 添加其他东西会使其随着时间的推移变得越来越大,并且很难维护。

什么时候添加不属于 AppDelegate 的东西呢?我认为当应用程序很小的时候,你知道它不会扩大规模,并且你需要优先考虑时间而不是干净的代码。

检查 AppDelegate responsibilities 和 Matt 的 answer

【讨论】:

是的,我完全明白你在说什么。但是其他情况呢?我看到很多人喜欢在 appDelegate 中添加他们所有的 ViewController 和管理器。有必要吗? 那是根据他们添加的内容。如果你有一个例子,我们可以讨论它。但总的来说,在应用程序委托中添加所有内容更容易,我看到一些初学者教程这样做,但这是错误的,它会在你以后维护应用程序时伤害你的理智。所以我的关键是,它是否属于应用程序委托职责?如果是这样添加它,否则永远不会...我将添加链接到答案检查它们【参考方案5】:

您可以创建CLLocationManager 的多个实例,并在需要时使用它们。

如果您创建一个实例并尝试共享它,那么您将无法尝试转发委托方法或尝试将它们重新实现为通知,从而导致一团糟。

【讨论】:

以上是关于AppDelegate 属性还是单例对象?的主要内容,如果未能解决你的问题,请参考以下文章

appdelegate 共享实例委托

iOS之UIApplicatioAppDelegate

向 AppDelegate 添加协议未注册

在AppDelegate 或其它地方用UITabBarController怎么办

在 AppDelegate 中切换 ViewController - 不显示

在哪里存储持久容器(或任何全局对象)? AppDelegate 还是场景委托?