【问题标题】:NSAttributedString initWithData and NSHTMLTextDocumentType crash if not on main thread如果不在主线程上,则 NSAttributedString initWithData 和 NSHTMLTextDocumentType 崩溃
【发布时间】:2015-05-09 01:42:53
【问题描述】:

打电话

NSAttributedString * as = [[NSAttributedString alloc] initWithData:[htmlString dataUsingEncoding:NSUTF8StringEncoding] options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding)} documentAttributes:nil error:nil];

在主线程之外,导致崩溃

1   0x194b861fc <redacted>
2   0x19801d31c <redacted>
3   0x198010eb4 _os_once
4   0x19801aa2c pthread_once
5   0x195a0858c <redacted>
6   0x195a07c78 WebKitInitialize
7   0x18bb38918 <redacted>
8   0x10020cdf0 _dispatch_client_callout
9   0x10020dcfc dispatch_once_f
10  0x1977f8bd0 <redacted>
11  0x1978009ac <redacted>
12  0x19780bdb8 <redacted>
13  0x1940b259c _NSReadAttributedStringFromURLOrData
14  0x1940b0eb4 <redacted>
15  0x1001041a0 -[MPMPostTextBrickCell attributedTextWithHTMLString:]
16  0x100103d3c __39-[MPMPostTextBrickCell setupWithBrick:]_block_invoke
17  0x187fb3508 <redacted>
18  0x187f04c94 <redacted>
19  0x187ef461c <redacted>
20  0x187fb626c <redacted>
21  0x10020cdf0 _dispatch_client_callout
22  0x100217854 _dispatch_queue_drain
23  0x100210120 _dispatch_queue_invoke
24  0x10021975c _dispatch_root_queue_drain
25  0x10021af18 _dispatch_worker_thread3
26  0x1980192e4 _pthread_wqthread
27  0x198018fa8 start_wqthread

当我不指定下面的属性时,它会起作用

NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,

我需要在后台线程上解析字符串,但这使得它不可能:(

【问题讨论】:

  • 错误信息是什么?
  • 例外是 EXC BAD ACCESS

标签: ios cocoa cocoa-touch nsattributedstring nsoperationqueue


【解决方案1】:

文档对此非常明确。

不应从后台线程调用 HTML 导入器(即,选项字典包含值为 NSHTMLTextDocumentType 的 NSDocumentTypeDocumentAttribute)。它将尝试与主线程同步,失败并超时。从主线程调用它是可行的(但如果 HTML 包含对外部资源的引用,仍然会超时,应该不惜一切代价避免这种情况)。 HTML 导入机制旨在实现诸如 markdown 之类的东西(即文本样式、颜色等),而不是用于一般的 HTML 导入。

只能在主线程上使用 HTML 导入器 (NSHTMLTextDocumentType)。

(来源:Apple's documentation

【讨论】:

  • 这样做的问题是它会挂起 UI(尤其是在 tableView 中或推送新视图控制器时)。除了使用 NSAttributedString 之外,还有什么方法可以在后台线程上解析 HTML?
  • 不使用第三方库可以做到这一点或自己编写解析器。到目前为止,还没有 API 可以在 Apple SDK afaik 提供的后台线程上执行此操作
  • 我添加了DTCoreText,现在正在使用他们的 NSAttributedString 的-initWithHTMLData 方法,到目前为止它似乎工作得更好。
【解决方案2】:

回答这个问题可能为时已晚,但可以帮助其他人。

实际上 NSAttributedStringNSHTMLTextDocumentType 必须在主队列或全局队列上异步运行。

您可以在后台线程中使用它,但您必须将包含 NSAttributedString 初始化程序的代码块分派到全局或主队列中。例如:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { () -> Void in




            print("Started on \(NSThread.currentThread())")

            let encodedData = "<font color=\"red\">Hello</font>".dataUsingEncoding(NSUTF8StringEncoding)!
            let attributedOptions : [String: AnyObject] = [
                NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
                NSCharacterEncodingDocumentAttribute: NSUTF8StringEncoding
            ]


            let attributedString = (try? NSAttributedString(data: encodedData, options: attributedOptions, documentAttributes: nil) ?? NSAttributedString(string: ""))



            print("Finished")

        }

【讨论】:

  • 如果按描述工作会很酷,但至少在 iOS 9.2 Xcode 模拟器上,并且使用 dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),堆栈抓取仍然显示 NSAttributedString 设置自己的信号量并等待主线程从 HTML 执行转换。
  • 您在 iOS 8.1 中尝试过吗?全局队列崩溃。
  • 你能告诉我哪里说这个函数必须异步运行吗?我想进一步阅读。
  • @AnthonyM 其实我只是通过经验找到了这个解决方案。不知道有没有文档。
  • 好的,谢谢。 @AliSoftware 的答案中的文档说这必须在主线程上完成。虽然它不会总是崩溃,但我认为在技术上不支持使用全局队列。
猜你喜欢
  • 2016-12-08
  • 2015-12-12
  • 2023-03-23
  • 2015-12-27
  • 1970-01-01
  • 1970-01-01
  • 2011-10-11
  • 2017-10-10
相关资源
最近更新 更多