首页 > 解决方案 > 在 UITextView 中点击 URL 时 iOS 应用程序崩溃

问题描述

我正在尝试在文本中设置具有多个链接的 UITextView。我的实现基于此处描述的建议。大多数链接按预期工作,但是点击其中一些会使应用程序崩溃并出现以下错误EXC_BREAKPOINT (code=1, subcode=0x185646694)
崩溃错误
调用堆栈

我的 UITextView 配置代码:

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)
        }
    }
}

为了处理点击动作,我使用了正确的 UITextViewDelegate 方法:

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
}

此屏幕的故事板配置(我在故事板中设置了 UITextView 委托):
故事板配置

任何见解将不胜感激!谢谢。

标签: iosswiftxcodeuitextviewuitextviewdelegate

解决方案


问题解决了!感谢Larme提供的快速见解和资源。

这确实是一个尝试在内部转换为 URL 的 UITextView 中使用错误字符串作为链接的情况。由于这是一个包含空格的字符串,因此 Apple 对 URL 的内部转换失败。

我的字符串“支持”链接正确并且有效,但是另一个字符串“新条款和条件”失败了。

解决方案

为了解决这个问题,我在将链接属性添加到 UITextView 的属性文本时使用了百分比编码。

private func addActionableLinks(to attributedText: NSMutableAttributedString) {
    actionableLinks.forEach {
        let actionableString = $0.0
            
        if let nsRange = messageText.nsRange(of: actionableString) {
            let escapedActionableString = escapedString(actionableString)
            attributedText.addAttribute(.link, value: escapedActionableString, range: nsRange)
        }
    }
}
    
private func escapedString(_ string: String) -> String {
    return string.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? string
}

我还更改了委托方法以检查是否与转义字符串匹配:

func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
    let tappedLinkString = URL.absoluteString
        
    for (actionableString, tapAction) in actionableLinks {
        let escapedActionableString = escapedString(actionableString)
            
        if escapedActionableString == tappedLinkString {
            tapAction()
            return false
        }
    }

    return true
}

谢谢!


推荐阅读