I am displaying text in my app as an attributed string from local HTML files, populating a label, as this gives me formatting flexibility. Why is the usual string interpolation not working in this case, and is there a workaround? The aim is to allow the user-provided username to be contained within the string. It functions well except leaves "(user)" from the HTML file displayed in the label rather than interpolating the username as I expected. I'm still learning so if this is a strange and unworkable way to be doing things anyway then please let me know...
This is my code:
class ArticleViewController: UIViewController {
@IBOutlet weak var contentField: UITextView!
var articleID : String = ""
var user = UserDefaults.standard.object(forKey: "user") ?? "user"
override func viewDidLoad() {
super.viewDidLoad()
if let html = Bundle.main.path(forResource: "\(articleID)", ofType: "html") {
let urlToLoad = URL(fileURLWithPath: html)
let data = NSData(contentsOf: urlToLoad)
if let attributedString = try? NSAttributedString(data: data as! Data, options: [.documentType: NSAttributedString.DocumentType.html], documentAttributes: nil) {
contentField.attributedText = attributedString
}
}
}
}
Thanks for your help!
Why is the usual string interpolation not working in this case
Usual string interpolation works on the String literals in the Swift source files, not on the content of general text files or html files.
You may need to replace the occurrences of (user)
in the attributed string. (The basic concept is not different from Carpsen90's answer, but you need to be careful when replacing already attributed string.)
if let htmlURL = Bundle.main.url(forResource: articleID, withExtension: "html") {
do {
let data = try Data(contentsOf: htmlURL)
let attributedString = try NSMutableAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html], documentAttributes: nil)
//### When you want to compare the result...
//originalText.attributedText = attributedString
let regex = try! NSRegularExpression(pattern: "\\(user\\)")
let range = NSRange(0..<attributedString.string.utf16.count)
let matches = regex.matches(in: attributedString.string, range: range)
for match in matches.reversed() {
attributedString.replaceCharacters(in: match.range, with: user)
}
contentField.attributedText = attributedString
} catch {
// Do error processing here...
print(error)
}
}
Example.
article.html:
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<i>(user)</i>😀<b>(user)</b>
</body>
</html>
What you can see in the text view: