web-dev-qa-db-ja.com

SwiftでNSDateFormatterを作成しますか?

私はSwiftに不慣れで、Objective-Cに慣れていません。誰かがこれをSwiftに変換するのを手伝ってくれませんか?このコードは、Ray WenderlichのiOSのベストプラクティスから入手しました- http:/ /www.raywenderlich.com/31166/25-ios-app-performance-tips-tricks

このコードをどこに配置しますか?グローバル変数でいっぱいのクラスファイルに入れますか?

- (NSDateFormatter *)formatter {
    static NSDateFormatter *formatter;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _formatter = [[NSDateFormatter alloc] init];
        _formatter.dateFormat = @"EEE MMM dd HH:mm:ss Z yyyy"; // Twitter date format
    });
    return formatter;
}
23
John Pollard
  1. 質問のメソッドに直接類似したものを本当に探している場合は、Swift 3で、次のようにすることができます。

    _class MyObject {
    
        // define static variable
    
        private static let formatter: DateFormatter = {
            let formatter = DateFormatter()
            formatter.dateFormat = "EEE MMM dd HH:mm:ss Z yyyy"
            return formatter
        }()
    
        // you could use it like so
    
        func someMethod(date: Date) -> String {
            return MyObject.formatter.string(from: date)
        }
    }
    _

    またはSwift 2:

    _class MyObject {
    
        // define static variable
    
        private static let formatter: NSDateFormatter = {
            let formatter = NSDateFormatter()
            formatter.dateFormat = "EEE MMM dd HH:mm:ss Z yyyy"
            return formatter
        }()
    
        // you could use it like so
    
        func someMethod(date: NSDate) -> String {
            return MyObject.formatter.stringFromDate(date)
        }
    }
    _

    グローバルのようなstaticプロパティは、デフォルト値に対して_dispatch_once_の動作をお楽しみください。詳細については、AppleのSwiftブログの Files and Initialization エントリの最後にある_dispatch_once_の説明)を参照してください。

  2. 日付フォーマッタのベストプラクティスについては、次のことをお勧めします。

    • はい、再度必要になる可能性が高いフォーマッタを不必要に作成および破棄しないことが賢明です。 WWDC 2012ビデオ iOS App Performance:Responsiveness 、Appleは明示的に

      • 日付形式ごとに1つのフォーマッターをキャッシュします。

      • _NSLocale.currentLocaleDidChangeNotification_のオブザーバーをSwift 3(NSCurrentLocaleDidChangeNotification in Swift 2)からNSNotificationCenterを介して追加し、これが発生した場合、キャッシュされたフォーマッタをクリア/リセットします。

      • フォーマットのリセットには再作成と同じくらいのコストがかかるため、フォーマッターのフォーマット文字列を繰り返し変更しないでください。

      結論として、同じ日付フォーマットを繰り返し使用している場合は、可能な限り日付フォーマッターを再利用してください。

    • NSDateFormatterを使用して日付文字列を解析し、Webサービスと交換する(またはデータベースに保存する)場合、_en_US_POSIX_ロケールを使用して、グレゴリオ暦を使用していない可能性のある国際ユーザーの問題を回避する必要があります。 Apple Technical Q&A#148 を参照してください。 (またはiOS 10およびmacOS 10.12では、_ISO8601DateFormatter_を使用します。)

      ただし、dateFormatNSDateFormatter/DateFormatterとともに使用する場合は、現在のロケールを使用して文字列を作成し、エンドユーザーに提示しますが、作成時には_en_US_POSIX_ localを使用します/アプリ内で内部的に使用される、またはWebサービスと交換される解析文字列。

    • ユーザーインターフェイスの日付文字列をフォーマットする場合は、可能であればdateFormatに文字列リテラルを使用しないようにして、文字列をローカライズしてください。可能な場合はdateStyleおよびtimeStyleを使用してください。また、カスタムdateFormatを使用する必要がある場合は、テンプレートを使用して文字列をローカライズしてください。たとえば、_E, MMM d_をハードコーディングするのではなく、Swift 3では、dateFormat(fromTemplate:options:locale:)を使用します。

      _formatter.dateFormat = DateFormatter.dateFormat(fromTemplate: "EdMMM", options: 0, locale: Locale.current)
      _

      またはSwift 2、dateFormatFromTemplate(_:options:locale:)

      _formatter.dateFormat = NSDateFormatter.dateFormatFromTemplate("EdMMM", options: 0, locale: NSLocale.currentLocale())
      _

      これにより、たとえば、米国のユーザーの場合は「Mon、Sep 5」、英国のユーザーの場合は「Mon 5 Sep」が自動的に表示されます。

    • NSDateFormatterは、iOS 7以降とmacOS 10.9以降で実行されている64ビットアプリでスレッドセーフになりました。

58
Rob

Rob が言ったように、DateFormatterを作成するパフォーマンスには注意が必要です。そのWWDCセッションのヒントを使用してください。

私はこれをNSDateとNSDateFormatterの拡張として行っています(Swift 2、3、4でテストされたコード):

extension NSDate {
    func PR2DateFormatterUTC() -> String {
        return NSDateFormatter.PR2DateFormatterUTC.stringFromDate(self)
    }
    //... more formats
}

extension NSDateFormatter {
    fileprivate static let PR2DateFormatterUTC: NSDateFormatter = {
        let formatter = NSDateFormatter()
        let timeZone = NSTimeZone(name:"UTC")
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        formatter.timeZone = timeZone
        return formatter
    }()
    //... more formats
}

使用法:

    let dateStringUTC  = NSDate().PR2DateFormatterUTC()
20
PabloR

私は見つかったシングルトンアプローチ here を適用しようとしました。これにより、アプリケーション内で使用するさまざまな形式でロードできるシングルトンが作成されます。たとえば、formatter.fromDateTime(myString)を使用して、アプリケーションの任意の場所にアクセスできます。

let formatter = FormatterFormats()

class FormatterFormats {
    var dateTime: NSDateFormatter = NSDateFormatter()

    class var sharedInstance:FormatterFormats {
        return formatter
    }

    func fromDateTime(dateString: String) -> NSDate {
        return dateTime.dateFromString(dateString)!
    }

    init() {
        dateTime.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
    }

}
1
Tom Rossi

そのようにして、NSDateFormatteronceTokenを関数の外に移動できます。次に、あなたの例のようにそれを行うことができます:

var theFormatter:NSDateFormatter!
var token: dispatch_once_t = 0
func formatter() ->NSDateFormatter {
    dispatch_once(&token) {
        theFormatter = NSDateFormatter()
        theFormatter.dateFormat = "EEE MMM dd HH:mm:ss Z yyyy"
    }
    return theFormatter

}

しかし David が示唆するように、d ispatch_once singleton question を確認する必要があります。

0
Christian