创建NSAttributedString时,索引1超出范围[0 .. 0]

时间:2018-09-12 15:22:49

标签: ios swift

在我的代码中,NSAttributedString有一个扩展名:

internal convenience init?(html: String) {
    guard let data = html.data(using: String.Encoding.utf8, allowLossyConversion: true) else {
        return nil
    }
    print(UIKit.Thread.isMainThread) //TRUE
    guard let attributedString = try? NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil) else { //here is the error
        return nil
    }
    self.init(attributedString: attributedString)
}

然后我尝试像这样使用它:

let text = "<p>Your order has been created. </p><p>Below You can find the details of Your order:</p><p>Order ID: 183</p><p>Summary: <ul><li>Filtered coffee 50.00 x 1</li></ul></p><p>Service fee: 30.0</p><p>Total: 80.0 Kn</p><p>You will receive a message when our staff starts preparing Your order.<br/></p>"

let attributedString = NSAttributedString(html: text)

文本具有以下值:

Your order has been created. 

Below You can find the details of Your order:

Order ID: 183

Summary:

  • Filtered coffee 50.00 x 1

Service fee: 30.0

Total: 80.0 Kn

You will receive a message when our staff starts preparing Your order.

怎么了?;)

编辑:

我将它与MessageKit一起使用以显示属性文本:

extension Message: MessageType {
var sender: Sender {
    return Sender(id: createdBy?.identifier ?? "", displayName: createdBy?.name ?? "BOT_RESPONSE")
}
var messageId: String {
    return identifier
}
var sentDate: Date {
    return date
}
var kind: MessageKind {
    guard let attributedString = NSAttributedString(html: text) else {
        return .text(text)
    }
    return .attributedText(attributedString)
}
}

当我将断点放在出现错误的行上并在控制台上打印时:

po NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil)

那一切都很好;)为什么呢?

2 个答案:

答案 0 :(得分:3)

NSAttributedString上的此扩展名适用于String.Encoding。 utf16

extension NSAttributedString {
    convenience init?(html: String) {
        guard let data = html.data(using: String.Encoding.utf16, allowLossyConversion: false) else {
            return nil
        }

        guard let attributedString = try?  NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil) else {
            return nil
        }

        self.init(attributedString: attributedString)
    }
}

let text = "<p>Your order has been created. </p><p>Below You can find the details of Your order:</p><p>Order ID: 183</p><p>Summary: <ul><li>Filtered coffee 50.00 x 1</li></ul></p><p>Service fee: 30.0</p><p>Total: 80.0 Kn</p><p>You will receive a message when our staff starts preparing Your order.<br/></p>"

let attributedString = NSAttributedString(html: text)
print(attributedString ?? "Nothing")

这是String的扩展,在操场上对我有用(它从此answer移植到Swift 4。):

import Foundation
import UIKit
import PlaygroundSupport

let label = UILabel()

extension String {
    func initFrom(html: String, with completionHandler: @escaping (NSAttributedString?) ->()) {
        guard let data = html.data(using: String.Encoding.utf8, allowLossyConversion: true) else {
            return completionHandler(nil)
        }

        let options: [NSAttributedString.DocumentReadingOptionKey : Any] = [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue]

        DispatchQueue.main.async {
            if let attributedString =
                try? NSAttributedString(data: data, options: options, documentAttributes: nil)
            {
                completionHandler(attributedString)
            } else {
                completionHandler(nil)
            }
        }
    }
}

let text = "<p>Your order has been created. </p><p>Below You can find the details of Your order:</p><p>Order ID: 183</p><p>Summary: <ul><li>Filtered coffee 50.00 x 1</li></ul></p><p>Service fee: 30.0</p><p>Total: 80.0 Kn</p><p>You will receive a message when our staff starts preparing Your order.<br/></p>"

text.initFrom(html: text, with: { attString in
    print("attString =", attString ?? "")
    label.attributedText = attString
})

PlaygroundPage.current.needsIndefiniteExecution = true

答案 1 :(得分:1)

我之前有一个类似的问题,我发现我在后台线程上运行逻辑。它在我创建新NSAttributedString实例的行崩溃,类似于您的行let attributedString = try? NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil)。您可以确定要在主线程上创建NSAttributedString实例吗?

NSAttributedString documentation中,声明“不应从后台线程调用HTML导入器(即,选项字典包括值为html的documentType)”,因此,这也许可以为您提供一些指导找出问题所在。