是否在后台将HTML转换为NSAttributedString?

时间:2018-09-03 17:15:40

标签: swift nsattributedstring

我正在开发一个应用程序,该应用程序将从WordPress检索帖子,并允许用户单独查看每个帖子的详细信息。 WordPress API带回帖子内容,即帖子的HTML。 (注意:img标签引用的是上传图片的WordPress URL)

最初,我正在使用WebView并将检索到的内容直接加载到其中。效果很好;但是,图像似乎正在主线程上加载,因为这会导致出现滞后现象,有时会冻结UI,直到图像完成下载为止。建议我检查WordPress的Aztec编辑器库;但是,我不知道如何使用它(找不到太多文档)。

我当前的路线是解析HTML内容并创建词典列表([image或text]类型的键和content)。解析后,我通过动态添加Labels&Image视图(使我可以在后台下载图像)来构建帖子。尽管这看起来似乎过于复杂并且可能是错误的路线,但它运行良好(不过,将对任何其他解决方案开放!)目前,我唯一的问题是将HTML字符串转换为NSAttributedText的延迟。在将文本内容添加到字典之前,我将其从String转换为NSAttributedString。我注意到延迟了几秒钟,模拟器的CPU在几秒钟内上升了50-60%,然后下降了。无论如何,在这段时间内我可以在后台线程上执行此转换并显示加载动画吗?

如果您有任何更好的解决方案的想法或建议,请告诉我。非常感谢你!

代码:

let postCache = NSCache<NSString, AnyObject>()
var yPos = CGFloat(20)
let screenWidth = UIScreen.main.bounds.width

...

 func parsePost() -> [[String:Any]]? {
    if let postFromCache = postCache.object(forKey: postToView.id as NSString) as? [[String:Any]] {
        return postFromCache
    } else {
        var content = [[String:Any]]()

        do {
            let doc: Document = try SwiftSoup.parse(postToView.postContent)
            if let elements = try doc.body()?.children() {
                for elem in elements {
                    if(elem.hasText()) {
                        do {
                            let html = try elem.html()
                            if let validHtmlString = html.htmlToAttributedString {
                                content.append(["text" : validHtmlString])
                            }
                        } 
                    } else {
                        let imageElements = try elem.getElementsByTag("img")
                        if(imageElements.size() > 0) {
                            for image in imageElements {
                                var imageDictionary = [String:Any]()
                                let width = (image.getAttributes()?.get(key: "width"))!
                                let height = (image.getAttributes()?.get(key: "height"))!
                                let ratio = CGFloat(Float(height)!/Float(width)!)
                                imageDictionary["ratio"] = ratio
                                imageDictionary["image"] = (image.getAttributes()?.get(key: "src"))!

                                content.append(imageDictionary)
                            }
                        }
                    }
                }
            }
        } catch {
            print("error")
        }

        if(content.count > 0) {
            postCache.setObject(content as AnyObject, forKey: postToView.id as NSString)
        }

        return content
    }
}

func buildUi(content: [[String:Any]]) {
    for dict in content {
        if let attributedText = dict["text"] as? NSAttributedString {
            let labelToAdd = UILabel()
            labelToAdd.attributedText = attributedText
            labelToAdd.numberOfLines = 0
            labelToAdd.frame = CGRect(x:0, y:yPos, width: 200, height: 0)
            labelToAdd.sizeToFit()
            yPos += labelToAdd.frame.height + 5
            self.scrollView.addSubview(labelToAdd)
        } else if let imageName = dict["image"] as? String {
            let ratio = dict["ratio"] as! CGFloat
            let imageToAdd = UIImageView()
            let url = URL(string: imageName)
            Nuke.loadImage(with: url!, into: imageToAdd)
            imageToAdd.frame = CGRect(x:0, y:yPos, width: screenWidth, height: screenWidth*ratio)
            yPos += imageToAdd.frame.height + 5
            self.scrollView.addSubview(imageToAdd)
        }
    }
    self.scrollView.contentSize = CGSize(width: self.scrollView.contentSize.width, height: yPos)
}

extension String {
var htmlToAttributedString: NSAttributedString? {
    guard let data = data(using: .utf8) else { return NSAttributedString() }
    do {
        return try NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding:String.Encoding.utf8.rawValue], documentAttributes: nil)
    } catch {
        return NSAttributedString()
    }
}
var htmlToString: String {
    return htmlToAttributedString?.string ?? ""
}

}

(请原谅我提供的代码不太干净!我只是想确保在开始重构之前可以取得理想的结果。再次感谢!)

0 个答案:

没有答案