4

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?

Tal Zion
  • 6,308
  • 3
  • 50
  • 73
Lefteris
  • 14,550
  • 2
  • 56
  • 95

2 Answers2

4

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
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • I actually wanted to us Numberformatter in that function (I want to format the number as currency with a currency symbol). – Lefteris Nov 21 '17 at 08:32
  • @Lefteris: There is a NumberFormatter in that function, which you can configure according to your needs. `numberStyle = .spellOut` was just an example, replace it with `numberStyle = .currency` – Martin R Nov 21 '17 at 08:34
  • Martin, this seem to work with `NSNumber`,`Double` and `Int`, but not with `Float`. I'm getting a compiler error: `Type 'Float' does not conform to protocol 'MyFormatConvertible'` – Lefteris Nov 21 '17 at 08:38
  • @Lefteris: Did you add `extension Float: MyFormatConvertible {}`? – The above code is an exact copy of my (working) test program. – Martin R Nov 21 '17 at 08:39
  • Martin I had. For some reason after cleaning the project it did compile. Doesn't make sense, but it's working. Thank you that solved my problem – Lefteris Nov 21 '17 at 08:48
2

You can simply use String(describing: self) to achieve that.

protocol MyFormatConvertible {
    var toMyFormat: String { get }
}

extension MyFormatConvertible {

    var toMyFormat: String {
      return String(describing: self)
   }
}

extension NSNumber: MyFormatConvertible {}
extension Double: MyFormatConvertible {}
extension Float: MyFormatConvertible {}
extension Int: MyFormatConvertible {}

print(1.toMyFormat)
print(1.2.toMyFormat)
print(1.234.toMyFormat)
print(NSNumber(value: 1.23456).toMyFormat)
Tal Zion
  • 6,308
  • 3
  • 50
  • 73
  • This is neat. However, this is essentially the same as merely calling `String(describing: )` to numbers, just in functional way. – Hexfire Nov 21 '17 at 08:25