Hashtags in Arabic Language Crashes the App

Hashtags in Arabic language crashes the app

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.

My app crashes when my phone's language is set to Persian or Arabic because of Double.parseDouble

Thanks to all who answered specially Alaa M., because I somehow found the answer through his comment. The "," in Persian or Arabic digits that we use to write the decimals with it made the problem.

I managed to fix it by adding

Locale.setDefault(new Locale("en", "US"));

to my code.

Swift Crashlytics EXC_BREAKPOINT error meaning

The crash is happening inside iOS hidden code, just before calling the UITextViewDelegate method textView(_:shouldInteractWith:in:interaction:).

It's the same issue as this one. To reproduce your bug, you can put for your links Korean text (한국어 텍스트, ie "korean text" according to Google Translate), Arabic text (نص عربي, ie "arabic text" according to Google Translate), etc. You can search on the Internet for sample "strange" text (ie, not "a-z characters).

What's happening:

  • Setting:

    attributedText.addAttribute(.link, value: INVALIDSTRINGVALUE, range: linkRange)
    aTextView.attributedText = someAttributedText
  • User Taping on link

  • Apple internal code that will call later textView(_:shouldInteractWith:in:interaction:)

  • textView(_:shouldInteractWith:in:interaction:)

  • linkTappedCallbackClosure(url: URL)

  • openURL(_ urlString: String) where you do:

    guard let url = URL(string: urlString) else {
    showInvalidUrlAlert()
    return
    }

So you check if the URL is valid, but too late. The code crash inside iOS code.

So before setting the url with hyperLink(originalText:hyperLink:urlString:) check there if it's a valid URL (ie URL(string: urlString) != nil), and if not, call showInvaludURLAlert().

Ok, but that will fix only the new entries, not the current values that will make it crash.

To fix the older entries, you can decide to remove in your database all the invalid URL. But it will remove maybe infos that user thought to be tags, or something else extra field.

An extra code, possibility maybe:

Iterate over your database.

Add a boolean field "hasBeenFixed" to your database.
For each invalid URL (meaning URL(string: thatValue) == nil)), percent escape it., change the value hasBeenFixed to true

It should avoid the crash (to verify) if the user tries to tap on the link.

When showing the value to the user, (when editing), if hasBeenFixed == true, show the value with percent escape removed. Then, when the user will try to validate it will have the pop-up alert, and will need to fix it. When saving a valid URL then, change the hasBeenFixed to false.

Convert attribute to URL / NSURL

I never had a issue when casting .link value to either String or URL, like so:

if let urlString = (attribute as? String) ?? (attribute as? URL)?.absoluteString {
print("URL: \(urlString)")

// URL from string
let url = URL(string: urlString)
}

I faced some issues in the past when casting .link value alone to String, here in my post @RasheshBosamiya in comments also faced this issue, and seems the value of NSAttributedString.Key.link can either be URL or String depending on what/how it is set.



Related Topics



Leave a reply



Submit