You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UITableView的cellForRowAt中DateFormatters的使用优化及相关疑问

日期格式化与UITableView性能相关问题

我有一个包含多个cell的UITableView,需要将从API获取的原始日期字符串(格式为yyyy-MM-dd'T'HH:mm:ssX)转换为易读格式MMMM dd, yyyy 'at' hh:mm a展示。目前通过调用convertToDate函数实现转换,已知DateFormatter创建成本较高,结合下方代码,希望解答以下问题:

注:我在UITableView的cellForRowAt方法中调用convertToDate函数

  1. 创建单例类维护唯一DateFormatter实例是否为最佳实践?
  2. 创建并发DispatchQueue保证DateFormatter线程安全是否合理?
  3. 在cellForRowAt中调用该带并发处理的方法是否会导致列表滑动卡顿?
  4. 有没有处理/创建DateFormatter的标准参考资料?

示例代码

下方代码可将2023-12-22T13:17:27Z转换为December 22, 2023 at 01:17 PM

import Foundation

class DateUtils {
    
    static let shared = DateUtils()
    let dateFormatter = DateFormatter()
    
    // Date formatter are not thread safe and adding this to a concurrent queue makes if safer.
    // For table views cells this may have minimal impact and needs to have performance tested in different cases where used.
    private let dateFormatterQueue = DispatchQueue(label: "com.example.dateformatter",
                                                   attributes: .concurrent)
    
    private init(){}
    
    func convertToDate(from date: String,
                       with format: String = "yyyy-MM-dd'T'HH:mm:ssX",
                       to: String = "MMMM dd, yyyy 'at' hh:mm a") -> String? {
        
        var formattedDate: String?
        
        dateFormatter.dateFormat = format
        guard let date = dateFormatter.date(from: date) else {
            return nil
        }
        dateFormatter.dateFormat = to
        
        dateFormatterQueue.sync {
            formattedDate = dateFormatter.string(from: date)
        }
        return formattedDate
    }
}

问题解答

1. 创建单例类维护唯一DateFormatter实例是否为最佳实践?

是,但有前提。DateFormatter的创建和初始化成本确实很高,复用单例能避免重复创建带来的性能损耗。不过要注意:

  • 若需同时处理多种固定格式的日期,更优方案是在单例中维护多个DateFormatter实例(每个对应一种格式),而非反复修改同一个实例的dateFormat——反复修改格式会引入额外开销,还可能因线程问题导致格式混乱。
  • 单例必须保证线程安全,不能在多线程环境下直接修改或调用其方法。

2. 创建并发DispatchQueue保证DateFormatter线程安全是否合理?

你的实现存在隐患,并发队列配合sync调用无法完全保证安全。正确思路是:

  • DateFormatter并非线程安全,任何对它的读写操作都必须在同一个串行队列中执行,或加锁保护。
  • 你的代码中先修改dateFormat再执行转换,属于读写混合操作,用并发队列+sync会有线程竞争风险。更稳妥的方式是用串行队列包裹所有对DateFormatter的操作,确保同一时间只有一个线程访问它。

3. 在cellForRowAt中调用该带并发处理的方法是否会导致列表滑动卡顿?

大概率会。cellForRowAt在主线程执行,代码中的sync调用会阻塞主线程等待队列任务完成。若列表滑动速度快,大量sync调用会让主线程等待,直接引发掉帧、卡顿。

正确做法是提前格式化日期:

  • 在API数据解析完成后,后台线程批量处理所有日期的格式化,将结果存入数据模型,cellForRowAt直接读取格式化好的字符串展示。
  • 若必须在cellForRowAt中处理,需把格式化操作放到后台线程异步执行,完成后切回主线程更新cell,避免阻塞主线程。

4. 有没有处理/创建DateFormatter的标准参考资料?

苹果官方文档有明确的性能与线程安全说明:

  • 线程安全:明确指出DateFormatter非线程安全,所有访问必须在同一线程,或通过同步机制保护。
  • 性能优化:推荐复用DateFormatter实例,避免频繁创建;若需多种格式,维护多个实例而非反复修改格式。
  • 此外,苹果WWDC的性能相关session(如UI性能、后台处理主题)也提到过DateFormatter的优化方案,核心思路是减少创建次数、避免主线程阻塞。

内容的提问来源于stack exchange,提问作者Max

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 16:05:03