Hashtags in Arabic language crashes the app

前端 未结 1 1304
伪装坚强ぢ
伪装坚强ぢ 2021-01-14 20:39

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.<

相关标签:
1条回答
  • 2021-01-14 21:03

    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.

    0 讨论(0)
提交回复
热议问题