I have a hashtags resolver UITextView extension that turns any word with \"#\" before it to a tappable blue link. It is working fine except when tapping on Arabic hashtags.<
What I guess could be the issue (either on tag or hash)...
You do:
attrString.addAttribute(NSAttributedStringKey.link, value: "hash://\(stringifiedWord)", range: matchRange)
But if you'd use a URL
object (let url = URL.init(string:"hash://\(stringifiedWord)")
) you'll see it may be nil
in case of invalid string url and in your case arabic characters seem to be invalid.
The delegate method func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool
is giving a URL
object in parameters, and because your method is not called when you don't have a valid url, I guess that inner line in Apple's code assume it's a valid url, doesn't check it and crashes. That would explain why your method isn't called and crash before entering yours.
Solution: Use percent escaped characters.
Instead of putting value: "hash://\(stringifiedWord)"
, do value: "hash://\(stringifiedWord.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed))"
or other character set allowed.
In the delegate method you are already removing the percent escape: let hash = path.removingPercentEncoding?.components(separatedBy: "://").last
so you don't have to add anything there.
Additional note:
You are doing if word.hasPrefix("#")
and `if word.hasPrefix("@") almost the same thing (just the scheme change), you could simplify/factorize that, sample code not tested:
let dict = ["#":"mention://", "@": "hash://"]
for (key, value) in dict
{
if word.hasPrefix(key)
{
let matchRange:NSRange = nsText.range(of: word as String)
var stringifiedWord:String = word as String
stringifiedWord = String(stringifiedWord.dropFirst(key.count))
let espcapedWord = stringifiedWord.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed
let stringURL = "\(value)\(escapedWord)"
if let url = URL.init(string:stringURL) //That should you avoid any crash just in case
{
attrString.addAttribute(.link, value: stringURL, range: matchRange)
}
else
{
print("Oooops with \(stringifiedWord) invalid URL: \(stringURL)")
}
}
}
Edit: Depending on the iOS version (tested on Simulator), it could make it crash, or simply not call the delegate method because of the invalid URL.