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 = someAttributedTextUser 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
iPhone Storage in Tmp Directory
Simple Low-Latency Audio Playback in iOS Swift
Invalid Image Path - No Image Found at the Path. Cfbundleicons Xcode 5
How to Execute Some Code After a Segue Is Done
Uisearchcontroller Persisting After Segue
Why Would a 'Scheduledtimer' Fire Properly When Setup Outside a Block, But Not Within a Block
Error Itms-90086 Submitting App
Nsnotificationcenter Swift 3.0 on Keyboard Show and Hide
Perform a Deeplink from Swiftui Widget on Tap
Exception Type: Exc_Crash (Sigabrt)
How to Use Http Live Streaming Protocol in iPhone Sdk 3.0
Deferredlocationupdatesavailable Returns No in iOS 10
Uisearchdisplaycontroller Without Dimming
Ckquery from Private Zone Returns Only First 100 Ckrecords from in Cloudkit
Apple Llvm 6.0 Error: Clang Failed with Exit Code -1
Dyld: Library Not Loaded: @Rpath/Libswiftswiftononesupport.Dylib