Search code examples
swiftgeneric-programming

Cannot convert value of type NSNumber to expected argument type NSNumber


I am getting the error in the title when trying to use the argument of a generic function inherited from a base class

Base class:

BaseBottomBar: UIView {
    ...
    func formatDetailText<T>(value: T...) {
        assertionFailure("You shouldn't be using this base class")
    }
}

Child class:

NewTicketBottomBar: BaseBottomBar {

    override func formatDetailText<NSNumber>(value: NSNumber...) {
        let priceAsCurrencyString = NumberFormatter.currencyFormatter.string(from: value[1]) //Error on this line
        assert(priceAsCurrencyString != nil, "The price cannot be nil")
        let newTicketText = String(format: "%4.0f", value[0]) + " / TOTAL : " + priceAsCurrencyString!
        detailLabel.text = newTicketText
    }
}

Cannot convert value of type NSNumber to expected argument type NSNumber

I guess I have my base method prototype wrong in some way but I can't see how.

I wasn't using a generic method in the beginning and the prototype was the following:

func formatDetailText(value: Double...) {
    ...
    let priceAsCurrencyString = NumberFormatter.currencyFormatter.string(from: NSNumber(value: value[1]))
    ...
}

And this was working fine

Any help would be appreciated


Solution

  • You seem to think that

    override func formatDetailText<NSNumber>(value: NSNumber...) {
    

    resolves the generic <T> in the overridden method as NSNumber. It doesn't. It merely introduces a different name for the generic; NSNumber here is not the NSNumber class, it's just another generic placeholder name, exactly like T (in fact, it is T by another name).

    So naturally, when you try to use this placeholder where an NSNumber is expected in NumberFormatter's string(from:), the compiler turns around and says, "Dude [the compiler is from California, this is how it talks], I have no reason to think that your placeholder called "NSNumber" is in fact NSNumber."

    You need to give it a reason to think that. What you probably mean is

    override func formatDetailText<T>(value: T...) where T : NSNumber {