Swift 3: 在 NSAttributedString 中获取子字符串的属性

Swift 3: Getting attributes at substring in NSAttributedString

我的一个控制器有一个 NSAttributeString,其中有一个 link:

@IBOutlet var textView: UITextView!

// Below is extracted from viewDidLoad()
let linkStr = "Click <a href='http://google.com'>here</a> for good times."
let attributedText = try! NSAttributedString(
  data: linkStr.data(using: String.Encoding.unicode, allowLossyConversion: true)!,
  options: [ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],
  documentAttributes: nil)
textView.attributedText = attributedText

我正在为控制器编写单元测试,我想验证 link 是否放在 "here" 文本中。 (link实际上是动态生成的,这就是我要测试它的原因)。

无论如何,我显然可以得到这样的无属性文本:

let text = viewController.textView.attributedText.string
// text == "Click here for good times."

我还可以从 "here" 中获取 link 属性,方法如下:

let url = uviewController.textView.attributedText.attribute(
    "NSLink", at: 6, effectiveRange: nil)
// url == A URL object for http://google.com.

问题是我不得不为 at 参数硬编码“6”。 linkStr 的值将来可能会改变,我不想每次都更新我的测试。对于这种情况,我们可以假设它将始终包含单词 "here" 以及附加到该单词的 link。

所以我想做的是找到单词 "here" 在 linkStr 中的字符,并将该值传递给 at 参数以提取NSLink 属性并验证它指向正确的 URL。但是我无法确定如何使用 Swift 中的字符串范围和索引来实现这一点。

有什么建议吗?

以下是无需硬编码即可实现的方法。这是基于您的示例的 Swift 3 playground 代码:

import UIKit
import PlaygroundSupport

let linkStr = "Click <a href='http://google.com'>here</a> for good times."
let attributedText = try! NSAttributedString(
    data: linkStr.data(using: String.Encoding.unicode, allowLossyConversion: true)!,
    options: [ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],
    documentAttributes: nil)

attributedText.enumerateAttribute(NSAttributedString.Key.link, in: NSMakeRange(0, attributedText.length), options: [.longestEffectiveRangeNotRequired]) { value, range, isStop in
    if let value = value {
        print("\(value) found at \(range.location)")
    }
}

print 语句输出:

http://google.com/ found at 6

p.s。由于重命名,'NSAttributedString.Key.link' 而不是 'NSLinkAttributeName'。