I would like to do what would seem like a fairly simple thing that would be trivial in SwiftUI, here on SO, markdown or html: bold a couple words in a string in Swift ideally using an extension for re-use. For example, bold the word "world" in "Hello world". I would be happy with an extension of any type of String eg String, NSString, NSAttributedString, NSMutableAttributedString and so forth as I can go back and forth. All of the examples I have found–dating typically from a number of years ago–do not compile. For example (with errors commented out):
extension NSMutableAttributedString {
func bold(_ text: String, font: UIFont = .systemFont(ofSize: 17, weight: .bold)) -> Self {
let range = self.range(of: text)!
self.addAttribute(.font, value: font, range: range) //error 'Value of type self has no member range'
return self
}
}
public extension String {
func attributedString(with boldText: String, boldTextStyle: [NSAttributedString.Key: Any] = [.font: UIFont.boldSystemFont(ofSize: 17)]) -> NSAttributedString {
let attributedString = NSMutableAttributedString(string: self)
let boldTextRange = range(of: boldText)!
attributedString.addAttributes(boldTextStyle, range: boldTextRange) //Cannot convert value of type 'Range<String.Index>' to expected argument type 'NSRange' (aka '_NSRange')
return attributedString
}
}
Edit: One more SO answer in Objective-C not using extension that does compile for me either. Throws about 10 errors:
NSString *normalText = @"Hello ";
NSString *boldText = @"world";
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:normalText];
NSDictionary<NSAttributedString.key, id> *attrs = @{ NSAttributedString.Key.font: [UIFont boldSystemFontOfSize:15] };//throws 5 errors
NSMutableAttributedString *boldString = [[NSMutableAttributedString alloc] initWithString:boldText attributes:attrs];//throws 5 errors
[attributedString appendAttributedString:boldString];
(I have tried many other approaches from old answers and multiple AIs without success.)
Can anyone suggest how to get the above to work in modern Swift short of SwiftUI or how to create a string extension to bold a portion of a string. Thanks for any suggestions.
2
Answers
The problem here is that "boldification" is not a thing. Given a font Georgia, you cannot simply boldify it; you have to know that the bold variant is a different font, Georgia-Bold. To find that out, or the equivalent, you have to pass thru UIFontDescriptor. Here’s a couple of extensions that might let you find the bold variant of a given font:
Once you do know that, then here’s a working extension that lets you apply an attribute container to a substring of an attributed string:
That’s more general than what you asked for, but in my opinion, generality is better. You can always add more code to pick out a specific case in point. Anyway, here’s an example of how to use it (which is, after all, the whole point):
That boldifies just the "world" part of "Hello, world!"