I'm trying to setup a UITextView with multiple links within the text. My implementation is based on the suggestion described here. Most links work as expected, however tapping on some of them makes the app crash with the following error EXC_BREAKPOINT (code=1, subcode=0x185646694)
:
Crash error
Call stack
My UITextView configuration code:
private var actionableLinks = [(String, ()->Void)]() // each link = (actionableString, tapAction)
private func setupMessageText() {
guard messageTextView != nil else { return }
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.paragraphSpacingBefore = 16
let attributedText = NSMutableAttributedString(string: messageText, attributes: [
.font: messageTextView.font!,
.foregroundColor: messageTextView.textColor!,
.paragraphStyle: paragraphStyle
])
addActionableLinks(to: attributedText)
messageTextView?.attributedText = attributedText
}
private func addActionableLinks(to attributedText: NSMutableAttributedString) {
actionableLinks.forEach {
let actionableString = $0.0
if let nsRange = messageText.nsRange(of: actionableString) {
attributedText.addAttribute(.link, value: actionableString, range: nsRange)
}
}
}
To handle the tap action, I've imlpemented the proper UITextViewDelegate method:
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
let tappedLinkString = URL.absoluteString
if let link = actionableLinks.first(where: { $0.0 == tappedLinkString }) {
let tapAction = link.1
tapAction()
return false
}
return true
}
My storyboard configuration for this screen (I have setup the UITextView delegate in the storyboard):
Storyboard Configuration
Any insights would be much appreciated! Thanks.
if let nsRange = messageText.nsRange(of: actionableString), URL(string: actionableString) != nil {
might be the fix. If you can reproduce, could you provide theactionableString
which is causing the issue?"new terms and conditions"
, converted toURL
, withURL(string: thatString)
internally by Apple, just before callingtextView(_:shouldInteractWith:in:)
, it's nil and make it crash., because space are invalid. Percent escape them (see second linked question), and maybe add a scheme to them:yourApp://
as prefix.