我是编写单例的新手,我必须为当前的 iOS 项目使用一个。要求之一是它可以被杀死。我知道这违背了单例的设计,但这是应该/可以做的事情吗?
7 回答
当然可以,但是如果您正在寻找一个可以创建,然后在不需要时释放的对象……这听起来像是一个常规对象。:)
通常单例控制自己的生命周期。你会在这里得到片面的讨论,除非你更多地说明这两个要求(一个,你使用一个单例,两个,它可以随意释放),以及为什么它们都对你的情况有意义。
这可能是因为单例包装了一些其他固有的独特资源(如文件资源或网络连接)。如果这是真的,那么通常单例是该资源的“管理者”,您将通过单例的接口公开对该资源的控制。
或者这可能是因为单例对象持有大量内存(某种缓冲区),并且您希望确保在必要时对其进行刷新。如果是这种情况,那么您可以根据需要对其创建和释放内存的每个方法更聪明,或者您可以让单例侦听低内存系统通知并适当地表现。
从本质上讲,我很难构建一个案例,让单例对象本身被释放是真正有意义的。单个基本对象只占用内存中的少量字节,并且闲逛不会伤害任何人。
几乎我写过的每一个单例(除了完全以 UI 为中心的控制器)最终都被重构为不是单例。每一个。单身的。一。
因此,我已经停止写单例了。我编写了在实例中维护状态的类,就像任何普通类一样,并且与其他实例隔离。如果它们是通知重的,它们总是self
作为通知对象传递。他们有代表。他们保持内部状态。他们避免真正的全局状态之外的全局变量。
而且,通常,我的应用程序中可能只有一个所述类的实例。这个实例就像一个单例,事实上,我什至可以创建一种方便的方法来获取它,可能是通过应用程序的委托或通过类方法(sharedInstance
有时甚至可能被命名)。
所述类包括通常分为两部分的拆解代码;保持当前状态以便稍后恢复的代码和释放实例相关资源的代码。
像单身一样方便。准备好在需要时进行多次实例化。
我知道这违背了单例的设计
它也违背了 Objective-C 中通常的内存管理模式。通常,一个对象可以保留另一个对象以防止它被销毁,并释放它以允许该对象被销毁。然而,明确地销毁一个对象并不是其他对象可以做的事情。
考虑如果对象 A 获得单例类 S 的共享实例 S1 会发生什么。如果 A 保留 S1,即使某个类方法释放 S 并将指向共享实例的全局变量设置为 nil,S1 仍将继续存在。当该类稍后创建一个新的共享实例 S2 时,将有两个 S 实例,即 S1 和 S2。这首先违反了定义单例的属性。
您可能可以通过覆盖-retain
甚至 swizzling来解决这个问题-release
,但这似乎很复杂,要解决一个原本不应该存在的问题。
一种可能的替代方法是重置您的共享对象,而不是尝试销毁它。如果需要,您可以将其所有属性设置为某个已知(可能无效)的状态,然后使用类方法重新初始化共享对象。请注意所有这些对可能使用共享对象的任何对象的影响。
好没问题。你提供了一个新的类方法:[MyClass killSingleton]; 该方法释放单例并将其内部引用设置为 nil。下次有人问 [MyClass sharedSingleton] 时,您将按照之前创建它的相同步骤进行操作。
编辑:实际上,在过去,这样的例程可能会覆盖release
选择器,并且拒绝消失。因此,正如下面的第一条评论所述,这是一个具有静态作用域的对象——它通过一个静态变量保持活动状态,保持对象的保留计数为 1。但是,通过添加一个新的类方法来消除该 ivar(在 ARC 下),从而释放它,可以达到预期的结果。对静态对象的实例化和释放的控制完全通过类方法完成,因此易于维护和调试。
这与 Singleton 的概念背道而驰,但是对于基于 ARC 的项目,它可以通过以下方式实现
//ARC
@interface Singleton : NSObject
+ (Singleton *)sharedInstance;
+ (void)selfDestruct;
@end
@implementation Singleton
static Singleton *sharedInstance = nil;
+ (Singleton *)sharedInstance {
if (sharedInstance == nil) {
sharedInstance = [[Singleton alloc] init];
}
return sharedInstance;
}
+ (void) selfDestruct {
sharedInstance = nil;
}
@end
//This can be implemented using bool variable. If bool no create new instance.
@interface Singleton : NSObject
+ (Singleton *)sharedInstance;
@end
@implementation Singleton
static Singleton *sharedInstance = nil;
+ (Singleton *)sharedInstance {
if (!keepInstance) {
sharedInstance = [[Singleton alloc] init];
keepInstance = YES;
}
return sharedInstance;
}
@end
我需要清除单例,所以我最终做了以下事情:
- (void)deleteSingleton{
@synchronized(self) {
if (sharedConfigSingletone != nil) {
sharedConfigSingletone = nil;
}
}
}
希望能帮助到你。