0

I have an extension that sets bold to a String.

extension NSAttributedString {
    convenience init(format: NSAttributedString, makeBold: [String], regularText: [String]) {
        let mutableString = NSMutableAttributedString(attributedString: format)
        
        makeBold.forEach { string in
            let range = NSString(string: mutableString.string).range(of: "%bold%")
            let attributedString = NSAttributedString(string: string, attributes: [.font: UIFont.openSans(style: .bold, size: 15)])
            mutableString.replaceCharacters(in: range, with: attributedString)
            
        }
        
        regularText.forEach { text in
            let textRange = NSString(string: mutableString.string).range(of: "%regular%")
            mutableString.replaceCharacters(in: textRange, with: text)
        }
        self.init(attributedString: mutableString)
    }
}

It works fine, but I need the regularText: [String] to be able to accept [NSAttributedString]. I tried to do it like this:

convenience init<T>(format: NSAttributedString, makeBold: [String], regularText: [T])

but this gives me an error here:

mutableString.replaceCharacters(in: textRange, with: text)

with the error text

No exact matches in call to instance method 'replaceCharacters(in:with:)'

Not being too familiar with generics I'm not sure how to make this work. Any help would be appriciated.

I read here No exact matches in call to instance method error message in Swift

that it's a general error for using the wrong type, so I guess I havn't gotten generics right.

EDIT If I change regularText type from String to NSAttributedString it works without any errors, so why doesn't a generic work for both?

Joakim Sjöstedt
  • 824
  • 2
  • 9
  • 18
  • Do I understand correctly that you are trying to make a regular `String` bold? That's not how it works. `String` does not have formatting, it's just a series of unicode scalars representing characters. It doesn't carry any information about how should it be displayed. – mag_zbc Aug 27 '20 at 08:31
  • It's an extension for NSAttributedString so not a regular String. The extension works, it's just the generic part I need help with. – Joakim Sjöstedt Aug 27 '20 at 08:36
  • You should focus on **what** you want to do, not **how**. What do you want to do? The part "It works fine, but I need the regularText: [String] to be able to accept [NSAttributedString]. I tried to do it like this:" describes your attempt on solving your problem, but does not say what are you actually trying to achieve. – mag_zbc Aug 27 '20 at 08:38
  • [What is XY problem?](http://xyproblem.info/) – mag_zbc Aug 27 '20 at 08:45

1 Answers1

1

UPDATE (see comments): Add another convenience init

convenience init(format: NSAttributedString, makeBold: [String], regularText: [NSAttributedString]) {
    self.init(format: format, makeBold: makeBold, regularText: regularText.map{ $0.string })
}

OR Just add another convenience init

convenience init(format: NSAttributedString, makeBold: [String], regularText: [NSAttributedString]) {
    self.init(format: format, makeBold: makeBold, regularText: regularText.asStringArray)
}

and an extension like this

extension Array where Element: NSAttributedString {
    var asStringArray: [String] {
        var strings: [String] = []
        
        self.forEach { text in
            strings.append(text.string)
        }
        
        return strings
    }
}
Roman Ryzhiy
  • 1,540
  • 8
  • 5
  • 1
    `convenience... { self.init(format: format, makeBold: makeBold, regularText: regularText.map{ $0.string }) }` would be simpler than using a extension `asStringArray`. – Larme Aug 27 '20 at 08:55
  • @Larme Great, I think it's really what TS needs. – Roman Ryzhiy Aug 27 '20 at 08:58
  • @Roman Ryzhiy Ah, of course! I just add another convenience init! I tried and it works just like expected. Thanks a bunch man, you just saved me many hours :) – Joakim Sjöstedt Aug 27 '20 at 09:24