swiftgenericsprotocolsprotocol-extension

Swift generics extension to multiple classes


So I want to add a generic extension to NSNumber,Int,Double and Float where the value is converted to a formatted String.

I started by creating a custom protocol:

protocol MyFormatConvertible {
    var toMyFormat: String { get }
}
extension NSNumber: MyFormatConvertible {}
extension Double: MyFormatConvertible {}
extension Float: MyFormatConvertible {}
extension Int: MyFormatConvertible {}

Now I'm trying to add the formatting to the extension:

extension MyFormatConvertible {
    public var toMyFormat: String {
        let numberValue = NSNumber(value:self)
    ....

But this doesn't seem to work as I'm getting the error:

Cannot invoke initializer for type 'NSNumber' with an argument list of type '(value: Self)'

Any hints on how to tackle this?


Solution

  • There are several overloads for NSNumber(value:) for the various number types, but there is no generic NSNumber(value:) constructor.

    A possible workaround could be to use the

    func string(for obj: Any?) -> String?
    

    function of the "abstract" superclass Formatter of NumberFormatter which accepts any type of argument (but might return nil):

    protocol MyFormatConvertible {
        var toMyFormat: String { get }
    }
    
    extension MyFormatConvertible {
        var toMyFormat: String {
            let formatter = NumberFormatter()
            formatter.numberStyle = .spellOut // <-- Just for demonstration purposes!!
            return formatter.string(for: self) ?? "\(self)"
        }
    }
    
    extension NSNumber: MyFormatConvertible {}
    extension Double: MyFormatConvertible {}
    extension Float: MyFormatConvertible {}
    extension Int: MyFormatConvertible {}
    
    print(123.toMyFormat) // one hundred twenty-three
    print(Float.pi.toMyFormat) // three point one four one five nine two five zero two five nine three nine nine