update
This commit is contained in:
37
Pods/CocoaDebug/Sources/App/AboutViewController.swift
generated
Normal file
37
Pods/CocoaDebug/Sources/App/AboutViewController.swift
generated
Normal file
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// Example
|
||||
// man
|
||||
//
|
||||
// Created by man 11/11/2018.
|
||||
// Copyright © 2020 man. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
class AboutViewController: UITableViewController {
|
||||
|
||||
@IBOutlet weak var versionLabel: UILabel!
|
||||
@IBOutlet weak var naviItem: UINavigationItem!
|
||||
|
||||
var naviItemTitleLabel: UILabel?
|
||||
|
||||
//MARK: - init
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
naviItemTitleLabel = UILabel.init(frame: CGRect(x: 0, y: 0, width: 80, height: 40))
|
||||
naviItemTitleLabel?.textAlignment = .center
|
||||
naviItemTitleLabel?.textColor = Color.mainGreen
|
||||
naviItemTitleLabel?.font = .boldSystemFont(ofSize: 20)
|
||||
naviItemTitleLabel?.text = "About"
|
||||
naviItem.titleView = naviItemTitleLabel
|
||||
|
||||
|
||||
// let version = "1.7.2"
|
||||
//
|
||||
// self.versionLabel.text = "CocoaDebug Version ".appending(version)
|
||||
|
||||
tableView.tableFooterView = UIView()
|
||||
}
|
||||
}
|
||||
217
Pods/CocoaDebug/Sources/App/AppInfoViewController.swift
generated
Normal file
217
Pods/CocoaDebug/Sources/App/AppInfoViewController.swift
generated
Normal file
@@ -0,0 +1,217 @@
|
||||
//
|
||||
// Example
|
||||
// man
|
||||
//
|
||||
// Created by man 11/11/2018.
|
||||
// Copyright © 2020 man. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class AppInfoViewController: UITableViewController {
|
||||
|
||||
@IBOutlet weak var labelVersionNumber: UILabel!
|
||||
@IBOutlet weak var labelBuildNumber: UILabel!
|
||||
@IBOutlet weak var labelBundleName: UILabel!
|
||||
@IBOutlet weak var labelScreenResolution: UILabel!
|
||||
@IBOutlet weak var labelDeviceModel: UILabel!
|
||||
@IBOutlet weak var labelCrashCount: UILabel!
|
||||
@IBOutlet weak var labelBundleID: UILabel!
|
||||
@IBOutlet weak var labelserverURL: UILabel!
|
||||
@IBOutlet weak var labelIOSVersion: UILabel!
|
||||
@IBOutlet weak var labelHtml: UILabel!
|
||||
@IBOutlet weak var crashSwitch: UISwitch!
|
||||
@IBOutlet weak var logSwitch: UISwitch!
|
||||
@IBOutlet weak var networkSwitch: UISwitch!
|
||||
@IBOutlet weak var webViewSwitch: UISwitch!
|
||||
@IBOutlet weak var slowAnimationsSwitch: UISwitch!
|
||||
@IBOutlet weak var naviItem: UINavigationItem!
|
||||
@IBOutlet weak var rnSwitch: UISwitch!
|
||||
@IBOutlet weak var uiBlockingSwitch: UISwitch!
|
||||
|
||||
var naviItemTitleLabel: UILabel?
|
||||
|
||||
//MARK: - init
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
naviItemTitleLabel = UILabel.init(frame: CGRect(x: 0, y: 0, width: 80, height: 40))
|
||||
naviItemTitleLabel?.textAlignment = .center
|
||||
naviItemTitleLabel?.textColor = Color.mainGreen
|
||||
naviItemTitleLabel?.font = .boldSystemFont(ofSize: 20)
|
||||
naviItemTitleLabel?.text = "App"
|
||||
naviItem.titleView = naviItemTitleLabel
|
||||
|
||||
labelCrashCount.frame.size = CGSize(width: 30, height: 20)
|
||||
|
||||
labelVersionNumber.text = CocoaDebugDeviceInfo.sharedInstance().appVersion
|
||||
labelBuildNumber.text = CocoaDebugDeviceInfo.sharedInstance().appBuiltVersion
|
||||
labelBundleName.text = CocoaDebugDeviceInfo.sharedInstance().appBundleName
|
||||
|
||||
labelScreenResolution.text = "\(Int(CocoaDebugDeviceInfo.sharedInstance().resolution.width))" + "*" + "\(Int(CocoaDebugDeviceInfo.sharedInstance().resolution.height))"
|
||||
labelDeviceModel.text = "\(CocoaDebugDeviceInfo.sharedInstance().getPlatformString)"
|
||||
|
||||
labelBundleID.text = CocoaDebugDeviceInfo.sharedInstance().appBundleID
|
||||
|
||||
labelserverURL.text = CocoaDebugSettings.shared.serverURL
|
||||
labelIOSVersion.text = UIDevice.current.systemVersion
|
||||
|
||||
if UIScreen.main.bounds.size.width == 320 {
|
||||
labelHtml.font = UIFont.systemFont(ofSize: 15)
|
||||
}
|
||||
|
||||
logSwitch.isOn = CocoaDebugSettings.shared.enableLogMonitoring
|
||||
networkSwitch.isOn = !CocoaDebugSettings.shared.disableNetworkMonitoring
|
||||
rnSwitch.isOn = CocoaDebugSettings.shared.enableRNMonitoring
|
||||
webViewSwitch.isOn = CocoaDebugSettings.shared.enableWKWebViewMonitoring
|
||||
slowAnimationsSwitch.isOn = CocoaDebugSettings.shared.slowAnimations
|
||||
crashSwitch.isOn = CocoaDebugSettings.shared.enableCrashRecording
|
||||
uiBlockingSwitch.isOn = CocoaDebugSettings.shared.enableUIBlockingMonitoring
|
||||
|
||||
logSwitch.addTarget(self, action: #selector(logSwitchChanged), for: UIControl.Event.valueChanged)
|
||||
networkSwitch.addTarget(self, action: #selector(networkSwitchChanged), for: UIControl.Event.valueChanged)
|
||||
rnSwitch.addTarget(self, action: #selector(rnSwitchChanged), for: UIControl.Event.valueChanged)
|
||||
webViewSwitch.addTarget(self, action: #selector(webViewSwitchChanged), for: UIControl.Event.valueChanged)
|
||||
slowAnimationsSwitch.addTarget(self, action: #selector(slowAnimationsSwitchChanged), for: UIControl.Event.valueChanged)
|
||||
crashSwitch.addTarget(self, action: #selector(crashSwitchChanged), for: UIControl.Event.valueChanged)
|
||||
uiBlockingSwitch.addTarget(self, action: #selector(uiBlockingSwitchChanged), for: UIControl.Event.valueChanged)
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
let count = UserDefaults.standard.integer(forKey: "crashCount_CocoaDebug")
|
||||
labelCrashCount.text = "\(count)"
|
||||
labelCrashCount.textColor = count > 0 ? .red : .white
|
||||
}
|
||||
|
||||
//MARK: - alert
|
||||
func showAlert() {
|
||||
let alert = UIAlertController.init(title: nil, message: "You must restart APP to ensure the changes take effect", preferredStyle: .alert)
|
||||
let cancelAction = UIAlertAction.init(title: "Restart later", style: .cancel, handler: nil)
|
||||
let okAction = UIAlertAction.init(title: "Restart now", style: .destructive) { _ in
|
||||
exit(0)
|
||||
}
|
||||
|
||||
alert.addAction(cancelAction)
|
||||
alert.addAction(okAction)
|
||||
|
||||
alert.popoverPresentationController?.permittedArrowDirections = .init(rawValue: 0)
|
||||
alert.popoverPresentationController?.sourceView = self.view
|
||||
alert.popoverPresentationController?.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
|
||||
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
//MARK: - target action
|
||||
@objc func slowAnimationsSwitchChanged(sender: UISwitch) {
|
||||
CocoaDebugSettings.shared.slowAnimations = slowAnimationsSwitch.isOn
|
||||
// self.showAlert()
|
||||
}
|
||||
|
||||
@objc func uiBlockingSwitchChanged(sender: UISwitch) {
|
||||
CocoaDebugSettings.shared.enableUIBlockingMonitoring = uiBlockingSwitch.isOn
|
||||
if uiBlockingSwitch.isOn == true {
|
||||
WindowHelper.shared.startUIBlockingMonitoring()
|
||||
} else {
|
||||
WindowHelper.shared.stopUIBlockingMonitoring()
|
||||
}
|
||||
}
|
||||
|
||||
@objc func crashSwitchChanged(sender: UISwitch) {
|
||||
CocoaDebugSettings.shared.enableCrashRecording = crashSwitch.isOn
|
||||
self.showAlert()
|
||||
}
|
||||
|
||||
@objc func networkSwitchChanged(sender: UISwitch) {
|
||||
CocoaDebugSettings.shared.disableNetworkMonitoring = !networkSwitch.isOn
|
||||
self.showAlert()
|
||||
}
|
||||
|
||||
@objc func logSwitchChanged(sender: UISwitch) {
|
||||
CocoaDebugSettings.shared.enableLogMonitoring = logSwitch.isOn
|
||||
self.showAlert()
|
||||
}
|
||||
|
||||
@objc func rnSwitchChanged(sender: UISwitch) {
|
||||
CocoaDebugSettings.shared.enableRNMonitoring = rnSwitch.isOn
|
||||
self.showAlert()
|
||||
}
|
||||
|
||||
@objc func webViewSwitchChanged(sender: UISwitch) {
|
||||
CocoaDebugSettings.shared.enableWKWebViewMonitoring = webViewSwitch.isOn
|
||||
self.showAlert()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//MARK: - UITableViewDelegate
|
||||
extension AppInfoViewController {
|
||||
|
||||
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat
|
||||
{
|
||||
if section == 0 {
|
||||
return 56
|
||||
}
|
||||
return 38
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
|
||||
{
|
||||
if indexPath.section == 1 && indexPath.row == 4 {
|
||||
if labelserverURL.text == nil || labelserverURL.text == "" {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
return 44
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
|
||||
{
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
|
||||
if indexPath.section == 1 && indexPath.row == 2 {
|
||||
UIPasteboard.general.string = CocoaDebugDeviceInfo.sharedInstance().appBundleName
|
||||
|
||||
let alert = UIAlertController.init(title: "copied bundle name to clipboard", message: nil, preferredStyle: .alert)
|
||||
let action = UIAlertAction.init(title: "OK", style: .cancel, handler: nil)
|
||||
alert.addAction(action)
|
||||
|
||||
alert.popoverPresentationController?.permittedArrowDirections = .init(rawValue: 0)
|
||||
alert.popoverPresentationController?.sourceView = self.view
|
||||
alert.popoverPresentationController?.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
|
||||
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
if indexPath.section == 1 && indexPath.row == 3 {
|
||||
UIPasteboard.general.string = CocoaDebugDeviceInfo.sharedInstance().appBundleID
|
||||
|
||||
let alert = UIAlertController.init(title: "copied bundle id to clipboard", message: nil, preferredStyle: .alert)
|
||||
let action = UIAlertAction.init(title: "OK", style: .cancel, handler: nil)
|
||||
alert.addAction(action)
|
||||
|
||||
alert.popoverPresentationController?.permittedArrowDirections = .init(rawValue: 0)
|
||||
alert.popoverPresentationController?.sourceView = self.view
|
||||
alert.popoverPresentationController?.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
|
||||
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
if indexPath.section == 1 && indexPath.row == 4 {
|
||||
if labelserverURL.text == nil || labelserverURL.text == "" {return}
|
||||
|
||||
UIPasteboard.general.string = CocoaDebugSettings.shared.serverURL
|
||||
|
||||
let alert = UIAlertController.init(title: "copied server to clipboard", message: nil, preferredStyle: .alert)
|
||||
let action = UIAlertAction.init(title: "OK", style: .cancel, handler: nil)
|
||||
alert.addAction(action)
|
||||
|
||||
alert.popoverPresentationController?.permittedArrowDirections = .init(rawValue: 0)
|
||||
alert.popoverPresentationController?.sourceView = self.view
|
||||
alert.popoverPresentationController?.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
|
||||
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
41
Pods/CocoaDebug/Sources/App/CrashCell.swift
generated
Normal file
41
Pods/CocoaDebug/Sources/App/CrashCell.swift
generated
Normal file
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// Example
|
||||
// man
|
||||
//
|
||||
// Created by man 11/11/2018.
|
||||
// Copyright © 2020 man. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class CrashCell: UITableViewCell {
|
||||
|
||||
@IBOutlet weak var textview: CustomTextView!
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
textview.isUserInteractionEnabled = false
|
||||
}
|
||||
|
||||
var crash: _CrashModel? {
|
||||
didSet {
|
||||
guard let crash = crash else {return}
|
||||
|
||||
if let formatDate = _OCLoggerFormat.formatDate(crash.date) {
|
||||
let content = "\("\(String(describing: formatDate))\n")\(crash.name ?? "unknown crash")"
|
||||
|
||||
textview.text = content
|
||||
let attstr = NSMutableAttributedString(string: content)
|
||||
|
||||
attstr.addAttribute(.foregroundColor,
|
||||
value: UIColor.white, range: NSMakeRange(0, content.count))
|
||||
|
||||
let range = NSMakeRange(0, formatDate.count)
|
||||
attstr.addAttribute(.foregroundColor, value: Color.mainGreen, range: range)
|
||||
attstr.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: 12), range: range)
|
||||
|
||||
textview.attributedText = attstr
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
62
Pods/CocoaDebug/Sources/App/CrashDetailViewController.swift
generated
Normal file
62
Pods/CocoaDebug/Sources/App/CrashDetailViewController.swift
generated
Normal file
@@ -0,0 +1,62 @@
|
||||
//
|
||||
// Example
|
||||
// man
|
||||
//
|
||||
// Created by man 11/11/2018.
|
||||
// Copyright © 2020 man. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class CrashDetailViewController: UITableViewController {
|
||||
|
||||
@IBOutlet weak var textviewName: CustomTextView!
|
||||
@IBOutlet weak var textviewReason: CustomTextView!
|
||||
@IBOutlet weak var textviewStackTraces: CustomTextView!
|
||||
@IBOutlet weak var naviItem: UINavigationItem!
|
||||
|
||||
var naviItemTitleLabel: UILabel?
|
||||
|
||||
var crash: _CrashModel?
|
||||
|
||||
static func instanceFromStoryBoard() -> CrashDetailViewController {
|
||||
let storyboard = UIStoryboard(name: "App", bundle: Bundle(for: CocoaDebug.self))
|
||||
return storyboard.instantiateViewController(withIdentifier: "CrashDetailViewController") as! CrashDetailViewController
|
||||
}
|
||||
|
||||
//MARK - init
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
naviItemTitleLabel = UILabel.init(frame: CGRect(x: 0, y: 0, width: 80, height: 40))
|
||||
naviItemTitleLabel?.textAlignment = .center
|
||||
naviItemTitleLabel?.textColor = Color.mainGreen
|
||||
naviItemTitleLabel?.font = .boldSystemFont(ofSize: 20)
|
||||
naviItemTitleLabel?.text = "Details"
|
||||
naviItem.titleView = naviItemTitleLabel
|
||||
|
||||
tableView.rowHeight = UITableView.automaticDimension
|
||||
tableView.estimatedRowHeight = 50
|
||||
tableView.delegate = self
|
||||
|
||||
textviewName.text = "\(crash?.name ?? "N/A")"
|
||||
textviewReason.text = "\(crash?.reason ?? "N/A")"
|
||||
|
||||
let contentStack = crash?.callStacks?.reduce("", {
|
||||
$0 == "" ? $1 : $0 + "\n" + $1
|
||||
})
|
||||
textviewStackTraces.text = contentStack
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: - UITableViewDelegate
|
||||
extension CrashDetailViewController {
|
||||
|
||||
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
|
||||
return UITableView.automaticDimension
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
|
||||
return 50
|
||||
}
|
||||
}
|
||||
115
Pods/CocoaDebug/Sources/App/CrashListViewController.swift
generated
Normal file
115
Pods/CocoaDebug/Sources/App/CrashListViewController.swift
generated
Normal file
@@ -0,0 +1,115 @@
|
||||
//
|
||||
// Example
|
||||
// man
|
||||
//
|
||||
// Created by man 11/11/2018.
|
||||
// Copyright © 2020 man. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class CrashListViewController: UITableViewController {
|
||||
|
||||
var models: [_CrashModel] = [_CrashModel]()
|
||||
|
||||
@IBOutlet weak var naviItem: UINavigationItem!
|
||||
|
||||
var naviItemTitleLabel: UILabel?
|
||||
|
||||
//MARK: - init
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
naviItemTitleLabel = UILabel.init(frame: CGRect(x: 0, y: 0, width: 80, height: 40))
|
||||
naviItemTitleLabel?.textAlignment = .center
|
||||
naviItemTitleLabel?.textColor = Color.mainGreen
|
||||
naviItemTitleLabel?.font = .boldSystemFont(ofSize: 20)
|
||||
naviItemTitleLabel?.text = "Crash"
|
||||
naviItem.titleView = naviItemTitleLabel
|
||||
|
||||
|
||||
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .trash, target: self, action:#selector(CrashListViewController.deleteCrashes))
|
||||
|
||||
tableView.delegate = self
|
||||
tableView.dataSource = self
|
||||
tableView.tableFooterView = UIView()
|
||||
|
||||
models = CrashStoreManager.shared.crashArray
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
||||
//MARK: - target action
|
||||
@objc func deleteCrashes() {
|
||||
models = []
|
||||
CrashStoreManager.shared.resetCrashs()
|
||||
|
||||
// dispatch_main_async_safe { [weak self] in
|
||||
tableView.reloadData()
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: - UITableViewDataSource
|
||||
extension CrashListViewController {
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return models.count
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "CrashCell", for: indexPath)
|
||||
as! CrashCell
|
||||
cell.crash = models[indexPath.row]
|
||||
cell.accessoryType = .none
|
||||
return cell
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: - UITableViewDelegate
|
||||
extension CrashListViewController {
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
|
||||
let vc = CrashDetailViewController.instanceFromStoryBoard()
|
||||
vc.crash = models[indexPath.row]
|
||||
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
}
|
||||
|
||||
@available(iOS 11.0, *)
|
||||
override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
|
||||
|
||||
let delete = UIContextualAction(style: .destructive, title: "Delete") { [weak self] (action, sourceView, completionHandler) in
|
||||
guard let models = self?.models else {return}
|
||||
CrashStoreManager.shared.removeCrash(models[indexPath.row])
|
||||
self?.models.remove(at: indexPath.row)
|
||||
// self?.dispatch_main_async_safe { [weak self] in
|
||||
self?.tableView.deleteRows(at: [indexPath], with: .automatic)
|
||||
// }
|
||||
completionHandler(true)
|
||||
}
|
||||
|
||||
return UISwipeActionsConfiguration(actions: [delete])
|
||||
}
|
||||
|
||||
//MARK: - only for ios8/ios9/ios10, not ios11
|
||||
override func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
|
||||
return .delete
|
||||
}
|
||||
override func tableView(_ tableView: UITableView, titleForDeleteConfirmationButtonForRowAt indexPath: IndexPath) -> String? {
|
||||
return "Delete"
|
||||
}
|
||||
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
|
||||
return true
|
||||
}
|
||||
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
|
||||
if (editingStyle == .delete) {
|
||||
CrashStoreManager.shared.removeCrash(models[indexPath.row])
|
||||
self.models.remove(at: indexPath.row)
|
||||
// self.dispatch_main_async_safe { [weak self] in
|
||||
self.tableView.deleteRows(at: [indexPath], with: .automatic)
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
98
Pods/CocoaDebug/Sources/App/CrashLogger.swift
generated
Normal file
98
Pods/CocoaDebug/Sources/App/CrashLogger.swift
generated
Normal file
@@ -0,0 +1,98 @@
|
||||
//
|
||||
// Example
|
||||
// man
|
||||
//
|
||||
// Created by man 11/11/2018.
|
||||
// Copyright © 2020 man. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Darwin
|
||||
|
||||
func exceptionHandler(exception: NSException) {
|
||||
if CrashLogger.shared.crashed {
|
||||
return
|
||||
}
|
||||
CrashLogger.shared.crashed = true
|
||||
CrashLogger.addCrash(name: exception.name.rawValue, reason: exception.reason)
|
||||
}
|
||||
|
||||
func handleSignal(signal: Int32) {
|
||||
if CrashLogger.shared.crashed {
|
||||
return
|
||||
}
|
||||
CrashLogger.shared.crashed = true
|
||||
switch signal {
|
||||
case SIGILL:
|
||||
CrashLogger.addCrash(name: "SIGILL", reason: nil)
|
||||
case SIGABRT:
|
||||
CrashLogger.addCrash(name: "SIGABRT", reason: nil)
|
||||
case SIGFPE:
|
||||
CrashLogger.addCrash(name: "SIGFPE", reason: nil)
|
||||
case SIGBUS:
|
||||
CrashLogger.addCrash(name: "SIGBUS", reason: nil)
|
||||
case SIGSEGV:
|
||||
CrashLogger.addCrash(name: "SIGSEGV", reason: nil)
|
||||
case SIGSYS:
|
||||
CrashLogger.addCrash(name: "SIGSYS", reason: nil)
|
||||
case SIGPIPE:
|
||||
CrashLogger.addCrash(name: "SIGPIPE", reason: nil)
|
||||
case SIGTRAP:
|
||||
CrashLogger.addCrash(name: "SIGTRAP", reason: nil)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
||||
class CrashLogger {
|
||||
|
||||
static let shared = CrashLogger()
|
||||
private init() {}
|
||||
|
||||
var hasBeenRegistered = false
|
||||
var crashed = false
|
||||
var enable: Bool = false {
|
||||
didSet {
|
||||
if enable {
|
||||
CrashLogger.shared.register()
|
||||
}
|
||||
else {
|
||||
CrashLogger.shared.unregister()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func register() {
|
||||
if hasBeenRegistered == false {
|
||||
hasBeenRegistered = true
|
||||
NSSetUncaughtExceptionHandler(exceptionHandler)
|
||||
signal(SIGILL, handleSignal)
|
||||
signal(SIGABRT, handleSignal)
|
||||
signal(SIGFPE, handleSignal)
|
||||
signal(SIGBUS, handleSignal)
|
||||
signal(SIGSEGV, handleSignal)
|
||||
signal(SIGSYS, handleSignal)
|
||||
signal(SIGPIPE, handleSignal)
|
||||
signal(SIGTRAP, handleSignal)
|
||||
}
|
||||
}
|
||||
|
||||
func unregister() {
|
||||
if hasBeenRegistered == true {
|
||||
hasBeenRegistered = false
|
||||
NSSetUncaughtExceptionHandler(nil)
|
||||
signal(SIGILL, SIG_DFL)
|
||||
signal(SIGABRT, SIG_DFL)
|
||||
signal(SIGFPE, SIG_DFL)
|
||||
signal(SIGBUS, SIG_DFL)
|
||||
signal(SIGSEGV, SIG_DFL)
|
||||
signal(SIGSYS, SIG_DFL)
|
||||
signal(SIGPIPE, SIG_DFL)
|
||||
signal(SIGTRAP, SIG_DFL)
|
||||
}
|
||||
}
|
||||
|
||||
static func addCrash(name: String, reason: String?) {
|
||||
let newCrash = _CrashModel(name: name, reason: reason)
|
||||
CrashStoreManager.shared.addCrash(newCrash)
|
||||
}
|
||||
}
|
||||
79
Pods/CocoaDebug/Sources/App/CrashStoreManager.swift
generated
Normal file
79
Pods/CocoaDebug/Sources/App/CrashStoreManager.swift
generated
Normal file
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// Example
|
||||
// man
|
||||
//
|
||||
// Created by man 11/11/2018.
|
||||
// Copyright © 2020 man. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class CrashStoreManager {
|
||||
|
||||
var crashArray: [_CrashModel] = [_CrashModel]()
|
||||
|
||||
static let shared = CrashStoreManager()
|
||||
private init() {
|
||||
crashArray = self.getCrashs()
|
||||
}
|
||||
|
||||
//MARK: - public
|
||||
func addCrash(_ crash: _CrashModel) {
|
||||
if self.crashArray.count >= 1000 {
|
||||
if self.crashArray.count > 0 {
|
||||
self.crashArray.remove(at: 0)
|
||||
}
|
||||
}
|
||||
self.crashArray.append(crash)
|
||||
archiveCrashs(self.crashArray)
|
||||
}
|
||||
|
||||
func removeCrash(_ model: _CrashModel) {
|
||||
if let index = self.crashArray.firstIndex(where: { (crash) -> Bool in
|
||||
return crash.id == model.id
|
||||
}) {
|
||||
self.crashArray.remove(at: index)
|
||||
}
|
||||
archiveCrashs(self.crashArray)
|
||||
}
|
||||
|
||||
func resetCrashs() {
|
||||
if self.crashArray.count > 0 {
|
||||
self.crashArray.removeAll()
|
||||
UserDefaults.standard.removeObject(forKey: "crashArchive_CocoaDebug")
|
||||
UserDefaults.standard.removeObject(forKey: "crashCount_CocoaDebug")
|
||||
UserDefaults.standard.synchronize()
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: - private
|
||||
private func archiveCrashs(_ crashs: [_CrashModel]) {
|
||||
do {
|
||||
var dataArchive: Data
|
||||
if #available(iOS 11.0, *) {
|
||||
dataArchive = try NSKeyedArchiver.archivedData(withRootObject: crashs, requiringSecureCoding: false)
|
||||
} else {
|
||||
// Fallback on earlier versions
|
||||
dataArchive = NSKeyedArchiver.archivedData(withRootObject: crashs)
|
||||
}
|
||||
UserDefaults.standard.set(dataArchive, forKey: "crashArchive_CocoaDebug")
|
||||
UserDefaults.standard.set(crashs.count, forKey: "crashCount_CocoaDebug")
|
||||
UserDefaults.standard.synchronize()
|
||||
} catch {}
|
||||
}
|
||||
|
||||
private func getCrashs() -> [_CrashModel] {
|
||||
guard let data = UserDefaults.standard.object(forKey: "crashArchive_CocoaDebug") as? Data else {return []}
|
||||
do {
|
||||
if #available(iOS 9.0, *) {
|
||||
let dataArchive = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data)
|
||||
return dataArchive as! [_CrashModel]
|
||||
} else {
|
||||
// Fallback on earlier versions
|
||||
return []
|
||||
}
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
}
|
||||
}
|
||||
119
Pods/CocoaDebug/Sources/App/IgnoredURLsViewController.swift
generated
Normal file
119
Pods/CocoaDebug/Sources/App/IgnoredURLsViewController.swift
generated
Normal file
@@ -0,0 +1,119 @@
|
||||
//
|
||||
// Example
|
||||
// man
|
||||
//
|
||||
// Created by man 11/11/2018.
|
||||
// Copyright © 2020 man. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
class IgnoredURLsViewController: UITableViewController {
|
||||
|
||||
var ignoredURLs: Array<String>?
|
||||
var onlyURLs: Array<String>?
|
||||
|
||||
var ignoredPrefixLogs: Array<String>?
|
||||
var onlyPrefixLogs: Array<String>?
|
||||
|
||||
@IBOutlet weak var naviItem: UINavigationItem!
|
||||
|
||||
var naviItemTitleLabel: UILabel?
|
||||
|
||||
//MARK: - init
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
naviItemTitleLabel = UILabel.init(frame: CGRect(x: 0, y: 0, width: 80, height: 40))
|
||||
naviItemTitleLabel?.textAlignment = .center
|
||||
naviItemTitleLabel?.textColor = Color.mainGreen
|
||||
naviItemTitleLabel?.font = .boldSystemFont(ofSize: 20)
|
||||
naviItemTitleLabel?.text = "Settings"
|
||||
naviItem.titleView = naviItemTitleLabel
|
||||
|
||||
tableView.tableFooterView = UIView()
|
||||
|
||||
ignoredURLs = CocoaDebugSettings.shared.ignoredURLs
|
||||
onlyURLs = CocoaDebugSettings.shared.onlyURLs
|
||||
|
||||
ignoredPrefixLogs = CocoaDebugSettings.shared.ignoredPrefixLogs
|
||||
onlyPrefixLogs = CocoaDebugSettings.shared.onlyPrefixLogs
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: - UITableViewDataSource
|
||||
extension IgnoredURLsViewController {
|
||||
|
||||
override func numberOfSections(in tableView: UITableView) -> Int {
|
||||
return 4
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
switch section {
|
||||
case 0:
|
||||
return ignoredURLs?.count ?? 0
|
||||
case 1:
|
||||
return onlyURLs?.count ?? 0
|
||||
case 2:
|
||||
return ignoredPrefixLogs?.count ?? 0
|
||||
case 3:
|
||||
return onlyPrefixLogs?.count ?? 0
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = UITableViewCell.init(style: .default, reuseIdentifier: "CocoaDebugSettingsCell")
|
||||
cell.textLabel?.textColor = .white
|
||||
cell.contentView.backgroundColor = .black
|
||||
cell.selectionStyle = .none
|
||||
|
||||
switch indexPath.section {
|
||||
case 0:
|
||||
cell.textLabel?.text = ignoredURLs?[indexPath.row]
|
||||
case 1:
|
||||
cell.textLabel?.text = onlyURLs?[indexPath.row]
|
||||
case 2:
|
||||
cell.textLabel?.text = ignoredPrefixLogs?[indexPath.row]
|
||||
case 3:
|
||||
cell.textLabel?.text = onlyPrefixLogs?[indexPath.row]
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
return cell
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
|
||||
switch section {
|
||||
case 0:
|
||||
return "ignored URLs"
|
||||
case 1:
|
||||
return "only URLs"
|
||||
case 2:
|
||||
return "ignored Prefix Logs"
|
||||
case 3:
|
||||
return "only Prefix Logs"
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: - UITableViewDelegate
|
||||
extension IgnoredURLsViewController {
|
||||
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
|
||||
return 60
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
|
||||
return 20
|
||||
}
|
||||
}
|
||||
57
Pods/CocoaDebug/Sources/App/_CrashModel.swift
generated
Normal file
57
Pods/CocoaDebug/Sources/App/_CrashModel.swift
generated
Normal file
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// Example
|
||||
// man
|
||||
//
|
||||
// Created by man 11/11/2018.
|
||||
// Copyright © 2020 man. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class _CrashModel: NSObject, NSCoding {
|
||||
|
||||
var id: String
|
||||
var date: Date
|
||||
var reason: String?
|
||||
var name: String?
|
||||
var callStacks: [String]?
|
||||
|
||||
|
||||
init(name: String, reason: String?) {
|
||||
id = UUID().uuidString
|
||||
date = Date()
|
||||
self.reason = reason
|
||||
self.name = name
|
||||
callStacks = Thread.callStackSymbols
|
||||
}
|
||||
|
||||
func encode(with aCoder: NSCoder) {
|
||||
aCoder.encode(id, forKey: "id")
|
||||
aCoder.encode(date, forKey: "date")
|
||||
aCoder.encode(reason, forKey: "reason")
|
||||
aCoder.encode(name, forKey: "name")
|
||||
aCoder.encode(callStacks, forKey: "callstacks")
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
id = aDecoder.decodeObject(forKey: "id") as? String ?? ""
|
||||
date = aDecoder.decodeObject(forKey: "date") as? Date ?? Date()
|
||||
reason = aDecoder.decodeObject(forKey: "reason") as? String
|
||||
name = aDecoder.decodeObject(forKey: "name") as? String
|
||||
callStacks = aDecoder.decodeObject(forKey: "callstacks") as? [String]
|
||||
}
|
||||
|
||||
func toString() -> String {
|
||||
let stringContent = NSMutableString()
|
||||
stringContent.append("Date: \(String(describing: _OCLoggerFormat.formatDate(date)))\n")
|
||||
stringContent.append("Name: \(name ?? "N/A")\n")
|
||||
stringContent.append("Reason: \(reason ?? "N/A")\n")
|
||||
|
||||
let stacks = (callStacks ?? []).reduce("", {
|
||||
return "\($0)\($1)\n"
|
||||
})
|
||||
stringContent.append(stacks)
|
||||
return stringContent as String
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user