Отображение HTML-текста в UITextView Сбой произошел в Swift 4? - PullRequest
0 голосов
/ 25 сентября 2018

Я использую этот код:

Code to show HTML Text in TextView

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) // Get crash on this line
    } catch let error {
        print(error.localizedDescription)
        return NSAttributedString()
    }
}

var htmlToString: String {
    return htmlToAttributedString?.string ?? ""
}

, показывающий HTML текст в UITableViewCell

cell.textViewMessage.attributedText = msg.htmlToAttributedString

Запуск в первый раз не приводит к сбою, но после этого при запуске кода происходит сбой и после этого не работает.

Поток 1: EXC_BAD_ACCESS (код = 1, адрес = 0x10)

# Редактировать строку HTML для отображения в ячейке

<p>Here\'s a short video tour.  Press play to start.</p><br><iframe class=\"ql-video\" frameborder=\"0\" allowfullscreen=\"true\" src=\"https://www.youtube.com\"></iframe><br>

# Редактировать 1 - я пытаюсь запустить этот код в Playground, и он работает нормальнотолько теперь он показывает ошибку.Пожалуйста, смотрите прикрепленное изображение

Playground output

Ответы [ 5 ]

0 голосов
/ 26 марта 2019

Причиной этой проблемы является представление таблицы, эта ошибка будет возникать очень случайно и ее трудно воспроизвести, поскольку она более специфична для памяти устройства и процесса рисования пользовательского интерфейса, что может привести к выполнению метода в фоновом потоке.При перераспределении и освобождении ячеек таблицы глубоко где-то ячейки таблицы могут вызывать этот метод в фоновом потоке, в то время как импортер HTML использует не-поточный импортер WebKit и ожидает, что он будет в основном потоке.

Как воспроизвести эту ошибку: Запустите код, используя UITest, и он будет чаще аварийно завершать работу, поскольку модульный тест значительно замедляет процесс отрисовки пользовательского интерфейса

Решение: декодировать HTML в String следует в основном потоке, но делайте это на уровне модели в основном потоке, а не во время создания ячейки.Это также сделает пользовательский интерфейс более плавным.

Почему сбой не был обнаружен в блоке перехвата : ваше приложение упало из-за необработанного языкового исключения, используемого инфраструктурой обработки исключенийдля Objective-C.SWIFT - это как обёртка вокруг NSError Какао.Swift не может обрабатывать исключения Objective-C, и, таким образом, обработчик ошибок Swift не будет вызывать исключение через код Objective-C в инфраструктуре.

0 голосов
/ 01 октября 2018

Попробуйте это для UITextView:

let string = "<h2>The bedding was hardly able to cover it.</h2>"
if !string.isEmpty{
    if let htmlData = string.data(using:String.Encoding.unicode) {
    do {
          let attributedText = try NSAttributedString(data: htmlData, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil)
           cell.textViewMessage.attributedText = attributedText
       } catch let e as NSError {
          print("Couldn't translate \(string): \(e.localizedDescription) ")
       }
 }

Попробуйте это для UILabel для установки HTML-текста в uilabel с HTML-тегами:

extension String {
     var withoutHtmlTags: String {
            let a = self.replacingOccurrences(of: "<[^>]+>", with: "", options: .regularExpression, range: nil)

            return a.replacingOccurrences(of: "&[^;]+;", with: "", options: String.CompareOptions.regularExpression, range: nil)
        }
    }

let string = "<h2>The bedding was hardly able to cover it.</h2>"

textUIlabel.text = string.withoutHtmlTags
0 голосов
/ 28 сентября 2018

Вот решение, вдохновленное этим репо.По сути, мы удаляем тег iframe и заменяем его кликабельным img:

let msg = "<p>Here\'s a short video tour. Press play to start.</p><br><iframe class=\"ql-video\" frameborder=\"0\" allowfullscreen=\"true\" src=\"https://www.youtube.com/embed/wJcOvdkI7mU\"></iframe><br>"

//Let's get the video id
let range = NSRange(location: 0, length: msg.utf16.count)
let regex = try! NSRegularExpression(pattern: "((?<=(v|V)/)|(?<=be/)|(?<=(\\?|\\&)v=)|(?<=embed/))([\\w-]++)")
guard let match = regex.firstMatch(in: msg, options: [], range: range) else {
    fatalError("Couldn't find the video ID")
}
let videoId: String = String(msg[Range(match.range, in: msg)!])

//Let's replace the the opening iframe tag
let regex2 = try! NSRegularExpression(pattern:
    "<[\\s]*iframe[\\s]+.*src=")

let str2 = regex2.stringByReplacingMatches(in: msg, options: [], range: range, withTemplate: "<a href=")

//And then replace the closing tag
let regex3 = try! NSRegularExpression(pattern:
    "><\\/iframe>")
let range2 = NSRange(location: 0, length: str2.utf16.count)
let str3 = regex3.stringByReplacingMatches(in: str2, options: [], range: range2, withTemplate: "><img src=\"https://img.youtube.com/vi/" + videoId + "/0.jpg\" alt=\"\" width=\"\(textView.frame.width)\" /></a>")         // You could adjust the width and height to your liking

//Set the text of the textView
textView.attributedText = str3.htmlToAttributedString
textView.delegate = self

Чтобы открыть приложение Youtube, когда пользователь нажимает и удерживает изображение, реализуйте этот метод делегата:

extension NameOfYourViewController: UITextViewDelegate {
    func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
        UIApplication.shared.open(URL, options: [:])
        return true
    }
}

Если приложение YouTube не установлено, видео будет воспроизводиться в Safari.

Вот результат:

Youtube in a UITextField

0 голосов
/ 29 сентября 2018

Изменяет ваши параметры на:

let options: [NSAttributedString.DocumentReadingOptionKey: Any] = [
                NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.html,
                NSAttributedString.DocumentReadingOptionKey.characterEncoding: String.Encoding.utf8.rawValue
            ]
0 голосов
/ 25 сентября 2018

Похоже, проблема в теге, не каждый тег может отображаться в uitextview.Вы можете лучше отобразить эти теги в uiwebview

Я думаю, что проблема заключается в теге iframe.

Для отображения iFrame вместо этого используйте uiwebview или wkwebview.

Спасибо

...