当前位置: 首页 > 知识库问答 >
问题:

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

黄弘盛
2023-03-14

众所周知,创建NSDate格式器是“昂贵的”

甚至苹果的数据格式指南(2014-02年更新)也指出:

创建日期格式化程序并不是一项廉价的操作。如果您可能经常使用格式化程序,缓存单个实例通常比创建和处理多个实例更有效。一种方法是使用静态变量。

但该文档似乎并不是swift的最新版本,我在最新的NSDateFormatter类参考中也找不到任何关于缓存格式化程序的信息,所以我只能假设swift和objective-c的成本一样高。

许多来源建议在类中缓存格式化程序,例如控制器或视图。

我想知道在项目中添加一个singleton类来存储datepicker是否方便甚至更“便宜”,这样您就可以放心,再也不必创建它了。这可以在应用程序的任何地方使用。您还可以创建几个包含多个日期选择器的共享实例。例如,一个日期选择器用于显示日期,另一个用于时间标记:

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 Licks和Lorenzo Rossi指出的,转换格式可能不是一个好主意(不是线程安全的,而且和重新创建一样昂贵..).

共有3个答案

宗政松
2023-03-14

在我看来,缓存 NSDateFormatter 是一个好主意,如果你的应用广泛使用或全面使用你的应用,它将提高你的应用的性能。如果你在1或2个地方需要它,那将不是一个好主意。但是,更改日期格式不是一个好主意,它可能会导致您进入意外情况。(在使用之前,您需要每次跟踪当前格式)

在我的一个应用程序中,我使用了一个具有三个日期格式对象(所有三个都包含三种不同格式)的单例作为属性。并且为每个NSDateForware自定义getter

+ (instancetype)defaultDateManager
{
    static DateManager *dateManager = nil;
    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{
        dateManager                = [[DateManager alloc] init];
    });

    return dateManager;
}

// Custom Getter for short date
- (NSDateFormatter *)shortDate
{
    if (!_shortDateFormatter)
    {
        _shortDateFormatter = [[NSDateFormatter alloc] init];
        [_shortDateFormatter setDateFormat:@"yyyy-MM-dd"]
    }
    return _shortDateFormatter
}

像这样,我也为其他两个实现了自定义getter。

为什么我要实现自定义getter?为什么我在单例初始化期间没有分配NSDateFormatter?

这是因为我不想在一开始就分配它们。我需要在第一次需要时分配它(按需分配)。在我的应用程序中,这三个NSDateFormatters都没有被广泛使用,所以我选择了这样的模式来实现它。(我的应用程序在Objective C中,这就是我在这里使用Objective C代码的原因)

蓟辰沛
2023-03-14

由于Swift使用一次调度方法来创建静态属性,因此以这种方式创建DateForware非常快速和安全。

extension DateFormatter {
    static let shortFormatDateFormatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd"
        formatter.locale = Locale(identifier: "en_US_POSIX")
        return formatter
    }()
}

不仅仅是写作

date = DateFormatter.shortFormatDateFormatter.string(from: json["date"])
公孙宏远
2023-03-14

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

为什么它很好?性能。事实证明,创建NSDate格式实际上很慢。我开发了一个高度本地化的应用程序,并使用了许多NSDate格式以及NS编号格式。有时,我们会在方法中贪婪地动态创建它们,并且具有具有自己所需格式化程序副本的类。此外,我们还有一个额外的负担,在某些情况下,我们还可以在同一屏幕上显示针对不同区域设置本地化的字符串。我们注意到我们的应用程序在某些情况下运行缓慢,在运行仪器后,我们意识到它是格式化程序的创建。例如,我们看到滚动包含大量单元格的表视图时性能受到影响。因此,我们最终通过创建一个出售适当格式化程序的单例对象来缓存它们。

通话内容如下:

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

请注意,这是Obj-C,但等效的可以用Swift制作。刚刚我们的是Obj-C。

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

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

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

我们在一天结束时使用的是单例,它提供特定的格式化程序(NSDateForware和NSNumberForware),确保每个线程本身都有该特定格式化程序的副本(请注意,该应用程序是在iOS7之前创建的,这使得这成为一件至关重要的事情)。这样做提高了我们的应用程序性能,并消除了由于线程安全和格式化程序而导致的一些讨厌的副作用。由于我们有线程字典部分,我从未测试过它,看看没有它在iOS7上是否有任何问题(即它们真的变得线程安全了)。因此,我在上面添加了“如果你愿意”。

 类似资料:
  • 问题内容: 考虑我有如下代码: 假设经常调用。那么建议缓存如下: 就我对java方法引用的理解而言,使用方法引用时,虚拟机会创建一个匿名类的对象。因此,缓存引用只会创建一次该对象,而第一种方法是在每个函数调用上创建该对象。它是否正确? 是应该缓存出现在代码中热门位置的方法引用,还是VM能够对其进行优化并使多余的缓存?是否有一般的最佳实践,或者这种高度VM实现是否特定于这种缓存是否有用? Java

  • 主要内容:什么是应用程序缓存(Application Cache)?,浏览器支持,HTML5 Cache Manifest 实例,实例,Cache Manifest 基础,Manifest 文件,更新缓存,实例 - 完整的 Manifest 文件,关于应用程序缓存的说明使用 HTML5,通过创建 cache manifest 文件,可以轻松地创建 web 应用的离线版本。 注意:manifest 的技术已被 web 标准废弃,不再推荐使用此功能。 什么是应用程序缓存(Application Ca

  • 使用 HTML5,通过创建 cache manifest 文件,可以轻松地创建 web 应用的离线版本。 什么是应用程序缓存(Application Cache)? HTML5 引入了应用程序缓存,这意味着 web 应用可进行缓存,并可在没有因特网连接时进行访问。 应用程序缓存为应用带来三个优势: 离线浏览 - 用户可在应用离线时使用它们 速度 - 已缓存资源加载得更快 减少服务器负载 - 浏览器

  • 我对匕首比较陌生,我刚开始使用剑柄。我想要的是在中注入一个应用程序范围的存储库(这意味着它需要在任何地方都是相同的对象)。存储库将用于检索用户、auth令牌和诸如此类的东西。这是我能找到的最接近的: 这样一切都可以正常工作,使用debug我可以确认每次使用时都注入了相同的实例。问题是第二次调用时(例如,视图被销毁并重新创建)。我不知道我是在科特林一侧犯了什么愚蠢的错误,还是在剑柄一侧犯了什么愚蠢的

  • 我一直在探索构建我的ColdFusion应用程序的不同方法,我正在寻找一些关于提供应用范围UDF的最佳方式的意见。 对于我的每一个应用程序,我通常都会使用一些不属于任何特定对象的额外功能。主要是数据操作。我希望这些功能在我的整个应用程序中都可用,既可以在CFM模板中使用,也可以在应用程序实例化的CFC中使用。 在我看来,有各种各样的方法来实现这一点,但它们都有自己的局限性: > 创建一个基本的Ut