ios - 缓存 NSDateformatter 应用程序范围的好主意吗?

标签 ios cocoa caching swift nsdatepicker

well已知创建 NSDateFormatters 是 'expensive '

即使是苹果的 Data Formatting Guide (2014-02 更新)指出:

Creating a date formatter is not a cheap operation. If you are likely to use a formatter frequently, it is typically more efficient to cache a single instance than to create and dispose of multiple instances. One approach is to use a static variable.

但该文档似乎并不是真正与 swift 同步的,而且我在最新的 NSDateFormatter Class Reference 中也找不到任何相关信息。关于缓存格式化程序,所以我只能假设它对 swift 和对 objective-c 一样昂贵。

很多来源建议caching使用它的类内部的格式化程序,例如 Controller 或 View 。

我想知道在项目中添加一个单例类来存储日期选择器是否方便甚至“更便宜”,这样您就可以放心,永远不需要再次创建它。这可以在应用程序的任何地方使用。您还可以创建多个包含多个日期选择器的共享实例。例如,一个用于显示日期的日期选择器和一个用于时间符号的日期选择器:

class DateformatterManager {
    var formatter = NSDateFormatter()

    class var dateFormatManager : DateformatterManager {
        struct Static {
            static let instance : DateformatterManager = DateformatterManager()
        }
        // date shown as date in some tableviews
        Static.instance.formatter.dateFormat = "yyyy-MM-dd"
        return Static.instance
    }

    class var timeFormatManager : DateformatterManager {
        struct Static {
            static let instance : DateformatterManager = DateformatterManager()
        }
        // date shown as time in some tableviews
        Static.instance.formatter.dateFormat = "HH:mm"
        return Static.instance
    }

    // MARK: - Helpers
    func stringFromDate(date: NSDate) -> String {
        return self.formatter.stringFromDate(date)
    }
    func dateFromString(date: String) -> NSDate? {
        return self.formatter.dateFromString(date)!
    }
}

// Usage would be something like: 
DateformatterManager.dateFormatManager.dateFromString("2014-12-05")

另一种类似的方法是只创建一个单例并根据需要切换格式:

class DateformatterManager {
    var formatter = NSDateFormatter()

    var dateFormatter : NSDateFormatter{
        get {
            // date shown as date in some tableviews
            formatter.dateFormat = "yyyy-MM-dd"
            return formatter
        }
    }

    var timeFormatter : NSDateFormatter{
        get {
            // date shown as time in some tableviews
            formatter.dateFormat = "HH:mm"
            return formatter
        }
    }

    class var sharedManager : DateformatterManager {
        struct Static {
            static let instance : DateformatterManager = DateformatterManager()
        }
        return Static.instance
    }

    // MARK: - Helpers
    func dateStringFromDate(date: NSDate) -> String {
        return self.dateFormatter.stringFromDate(date)
    }
    func dateFromDateString(date: String) -> NSDate? {
        return self.dateFormatter.dateFromString(date)!
    }
    func timeStringFromDate(date: NSDate) -> String {
        return self.timeFormatter.stringFromDate(date)
    }
    func dateFromTimeString(date: String) -> NSDate? {
        return self.timeFormatter.dateFromString(date)!
    }
}

// Usage would be something like: 
var DateformatterManager.sharedManager.dateFromDateString("2014-12-05")

这些想法是好是坏?转换格式也很昂贵吗?

更新: 作为Hot LicksLorenzo Rossi指出,切换格式可能不是一个好主意(不是线程安全的,而且与重新创建一样昂贵..)。

最佳答案

我会根据经验在这里插话。答案是肯定的,在整个应用程序范围内缓存 NSDateFormatter 是一个好主意,但是,为了增加安全性,您需要为此采取一个步骤。

为什么好?表现。事实证明,创建 NSDateFormatters 实际上很慢。我开发了一个高度本地化的应用程序,并使用了很多 NSDateFormatters 和 NSNumberFormatters。有时我们会在方法中贪婪地动态创建它们,并让类拥有自己所需的格式化程序副本。此外,在某些情况下,我们还可以在同一屏幕上显示针对不同区域设置本地化的字符串,这给我们带来了额外的负担。我们注意到我们的应用程序在某些情况下运行缓慢,在运行 Instruments 后,我们意识到这是格式化程序创建。例如,当滚动包含大量单元格的 TableView 时,我们看到了性能下降。因此,我们最终通过创建一个提供适当格式化程序的单例对象来缓存它们。

调用看起来像这样:

NSDateFormatter *dateFormatter = [[FormatterVender sharedInstance] shortDate];

请注意,这是 Obj-C,但可以在 Swift 中创建等效项。碰巧我们的在 Obj-C 中。

从 iOS 7 开始,NSDateFormatters 和 NSNumberFormatters 是“线程安全的”,但是正如 Hot Licks 所提到的,如果另一个线程正在使用它,您可能不想四处修改格式。另一个用于缓存它们的 +1。

我刚刚想到的另一个好处是代码的可维护性。特别是如果您拥有像我们这样的大型团队。因为所有开发人员都知道有一个出售格式化程序的集中对象,所以他们可以简单地查看他们需要的格式化程序是否已经存在。如果没有,则会添加。这通常与功能相关,因此通常意味着其他地方也需要新的格式化程序。这也有助于减少错误,因为如果格式化程序中恰好有错误,您可以在一个地方修复它。但我们通常会在新格式化程序的单元测试期间发现这一点。

如果需要,您还可以添加一个元素来确保安全。您可以使用 NSThread 的 threadDictionary 来存储格式化程序。换句话说,当您调用将出售格式化程序的单例时,该类会检查当前线程的 threadDictionary 以查看该格式化程序是否存在。如果它存在,那么它只是返回它。如果没有,它创建它然后返回它。这增加了一个安全级别,所以如果出于某种原因你想修改你的格式化程序,你可以这样做而不必担心格式化程序正在被另一个线程修改。

我们在一天结束时使用的是单例,它提供特定的格式化程序(NSDateFormatter 和 NSNumberFormatter),确保每个线程本身都有它自己的特定格式化程序的副本(注意该应用程序是在 iOS 7 之前创建的,它使那成为必不可少的事情)。这样做提高了我们的应用程序性能,并消除了我们因线程安全和格式化程序而遇到的一些令人讨厌的副作用。因为我们有 threadDictionary 部分,我从来没有测试过它,看看如果没有它我们在 iOS7+ 上是否有任何问题(即它们真的变成了线程安全的)。因此,为什么我在上面添加了“如果你想要”。

关于ios - 缓存 NSDateformatter 应用程序范围的好主意吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27321993/

相关文章:

ios - 如何设置自动布局约束常数通用或设备特定?

list - 在flift中缓存两个列表

asp.net - 缓存是客户端还是服务器端?

php - 如何在 IE (PHP) 中下载服务器文件的更新版本?

ios - ScrollView 手势识别器吃掉所有的触摸事件

ios - 推送通知以进行即时消息传递

macos - 如何实现 OSX 的 UITableView 行为/外观?

objective-c - 为什么 Apple header 没有 NSError** 参数的 __autoreleasing?

objective-c - NSMutableDictionary 不采用键/值对

iphone - UIButton 在被选中时设置为黑色(我想避免这种情况)