我有一个很简单的
UIViewController
viewDidLoad
:
class TextViewController: UIViewController {
private var textView: UITextView?
var htmlText: String? {
didSet {
updateTextView()
}
}
private func updateTextView() {
textView?.setHtmlText(htmlText)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
textView = UITextView()
// add as subview, set constraints etc.
updateTextView()
}
}
(
.setHtmlText
是UITextView的扩展,它将HTML转换为
NSAttributedString
,灵感来自
this answer
创建了TextViewController的实例,
.htmlText
设置为“获取…”,将发出HTTP请求,并将viewcontroller推送到UINavigationController上。
这将导致调用
updateTextView
没有效果(
.textView
视图加载
再次调用以确保显示当前文本值。不久之后,HTTP请求返回一个响应,并且
设置为该响应的主体,从而导致对
更新文本视图
所有这些代码都在主队列上运行(通过设置断点和检查堆栈跟踪进行确认),但是,除非http get中有明显的延迟,否则显示的最后文本是占位符(“Fetching…”)。在调试器中单步执行会显示序列为:
1. updateTextView() // htmlText = "Fetching...", textView == nil
2. updateTextView() // htmlText = "Fetching...", textView == UITextView
3. updateTextView() // htmlText = <HTTP response body>
4. setHtmlText(<HTTP response body>)
5. setHtmlText("Fetching...")
最后一个电话
setHtmlText
似乎超过了第一个。同样奇怪的是,当
设置文本
声称它是通过“获取…”传递的,调用方认为它传递的是HTTP HTML正文。
更改HTTP响应的接收器以执行此操作:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { vc.htmlText = html }
而不是更传统的:
DispatchQueue.main.async { vc.htmlText = html }
所有这些行为在模拟器或真实设备上都是可复制的。一个有点古怪的感觉“解决办法”是再打一个电话给
更新文本视图
在里面
viewWillAppear
编辑以添加:
我真的不知道只要打一个电话
更新文本视图
将出现视图
,但需要从
视图加载
将出现视图
以显示最终值。
编辑以添加请求的代码:
let theVc = TextViewController()
theVc.htmlText = "<i>Fetching...</i>"
service.get(from: url) { [weak theVc] (result: Result<String>) in
// DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
DispatchQueue.main.async {
switch result {
case .success(let html):
theVc?.htmlText = html
case .error(let err):
theVc?.htmlText = "Failed: \(err.localizedDescription)"
}
}
}
navigationController.pushViewController($0, animated: true)
let theVc = TextViewController()
theVc.htmlText = "<i>Before...</i>"
DispatchQueue.main.async {
theVc.htmlText = "<b>After</b>"
}
navigationController.pushViewController(theVc, animated: true)
这将产生一个等价的调用序列
updateTextView()
如前所述:
-
“之前”,还没有文本视图
-
-
“之后”
但“以前”是我在屏幕上看到的。
在开始处设置断点
设置文本
NSAttributedString(data:options:documentAttributes:)
重新进入运行循环,第二个赋值(“After”)有机会运行到完成,将其结果赋值给
.attributedText
. 然后,原始的nsattributed字符串有机会完成,它立即替换
.属性文本
这是个怪癖
s是从HTML生成的(参见
similar issues
UITableView
)