阿拉伯语的Hashtags崩溃应用程序

时间:2018-01-08 16:50:56

标签: ios swift uitextview nsattributedstring hashtag

我有一个hashtags解析器UITextView扩展,可以用"#"在它之前是一个可点击的蓝色链接。除了点击阿拉伯语标签外,它工作正常。

extension UITextView {

func resolveHashAndMentionTags(){

    // turn string in to NSString
    let nsText:NSString = self.text as NSString

    // this needs to be an array of NSString.  String does not work.
    let words:[NSString] = nsText.components(separatedBy: " ") as [NSString]

    // you can't set the font size in the storyboard anymore, since it gets overridden here.
    let attrs = [
        NSAttributedStringKey.font : UIFont(name: "Avenir-Light", size: 14.0)!//UIFont.systemFont(ofSize: 13.0)

    ]

    // you can staple URLs onto attributed strings
    let attrString = NSMutableAttributedString(string: nsText as String, attributes:attrs)

    // tag each word if it has a hashtag or mention
    for word in words {

        // found a word that is prepended by a hashtag!
        if word.hasPrefix("#") {

            // a range is the character position, followed by how many characters are in the word.
            // we need this because we staple the "href" to this range.
            let matchRange:NSRange = nsText.range(of: word as String)

            // convert the word from NSString to String
            // this allows us to call "dropFirst" to remove the hashtag
            var stringifiedWord:String = word as String

            // drop the hashtag
            stringifiedWord = String(stringifiedWord.dropFirst())

                print(stringifiedWord)
                attrString.addAttribute(NSAttributedStringKey.link, value: "hash://\(stringifiedWord)", range: matchRange)
         //   }

        } else if word.hasPrefix("@") {

            // a range is the character position, followed by how many characters are in the word.
            // we need this because we staple the "href" to this range.
            let matchRange:NSRange = nsText.range(of: word as String)

            // convert the word from NSString to String
            // this allows us to call "dropFirst" to remove the mention@
            var stringifiedWord:String = word as String

            // drop the hashtag
            stringifiedWord = String(stringifiedWord.dropFirst())


            attrString.addAttribute(NSAttributedStringKey.link, value: "mention://\(stringifiedWord)", range: matchRange)
           // }
        }
    }

    // we're used to textView.text
    // but here we use textView.attributedText
    // again, this will also wipe out any fonts and colors from the storyboard,
    // so remember to re-add them in the attrs dictionary above
    self.attributedText = attrString
}

然后在我的帖子单元格中,我调用UITextViewDelegate函数。

func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {

    let path = URL.absoluteString
    switch URL.scheme! {
    case "hash" :
        let hash = path.removingPercentEncoding?.components(separatedBy: "://").last
        print(hash!) // ---> Retriving tapped on hash name correctly
        delegate?.hashTableViewCell(self, shouldSelectTag: hash!)
    case "mention" :
        let mention = path.removingPercentEncoding?.components(separatedBy: "://").last
        print(mention!) // ---> Retriving tapped on mention name correctly
        delegate?.mentionTableViewCell(self, shouldSelectTag: mention!, userId: nil)
    default:
        print("Just a regular link \(path.removingPercentEncoding!)")
    }
    return true
}

正如我上面提到的代码,它适用于英文字母,但是当点击阿拉伯语标签或提及它在AppDelegate中崩溃时。

  

线程1:EXC_BREAKPOINT(代码= 1,子代码= 0x1030fcb94)

我尝试使用断点进行调试以了解错误的确切位置,但实际上我发现它甚至在进入UITextViewDelegate函数之前就崩溃了。所以现在我完全不知道错误可能是什么。

UITextView中使用阿拉伯字母作为链接可能存在某种问题?

这是堆栈跟踪。

  
      
  • 线程#1,队列=&#39; com.apple.main-thread&#39;,停止原因= EXC_BREAKPOINT(代码= 1,子代码= 0x1030fcb94)   frame#0:0x00000001030fcb94 libswiftFoundation.dylib function signature specialization <Arg[0] = Owned To Guaranteed, Arg[1] = Dead> of static Foundation.URL._unconditionallyBridgeFromObjectiveC(Swift.Optional<__ObjC.NSURL>) -> Foundation.URL + 288 frame #1: 0x0000000103045f24 libswiftFoundation.dylib static Foundation.URL._unconditionallyBridgeFromObjectiveC(Swift.Optional&lt; __ ObjC.NSURL&gt;) - &gt; Foundation.URL + 20   帧#2:0x0000000101199c68 OOL @objc PostTableViewCell.textView(_:shouldInteractWith:in:) at PostTableViewCell.swift:0 frame #3: 0x000000018e1e397c UIKit - [_ UITextViewInteractableLink allowInteraction:] + 360   帧#4:0x000000018e1e2698 UIKit -[_UITextViewInteractableItem handleTap] + 40 frame #5: 0x000000018db64548 UIKit - [UITextGestureClusterLinkInteract smallDelayRecognizer:] + 296   帧#6:0x000000018db7ccd0 UIKit -[UIGestureRecognizerTarget _sendActionWithGestureRecognizer:] + 64 frame #7: 0x000000018db812c4 UIKit _ UIGestureRecognizerSendTargetActions + 124   帧#8:0x000000018d659aa8 UIKit _UIGestureRecognizerSendActions + 320 frame #9: 0x000000018d510c38 UIKit - [UIGestureRecognizer _updateGestureWithEvent:buttonEvent:] + 732   帧#10:0x000000018db6ab34 UIKit _UIGestureEnvironmentUpdate + 1084 frame #11: 0x000000018db6a6a4 UIKit - [UIGestureEnvironment _deliverEvent:toGestureRecognizers:usingBlock:] + 404   帧#12:0x000000018db69800 UIKit -[UIGestureEnvironment _updateGesturesForEvent:window:] + 276 frame #13: 0x000000018d50ef44 UIKit - [UIWindow sendEvent:] + 3180   帧#14:0x000000018d4dff64 UIKit -[UIApplication sendEvent:] + 340 frame #15: 0x000000018de3531c UIKit __ dispatchPreprocessedEventFromEventQueue + 2364   帧#16:0x000000018de378a8 UIKit __handleEventQueueInternal + 4760 frame #17: 0x000000018de307c0 UIKit __ handleHIDEventFetcherDrain + 152   帧#18:0x0000000183fa697c CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 24 frame #19: 0x0000000183fa68fc CoreFoundation __ CFRunLoopDoSource0 + 88   帧#20:0x0000000183fa6184 CoreFoundation __CFRunLoopDoSources0 + 204 frame #21: 0x0000000183fa3d5c CoreFoundation __ CFRunLoopRun + 1048   帧#22:0x0000000183ec3e58 CoreFoundation CFRunLoopRunSpecific + 436 frame #23: 0x0000000185d70f84 GraphicsServices GSEventRunModal + 100   帧#24:0x000000018d54367c UIKit`UIApplicationMain + 236      
        
    • 第25帧:0x0000000101063348 OOL main at AppDelegate.swift:22 frame #26: 0x00000001839e056c libdyld.dylib开始+ 4
    •   
  •   

1 个答案:

答案 0 :(得分:3)

我猜这可能是问题(无论是标签还是哈希)......

你这样做:

attrString.addAttribute(NSAttributedStringKey.link, value: "hash://\(stringifiedWord)", range: matchRange)

但是如果您使用URL对象(let url = URL.init(string:"hash://\(stringifiedWord)")),如果网格网址无效,您会看到它可能是nil,在您的情况下,阿拉伯字符似乎是无效。

委托方法func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool在参数中提供了一个URL对象,并且因为当你没有有效的url时你的方法没有被调用,我想Apple的代码中的内线假定它是一个有效的网址,不检查它和崩溃。这可以解释为什么在进入你的方法之前没有调用你的方法并崩溃。

解决方案:使用转义字符百分比。 value: "hash://\(stringifiedWord)",而是允许value: "hash://\(stringifiedWord.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed))"或其他字符集。

在委托方法中,您已经删除了百分比转义:let hash = path.removingPercentEncoding?.components(separatedBy: "://").last,因此您无需在那里添加任何内容。

附加说明: 您正在执行if word.hasPrefix("#")和`if word.hasPrefix(“@”)几乎相同的事情(只是方案更改),您可以简化/分解,未经测试的示例代码:

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