如何覆盖 NSDate 描述? ..方法调配?

How to override NSDate description? ..Method Swizzling?

如何调用

print(NSDate()) 

而不是收到通常的响应,而是获取我在名为 getString() 的函数中的响应,该函数是 NSDateextension 的一部分。

Here's my extension:

extension NSDate {
    
   //NSDate to String
    public func getString() -> String {
        let dateFormatter = NSDateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss ZZZ"
        dateFormatter.locale = NSLocale.currentLocale()
        
        return dateFormatter.stringFromDate(self)
    }
}

Please, note that I don't want to just use:

NSDate().getString()

I want to override original description of this class.

更新:

So, everything looks like the only option is Method Swizzling, if even possible.

Anyone interested in the bounty?

注意

I'm doing this just for personal growth and to get to understand the concept, not planning on shipping an App using it in this scenario, not even sure right now in what scenarios I could be using it.

根据定义,扩展可以添加功能但不能覆盖它们。 来源:The Swift Programming Language - Extensions

您可以执行协议 CustomStringConvertible 并替换该行为:

extension NSDate : CustomStringConvertible {
   var description: String {
     let dateFormatter = NSDateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss ZZZ"
        dateFormatter.locale = NSLocale.currentLocale()

        return dateFormatter.stringFromDate(self)
  }
}

我很确定这是一个糟糕的、糟糕的、不好的、可怕的想法。但是给你:

extension NSDate {
    private static let dateFormatter = NSDateFormatter()
    private static var once = dispatch_once_t()
    static func swizzleDescription() {
        dispatch_once(&once) {
            dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss ZZZ"
            dateFormatter.locale = NSLocale.currentLocale()

            let originalMethod = class_getInstanceMethod(self, "description")
            let replacementMethod = class_getInstanceMethod(self, "description_terribleIdea")
            method_exchangeImplementations(originalMethod, replacementMethod)
        }
    }

    func description_terribleIdea() -> String {
        return NSDate.dateFormatter.stringFromDate(self)
    }
}

let date = NSDate()
print(date)
NSDate.swizzleDescription()
print(date)

输出:

2016-03-04 22:17:20 +0000
2016-03-04 16:17:20 -0600
import Foundation

extension NSDate: Streamable {
    public func writeTo<Target : OutputStreamType>(inout target: Target) {
        let dateFormatter = NSDateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss ZZZ"
        dateFormatter.locale = NSLocale.currentLocale()

        print("without swizzling", dateFormatter.stringFromDate(self), toStream: &target)
    }
}

let date = NSDate()

print(date) // without swizzling 2016-03-05 00:09:34 +0100

打印'default'/原创行为/使用

print(date.description)

如果您担心在扩展程序中使用打印,只需将其替换为

//print("without swizzling", dateFormatter.stringFromDate(self), toStream: &target)
let str = dateFormatter.stringFromDate(self)
str.writeTo(&target)

您可以在模块中使用相同的 class 名称定义 NSDate 的覆盖。你必须遵循覆盖 NSDate 的指南,这有点乏味(但它至少在操场上有效)

编译器应该在范围内使用您的覆盖而不是基础覆盖:

 public class NSDate:Foundation.NSDate
 {
     override public var description:String { return getString() }

     private var dateValue:NSTimeInterval = Foundation.NSDate().timeIntervalSinceReferenceDate

     override public var timeIntervalSinceReferenceDate:NSTimeInterval { return dateValue }

     override public init()
     { super.init() }

     override public init(timeIntervalSinceReferenceDate ti: NSTimeInterval)
     { 
       super.init()
       dateValue = ti 
     }

     required public init?(coder aDecoder: NSCoder)
     { super.init(coder:aDecoder) }

     //NSDate to String
     public func getString() -> String 
     {
         let dateFormatter = NSDateFormatter()
         dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss ZZZ"
         dateFormatter.locale = NSLocale.currentLocale()
         return dateFormatter.stringFromDate(self) + " This is the Overriden One"
     }
 }

 print("\(NSDate())")

打印:2016-03-04 18:16:22 -0500 这是被覆盖的

请注意,这实际上覆盖了描述变量,而不仅仅是欺骗打印功能。

可以定义您自己的打印版本:

func print(date: NSDate) {
    print(date.getString())
}

extension NSDate {

    //NSDate to String
    public func getString() -> String {
        let dateFormatter = NSDateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss ZZZ"
        dateFormatter.locale = NSLocale.currentLocale()

        return dateFormatter.stringFromDate(self)
    }
}

这两个调用现在将打印相同的内容:

let date = NSDate()
print(date.getString())
print(date)