【问题标题】:Use of singleton in IOS and things to watch out forIOS中单例的使用及注意事项
【发布时间】:2016-09-01 13:54:16
【问题描述】:

我一直在广泛使用单例来与类似于以下类的 firebase 进行交互。我发现单例非常方便,所以我想在开始使用它之前对它有更多的了解。一位在线课程的讲师提到我在使用单例时必须非常小心,但他并没有真正解释原因。我想知道如何正确使用它,为什么我需要非常小心地使用它们?

class DataService {
static let dataService = DataService()

private var _BASE_REF = Firebase(url: "\(BASE_URL)")
private var _USER_REF = Firebase(url: "\(BASE_URL)/users")
private var _JOKE_REF = Firebase(url: "\(BASE_URL)/jokes")

var BASE_REF: Firebase {
    return _BASE_REF
}

var USER_REF: Firebase {
    return _USER_REF
}

var CURRENT_USER_REF: Firebase {
    let userID = NSUserDefaults.standardUserDefaults().valueForKey("uid") as! String

    let currentUser = Firebase(url: "\(BASE_REF)").childByAppendingPath("users").childByAppendingPath(userID)

    return currentUser!
}

var JOKE_REF: Firebase {
    return _JOKE_REF
}

另外,我还将创建另一个单例,如下所示(我还没有创建,因为我想先更好地理解它)。这些“帖子”将被多个 VC 访问,这就是为什么我想使用单例以便所有 VC 都可以访问他们需要的任何数组而不会产生任何冲突。一般来说,这种设置有什么需要注意的吗?

抱歉,这个问题可能有点宽泛。但我们的想法是大致了解在这些特定示例中使用 Singleton 的注意事项(内存、分配、计时??)

class PostService {

static let ps = PostService()

private var _myPosts = [Post]()
private var _otherPeoplesPosts = [Post]()
private var _followingPosts = [Post]()

var myPosts: [Post] {
    return _myPosts

}

var otherPeoplesPosts: [Post] {
    return _otherPeoplesPosts
}

var followingPosts: [Post] {
    return _followingPosts
}

【问题讨论】:

  • 如果单例的目的只是为了持久化数据,如果可以使用它们,还有更好的选择,比如核心数据。如果您可以将数据传递到视图控制器而不是使用单例,那就更好了。至于内存管理,它是安全的。如果您重置属性并且您的对象不包含对单例的引用,则不会发生内存泄漏。根据我的经验,当我有某种持续运行的任务或图像缓存等服务时,我只使用单例,每个类都可以使用它并从中受益(UIView、UIViewController、任何模型类/结构等)
  • 图像缓存甚至不是最好的例子,因为我可以创建图像缓存的实例并将它们传递到它们需要的位置。
  • “在应用程序的整个生命周期中,单例携带状态”。这是指手机上应用的生命周期还是应用关闭前的生命周期(前台和后台)。

标签: ios objective-c swift singleton


【解决方案1】:

据我所知,关于单例的唯一主要问题是,无论您是否使用它们,它们都会保留在内存中。

您的第一个单例看起来可以很容易地用具有静态函数的结构替换。

正如其中一个 cmets 所述,使用某种存储(即 CoreData)会更好,因为对象不在堆中(至少不是全部)。 如果您的数组由几十个对象组成,那应该不是问题,但想象每个数组都包含数百个对象。 当然,它可以从应用程序的任何地方访问,但缺点是您的内存使用量会非常高。

如果您不使用 CoreData 并且将其集成到您的项目中会成为问题,请考虑将数据存储到文档文件夹并限制内存中的对象数量以及何时需要访问对象它不在数组中,从文档文件夹中加载它并替换最后使用的对象(有点像 CoreData 所做的)。这并不理想,需要一些严格的逻辑,但总比堆中有太多对象并导致内存警告要好。

归根结底,这取决于数据的使用情况和大小。

希望它在某种程度上有所帮助。

【讨论】: