Swift.assert-发布后的生活

您在代码中多久使用Swift.assert() ? 老实说,我经常使用它(如果这是不好的做法,请在评论中写-为什么不好?)。 在我的代码中,您经常可以看到例如这样的调用:

 Swift.assert(Thread.isMainThread) 

不久前,我决定继续观察这些调用的结果将是一件很不错的事情,不仅是在模拟器/设备中启动应用程序的一部分,而且是真实用户的操作。 顺便说Swift.precondition() ,尽管我试图避免它们,但在这里我们可以谈论Swift.precondition()Swift.fatalError()等。 我在此出版物中阅读了更多有关Swift 不可恢复错误的信息,事实证明该信息非常有用。

更接近一点: 在代码中,我发现了大约300个此类调用。 他们都没有在通常的本地测试中工作,这让我感到很高兴。 但是我建议用户操作可能仍会触发某些调用。

从用户的角度来看,崩溃不应该发生(再次,我认为)。 在极端情况下,用户必须了解某些情况出现了错误,并且开发团队已经在进行修复。 类似的例外情况一直由我处理,对于用户而言,它可能以最无害的形式受到影响。 例如,数百个表格单元之一只是不可见。

随着用户或多或少,一切都变得清晰了。 它仍然需要处理将日志交付给开发人员的问题。 首先,需要以最小的努力将代码中的当前调用替换为在应用程序外部发送日志的调用。 其次,必须准确定位事件现场,否则实际上将异常与实际代码相关联是不可能的。 第三,应该注意的是,修改后的调用可以在单元测试期间工作,其中Thread.isMainThread应该已经被忽略。 我将RxTest框架用于某些类型的测试(在这里我也准备倾听建议和批评)。 要点仍然是本地所有异常都应像以前一样触发,即 Loggin.assert()应该在Loggin.assert()触发的同时触发

FabricCrashlytics )提供了一种发送事件的好方法。 看起来像这样:

 Crashlytics.sharedInstance().recordCustomExceptionName("", reason: ""... 

它仍然可以将Crashlytics打包到某个框架中,该框架可以完整地加载到应用程序中,并且可以在测试目标中以截短的形式(没有Crashlytics依赖项) 加载

我决定通过CocoaPods进行“ 包装 ”:

 Pod::Spec.new do |s| s.name = 'Logging' ... s.subspec 'Base' do |ss| ss.source_files = 'Source/Logging+Base.swift' ss.dependency 'Crashlytics' end s.subspec 'Test' do |ss| ss.source_files = 'Source/Logging+Test.swift' end end 

“作战目标”的代码如下:

 import Crashlytics public enum Logging { public static func send(_ reason: String? = nil, __file: String = #file, __line: Int = #line) { let file = __file.components(separatedBy: "/").last ?? __file let line = "\(__line)" let name = [line, file].joined(separator: "_") Crashlytics.sharedInstance().recordCustomExceptionName(name, reason: reason ?? "no reason", frameArray: []) } public static func assert(_ assertion: @escaping @autoclosure () -> Bool, reason: String? = nil, __file: String = #file, __line: Int = #line) { if assertion() == false { self.assertionFailure(reason, __file: __file, __line: __line) } } public static func assert(_ assertion: @escaping () -> Bool, reason: String? = nil, __file: String = #file, __line: Int = #line) { if assertion() == false { self.assertionFailure(reason, __file: __file, __line: __line) } } public static func assertionFailure(_ reason: String? = nil, __file: String = #file, __line: Int = #line) { Swift.assertionFailure(reason ?? "") self.send(reason, __file: __file, __line: __line) } } 

对于“测试目标”,即 没有Crashlytics依赖性:

 import Foundation public enum Logging { public static func send(_ reason: String? = nil, __file: String = #file, __line: Int = #line) { // } public static func assert(_ assertion: @escaping @autoclosure () -> Bool, reason: String? = nil, __file: String = #file, __line: Int = #line) { // } public static func assert(_ assertion: @escaping () -> Bool, reason: String? = nil, __file: String = #file, __line: Int = #line) { // } public static func assertionFailure(_ reason: String? = nil, __file: String = #file, __line: Int = #line) { // } } 

结果:


异常确实开始起作用。 他们中的大多数报告接收到的数据格式不正确:有时可Decodable接收到的数据具有Decodable类型。 有时Thread.isMainThread的日志有效,在接下来的发行版中很快对此进行了修复。 NSException奇迹般地捕获了最有趣的错误。

谢谢您的关注。

PS:如果您经常将此类日志发送给Crashlytics ,则该服务可能会将您的操作识别为垃圾邮件。 您将看到以下消息:
由于使用不当,非致命报告已针对多个版本禁用。 在我们的文档中了解如何重新启用报告。
因此,值得事先考虑发送日志的频率。 否则,所有构建日志都有被Crashlytics忽略的危险。

Source: https://habr.com/ru/post/zh-CN476792/


All Articles