如何在Swift中创建带参数的单例:

3

我有以下的类:

class FeedDataManager: URLManagerdelegate {

let TAG: String = "FeedDataManager"

weak var mDelegate: KeyboardViewController?

var mModelManager: ModelManager!
var mURLManager: UrlManager!
var mGetNewsTimer: NSTimer?

var mFeedsArray: Array<News>!

var mManagedObjectContext: NSManagedObjectContext!
var mPersistentStoreCoordinator: NSPersistentStoreCoordinator!
var mManagedObjectModel: NSManagedObjectModel!

class var sharedInstance: FeedDataManager {
    struct Static {
        static var onceToken: dispatch_once_t = 0
        static var instance: FeedDataManager? = nil
    }

    dispatch_once(&Static.onceToken) {
        Static.instance = FeedDataManager()
    }
    return Static.instance!
}

init (aDelegate: KeyboardViewController) {
    self.mDelegate = aDelegate
}
}
问题:如果您查看init方法,您将看到它应该接收一个委托指针作为参数,我想将其存储在单例中,因此基本上我需要将此参数传递到此行:
Static.instance = FeedDataManager()

但我不知道如何实现,有人知道怎么做吗?

顺便说一下:我看到了这个链接: Singleton and init with parameter 但那里的单例创建方式不同。


дҪ йңҖиҰҒеңЁsharedInstanceж–№жі•дёӯж·»еҠ зӣёеҗҢзҡ„еҸӮж•°пјҢжҲ–иҖ…еғҸе…¶д»–й—®йўҳжүҖеҒҡзҡ„йӮЈж ·ж·»еҠ дёҖдёӘвҖңsetupвҖқж–№жі•гҖӮ - rmaddy
我发的链接没有使用dispatch_once方法。而且在进行两阶段初始化时,你首先必须运行设置方法,然后才能获取实例(这是一个巨大的错误源)。我希望能一步完成。 - Emil Adz
@EmilAdz,你回答了我删除的评论。请看我的新评论。 - rmaddy
@rmaddy 我不想使用setup方法,正如我所说的。参数如何传递给sharedInstance方法? - Emil Adz
就像你给任何方法添加参数一样,将参数添加到方法签名中。 - rmaddy
@Rob,非常感谢您的评论,您在我的公司发表的第一条评论和小讨论使我明白了我的方法是错误的。您可以将这些评论作为答案提供给我接受。 - Emil Adz
1个回答

10
我们可以向您展示如何在单例声明中添加参数,但这并不是一个好主意。单例背后的整个思想是,无论在哪里实例化它,您都可以在任何地方使用它。如果您在代码中的两个不同位置调用此单例,并带有不同的参数,那么这意味着什么?您将面临竞态条件,行为可能会因单例首次遇到的位置和方式而有所不同。
无关紧要的是,dispatch_once是多余的。静态变量已经与dispatch_once一起使用了。请参见http://developer.apple.com/swift/blog/?id=7末尾的讨论(这主要是针对全局变量的,但他们在括号中指出,它也适用于静态变量)。另外,在Swift 1.2中,我们现在可以拥有静态类变量,也消除了对结构体的需要。

如果你想从你的应用程序中提取一些代码,比如处理网络调用的组件。这些组件很可能会使用来自配置文件的 url(因为每次都必须将 url 作为参数传递是冗余的)。 现在你想将这个组件拿出来制作成一个框架,以便在其他地方重复使用它,你需要为每个应用程序更改该 url,并且每次都要子类化它的话,我认为这是多余的,我没有看到比使用带参数的单例更简单的方法(因为该组件已经是一个单例)。 - thibaut noah
我能理解直觉上的考虑,但是对于单例来说添加一个参数会抵消这个设计。在你的示例中,你计划在每次引用单例时都传递一个 URL 参数吗?如果你想要实现类似单例的功能,我建议你不要使用真正的单例模式,而是使用一个简单的 static 变量,并初始化它一次(例如,不要称其为 shared,而应该称之为 current 并且只实例化一次)。或者进行子类化/封装。或者将配置参数作为类的一个简单属性。或者采用真正的依赖注入。有很多种方法,但不能使用带参数的单例模式。 - Rob
如果您第二次调用,应该得到第一次创建的相同实例。这就是单例的全部意义。 - Clive Jefferies
1
@CliveJefferies - 当然。我的观点只是OP关于向单例添加参数的问题是一个“非续集”的问题。我个人会将需要设置的任何内容作为独立属性保留,并相应地设置它们。例如,如果MOC由应用程序委托设置,那么您可以在应用程序委托中执行类似FeedDataManager.shared.mManagedObjectContext = ...的操作,而不是将它们添加为单例初始化的参数。或者更好的方法是将这个MOC的东西从应用程序委托中移出,并将其移到Singleton的“init”方法中,从而完全消除这个问题。 - Rob

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接