【问题标题】:Error handling optimization错误处理优化
【发布时间】:2016-01-08 21:37:18
【问题描述】:

我只是在玩 2.0 版中的新错误处理。我现在有了以下功能:

func decodeHTML(HTML: String) throws {
    guard let remove : String? = HTML.componentsSeparatedByString("<div id=\"loading\" style=\"display: none;\">")[0] else { throw DecodeError.MatchError }
    guard var splitter : [String]? = remove!.componentsSeparatedByString("<div class=\"info\">") else { throw DecodeError.MatchError }
    if splitter!.count > 0 { splitter!.removeFirst() }
    if splitter!.count > 0 { splitter!.removeLast() }

    if splitter!.count > 0 {
        for HTMLmessage in splitter! {
            guard var splitter2 : [String]? = HTMLmessage.componentsSeparatedByString("</td><td>Besked fra ") else { throw DecodeError.MatchError }
            guard let author : String? = (splitter2![1].componentsSeparatedByString("</tr>"))[0] else { throw DecodeError.MatchError }
            guard let date : String? = (splitter2![0].componentsSeparatedByString("<td width=\"25%\">"))[1] else { throw DecodeError.MatchError }
            guard let title : String? = HTMLmessage.componentsSeparatedByString("\"><b>")[1].componentsSeparatedByString("</b></a></td></tr>")[0] else { throw DecodeError.MatchError }
            guard var string : String? = HTMLmessage.componentsSeparatedByString("</a></td></tr><tr><td colspan=2>")[1].componentsSeparatedByString("</td></tr></table></div>")[0] else { throw DecodeError.MatchError }
            string = string!.stringByReplacingOccurrencesOfString("</p><p>", withString: "\n")
            string = string!.stringByReplacingOccurrencesOfString("<[^>]+>", withString: "", options: .RegularExpressionSearch, range: nil)

            self.messages.append(message(author, date, title, string))
        }
    } else {
        throw DecodeError.MatchError
    }
}

但我想知道,我真的必须在每次出现问题时都保持警惕吗?如果其中一行失败,是否有更简单的方法来引发错误?

【问题讨论】:

  • 由于您抛出相同的错误,您可以将所有条件放在一个保护块中。
  • 请注意(至少在 Swift 2.0 中)componentsSeparatedByString() 返回一个 非可选 [String] 数组。如果数组太短,下标(使用[0][1] ...)也不会返回可选值,但会因运行时异常而中止。 – 换句话说,您的大多数受保护绑定都没有按您可能期望的那样工作。
  • 如果你删除所有显式类型注释,例如: String?,让编译器推断类型,你的问题会变得更加明显。
  • 顺便说一句。你的“解码”方法对我来说看起来很脆弱。使用适当的 HTML 解析库可能会更好。
  • 考虑使用基于libxml的HTML解析器

标签: swift throw


【解决方案1】:

我稍微清理了你的函数:

extension String {
    func split(string: String) -> [String] { return componentsSeparatedByString(string) }
}

extension Array {
    var second : Element? { return dropFirst().first }
}

func decodeHTML(HTML: String) throws {
    guard let
        splitter = HTML
            .split("<div id=\"loading\" style=\"display: none;\">").first?
            .split("<div class=\"info\">").dropFirst().dropLast()
    where !splitter.isEmpty else {
        throw DecodeError.MatchError
    }

    for HTMLmessage in splitter {
        let splitter2 = HTMLmessage.split("</td><td>Besked fra ")

        guard let
            author = splitter2.second?
                .split("</tr>").first,
            date = splitter2.first?
                .split("<td width=\"25%\">").second,
            title = HTMLmessage
                .split("\"><b>").second?
                .split("</b></a></td></tr>").first,
            string = HTMLmessage
                .split("</a></td></tr><tr><td colspan=2>").second?
                .split("</td></tr></table></div>").first?
                .stringByReplacingOccurrencesOfString("</p><p>", withString: "\n")
                .stringByReplacingOccurrencesOfString("<[^>]+>", withString: "", options: .RegularExpressionSearch, range: nil)
        else {
            throw DecodeError.MatchError
        }

        let message = (author, date, title, string)

    }
}

您可以使用dropFirstdropLastfirst 安全地访问元素。不过,您可能真的应该使用 HTML 解析库。

【讨论】:

  • 您好,非常感谢您花时间和精力来查看我的代码。我真的可以看到,您如何优化它以及您创建的代码多么漂亮。我将从中学习并查看一个 HTML 解析库。谢谢!
【解决方案2】:

我建议你创建一个包装函数:

func componentsSeparatedByString(string: String) throws -> String {
    let texts = HTMLmessage.componentsSeparatedByString(string)

    if texts.count > 0
        return texts[0]
    } else {
        throw DecodeError.MatchError
    }
}

现在您可以多次调用此函数并使用单个 catch 块:

do {
    let text1 = try componentsSeparatedByString("text1")
    let text2 = try componentsSeparatedByString("text2")
    let text3 = try componentsSeparatedByString("text3")
} catch {
    print("Something went wrong!")
}

【讨论】:

  • @MartinR 这只是一个概念。我没有测试过:)
  • 正如我上面所说,componentsSeparatedByString() 返回一个非可选的字符串数组。
  • 那(仍然)无法编译。除非你解释包装函数应该做什么,否则你的“概念”对我来说是不清楚的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-08-08
  • 2022-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-25
相关资源
最近更新 更多