在 UITextView 中点击 URL 时 iOS 应用程序崩溃 [重复]

Posted

技术标签:

【中文标题】在 UITextView 中点击 URL 时 iOS 应用程序崩溃 [重复]【英文标题】:iOS app crashes when tapping URL within UITextView [duplicate] 【发布时间】:2021-06-09 10:20:20 【问题描述】:

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

我的 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 委托):Storyboard Configuration

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

【问题讨论】:

我怀疑该链接无效。 if let nsRange = messageText.nsRange(of: actionableString), URL(string: actionableString) != nil 可能是解决办法。如果可以重现,能否提供导致问题的actionableString 请参阅 ***.com/questions/65656646/… 和 ***.com/questions/48154641/…,因为这可能是问题所在(有解释) 感谢您的评论和很好的见解。我用作链接的字符串实际上只是一个普通字符串而不是 URL。我的实现基于this previous answer,并且没有提到任何内容。导致崩溃的链接的字符串是“新条款和条件”,成功的是“支持”。 如前所述(在解释中请参阅两个链接),如果“链接”是"new terms and conditions",则转换为URL,由Apple 在内部使用URL(string: thatString),就在调用textView(_:shouldInteractWith:in:) 之前,它为零并使其崩溃。,因为空间无效。百分比转义它们(参见第二个链接问题),并可能向它们添加一个方案:yourApp:// 作为前缀。 确实不错!在阅读了您链接的问题后,我产生了怀疑。我马上测试一下 【参考方案1】:

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

这确实是一个尝试使用错误字符串作为 UITextView 中的链接的情况,该链接在内部被转换为 URL。由于这是一个带有空格的字符串,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

谢谢!

【讨论】:

您可以只保留您的 shouldInteractLogic:let tappedLinkString = URL.aboluteString.removingPercentEncoding 和您的 first(where:) 哦,酷!我会用它,它更干净。非常感谢!

以上是关于在 UITextView 中点击 URL 时 iOS 应用程序崩溃 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

是否有机会确定是否在 UITextView 中点击了空白空间?

iOS 自动识别URL(链接)功能的实现

如何在 ios 中点击 UITextView 打开 Pickerview(dropdown)?

当我点击UITextView时,如何让我的iOS应用程序显示东部阿拉伯语小数点?

如何检测 URL 是不是已粘贴/输入到 UITextView? Swift iOS [关闭]

UITextView shouldInteractWith 委托在警报完成中返回值