Seberapa sering Anda menggunakan 
Swift.assert() dalam kode Anda? Jujur saya cukup sering menggunakannya (Jika ini adalah praktik yang buruk, maka silakan tulis di komentar - mengapa itu buruk?). Dalam kode saya, Anda sering dapat melihat, misalnya, panggilan seperti itu:
 Swift.assert(Thread.isMainThread) 
Belum lama ini, saya memutuskan bahwa akan menyenangkan untuk terus mengamati hasil dari panggilan ini, tidak hanya sebagai bagian dari peluncuran aplikasi di simulator / perangkat, tetapi juga dari tindakan pengguna nyata. Ngomong-ngomong, di sini kita dapat berbicara tentang 
Swift.precondition() , 
Swift.fatalError() , dll., Walaupun saya mencoba menghindarinya. Saya membaca lebih lanjut tentang 
Kesalahan yang Tidak Dapat Dipulihkan di Swift dalam publikasi ini dan ternyata sangat informatif.
Lebih dekat ke titik: 
dalam kode saya menemukan sekitar 300 panggilan seperti itu. Tak satu pun dari mereka bekerja selama pengujian lokal yang biasa, dan itu menyenangkan saya. Tetapi saya menyarankan bahwa tindakan pengguna mungkin masih memicu beberapa panggilan.
Dari sudut pandang pengguna, crash seharusnya tidak terjadi (sekali lagi, menurut saya). Dalam kasus yang ekstrim, pengguna harus memahami bahwa beberapa skenario salah dan tim pengembang sudah bekerja untuk memperbaikinya. Pengecualian serupa selalu ditangani oleh saya, dan bagi pengguna itu bisa berdampak pada bentuk yang paling tidak berbahaya. Sebagai contoh, salah satu dari ratusan sel tabel tidak terlihat.
Dengan pengguna lebih atau kurang semuanya jelas. Masih berurusan dengan pengiriman log ke pengembang. Pertama, diperlukan upaya minimal untuk mengganti panggilan saat ini dalam kode dengan panggilan mengirim log di suatu tempat di luar aplikasi. Kedua, itu perlu untuk secara akurat melokalisasi tempat kejadian, jika tidak praktis tidak mungkin untuk menghubungkan pengecualian dengan kode nyata. Ketiga, harus dicatat bahwa panggilan yang dimodifikasi dapat bekerja selama pengujian Unit, di mana 
Thread.isMainThread seharusnya sudah diabaikan. Saya menggunakan kerangka kerja 
RxTest untuk jenis pengujian tertentu (di sini saya juga siap mendengarkan saran dan kritik). Poin utama tetap bahwa secara lokal semua pengecualian harus dipicu seperti sebelumnya, yaitu 
Loggin.assert() harus memecat pada saat yang sama bahwa 
Swift.assert() akan memecat
Fabric ( 
Crashlytics ) menyediakan cara hebat untuk mengirim acara. Ini terlihat seperti ini:
 Crashlytics.sharedInstance().recordCustomExceptionName("", reason: ""... 
Masih mengemas 
Crashlytics ke dalam beberapa kerangka kerja yang dapat dimuat 
secara keseluruhan ke dalam aplikasi dan dalam bentuk terpotong (tanpa ketergantungan 
Crashlytics ) dalam target pengujian.
Saya memutuskan untuk melakukan " 
pengemasan " melalui 
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 
Kode untuk "target tempur" adalah sebagai berikut:
 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) } } 
Untuk "target pengujian" yaitu tanpa ketergantungan 
Crashlytics :
 import Foundation public enum Logging { public static func send(_ reason: String? = nil, __file: String = #file, __line: Int = #line) {  
Hasil:
Pengecualian benar-benar mulai bekerja. Sebagian besar dari mereka melaporkan format yang salah untuk data yang diterima: 
Decodable terkadang menerima data dengan tipe yang 
Decodable . Terkadang log untuk 
Thread.isMainThread berfungsi, yang sangat cepat diperbaiki di rilis berikutnya. Kesalahan paling menarik secara ajaib ditangkap oleh 
NSException .
Terima kasih atas perhatian anda
NB Jika Anda terlalu sering mengirim log seperti itu ke 
Crashlytics , layanan ini dapat mengenali tindakan Anda sebagai spam. Dan Anda akan melihat pesan berikut:
Karena penggunaan yang tidak tepat, pelaporan non-fatal telah dinonaktifkan untuk beberapa bangunan. Pelajari cara mengaktifkan kembali pelaporan dalam dokumentasi kami.
Oleh karena itu, perlu mempertimbangkan terlebih dahulu frekuensi pengiriman log. Jika tidak, semua log bangunan mungkin dalam bahaya diabaikan oleh 
Crashlytics.