This commit is contained in:
DDIsFriend
2023-08-23 09:24:40 +08:00
parent 6bd037c5dd
commit 63ca919ed5
494 changed files with 35308 additions and 6623 deletions

View File

@@ -0,0 +1,31 @@
//
// CocoaDebugTool.h
// Example_Swift
//
// Created by man 5/8/19.
// Copyright © 2020 man. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface CocoaDebugTool : NSObject
/// log with string,
/// default color is white
+ (void)logWithString:(NSString *)string;
+ (void)logWithString:(NSString *)string color:(UIColor *)color;
/// log with JSON Data,
/// default color is white,
/// return string
+ (NSString *)logWithJsonData:(NSData *)data;
+ (NSString *)logWithJsonData:(NSData *)data color:(UIColor *)color;
/// log with Protobuf Data,
/// default color is white,
/// return string
//+ (NSString *)logWithProtobufData:(NSData *)data className:(NSString *)className;
//+ (NSString *)logWithProtobufData:(NSData *)data className:(NSString *)className color:(UIColor *)color;
@end

View File

@@ -0,0 +1,103 @@
//
// CocoaDebugTool.m
// Example_Swift
//
// Created by man 5/8/19.
// Copyright © 2020 man. All rights reserved.
//
#import "CocoaDebugTool.h"
#import "_OCLogHelper.h"
#import "GPBMessage+CocoaDebug.h"
//#import "GPBMessage.h"
@implementation CocoaDebugTool
#pragma mark - logWithString
+ (void)logWithString:(NSString *)string {
[self logWithString:string color:[UIColor colorWithRed:1 green:1 blue:1 alpha:1]];
}
+ (void)logWithString:(NSString *)string color:(UIColor *)color {
[self finalLogWithString:string type:CocoaDebugToolTypeNone color:color];
}
#pragma mark - logWithJsonData
+ (NSString *)logWithJsonData:(NSData *)data {
return [self logWithJsonData:data color:[UIColor colorWithRed:1 green:1 blue:1 alpha:1]];
}
+ (NSString *)logWithJsonData:(NSData *)data color:(UIColor *)color {
NSString *string = [self getPrettyJsonStringWithData:data] ? : @"NULL";
return [self finalLogWithString:string type:CocoaDebugToolTypeJson color:color];
}
//#pragma mark - logWithProtobufData
//+ (NSString *)logWithProtobufData:(NSData *)data className:(NSString *)className {
// return [self logWithProtobufData:data className:className color:[UIColor colorWithRed:1 green:1 blue:1 alpha:1]];
//}
//
//+ (NSString *)logWithProtobufData:(NSData *)data className:(NSString *)className color:(UIColor *)color {
// NSString *string = [self parsingProtobufWithData:data className:className] ? : @"NULL";
// return [self finalLogWithString:string type:CocoaDebugToolTypeProtobuf color:color];
//}
#pragma mark - tool
+ (NSString *)getPrettyJsonStringWithJsonString:(NSString *)jsonString {
return [self getPrettyJsonStringWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding]];
}
+ (NSString *)getPrettyJsonStringWithData:(NSData *)data {
if (!data) {return nil;}
//1.pretty json
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
if (!dict) {return nil;}
NSData *prettyData = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:nil];
if (!prettyData) {return nil;}
NSString *prettyJsonString = [[NSString alloc] initWithData:prettyData encoding:NSUTF8StringEncoding];
if (prettyJsonString) {
return prettyJsonString;
}
//2.protobuf
// GPBMessage *message = [GPBMessage parseFromData:data error:nil];
// if ([message serializedSize] > 0) {
// return [message description];
// }
//3.utf-8 string
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
+ (NSString *)finalLogWithString:(NSString *)string type:(CocoaDebugToolType)type color:(UIColor *)color {
[[_OCLogHelper shared] handleLogWithFile:@"XXX" function:@"XXX" line:1 message:string color:color type:type];
return string;
}
//Protobuf
//+ (NSString *)parsingProtobufWithData:(NSData *)data className:(NSString *)className {
// if (!data || !className) {return nil;}
//
// Class cls = NSClassFromString(className);
// //protobuf
// GPBMessage *obj = [cls parseFromData:data error:nil];
// //HuiCao
// NSString *jsonString = [obj _JSONStringWithIgnoreFields:nil];
// if (!jsonString) {return nil;}
//
// NSString *prettyJsonString = [self getPrettyJsonStringWithJsonString:jsonString];
// if (!prettyJsonString) {return nil;}
//
// return [prettyJsonString stringByReplacingOccurrencesOfString:@"\\/" withString:@"/"];
//}
@end

View File

@@ -0,0 +1,68 @@
//
// Example
// man
//
// Created by man 11/11/2018.
// Copyright © 2020 man. All rights reserved.
//
import UIKit
class LogCell: UITableViewCell {
@IBOutlet weak var labelContent: CustomTextView!
@IBOutlet weak var viewTypeLogColor: UIView!
var model: _OCLogModel? {
didSet {
guard let model = model else { return }
labelContent.text = nil
labelContent.text = model.str
labelContent.attributedText = model.attr
labelContent.textContainer.lineBreakMode = NSLineBreakMode.byCharWrapping
labelContent.textContainer.lineFragmentPadding = 0
labelContent.textContainerInset = .zero
labelContent.isUserInteractionEnabled = false
//tag
if model.isTag == true {
self.contentView.backgroundColor = "#007aff".hexColor
} else {
//isSelected
if model.isSelected == true {
self.contentView.backgroundColor = "#222222".hexColor
} else {
self.contentView.backgroundColor = .black
}
}
}
}
}
class CustomTextView : UITextView {
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
self.inputView = UIView.init(frame: CGRect(x: 0, y: 0, width: 1, height: 1))
}
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == #selector(selectAll) {
if let range = selectedTextRange, range.start == beginningOfDocument, range.end == endOfDocument {
return false
}
return !text.isEmpty
}
else if action == #selector(paste(_:)) {
return false
}
else if action == #selector(cut(_:)) {
return false
}
return super.canPerformAction(action, withSender: sender)
}
}

View File

@@ -0,0 +1,700 @@
//
// Example
// man
//
// Created by man 11/11/2018.
// Copyright © 2020 man. All rights reserved.
//
import UIKit
class LogViewController: UIViewController {
var reachEndDefault: Bool = true
var reachEndRN: Bool = true
var reachEndWeb: Bool = true
var firstInDefault: Bool = true
var firstInRN: Bool = true
var firstInWeb: Bool = true
var selectedSegmentIndex: Int = 0
var selectedSegment_0: Bool = false
var selectedSegment_1: Bool = false
var selectedSegment_2: Bool = false
var defaultReloadDataFinish: Bool = true
var rnReloadDataFinish: Bool = true
var webReloadDataFinish: Bool = true
@IBOutlet weak var segmentedControl: UISegmentedControl!
@IBOutlet weak var deleteItem: UIBarButtonItem!
@IBOutlet weak var defaultTableView: UITableView!
@IBOutlet weak var defaultSearchBar: UISearchBar!
var defaultModels: [_OCLogModel] = [_OCLogModel]()
var defaultCacheModels: Array<_OCLogModel>?
var defaultSearchModels: Array<_OCLogModel>?
@IBOutlet weak var rnTableView: UITableView!
@IBOutlet weak var rnSearchBar: UISearchBar!
var rnModels: [_OCLogModel] = [_OCLogModel]()
var rnCacheModels: Array<_OCLogModel>?
var rnSearchModels: Array<_OCLogModel>?
@IBOutlet weak var webTableView: UITableView!
@IBOutlet weak var webSearchBar: UISearchBar!
var webModels: [_OCLogModel] = [_OCLogModel]()
var webCacheModels: Array<_OCLogModel>?
var webSearchModels: Array<_OCLogModel>?
//MARK: - tool
//
func searchLogic(_ searchText: String = "") {
if selectedSegmentIndex == 0
{
guard let defaultCacheModels = defaultCacheModels else {return}
defaultSearchModels = defaultCacheModels
if searchText == "" {
defaultModels = defaultCacheModels
} else {
guard let defaultSearchModels = defaultSearchModels else {return}
for _ in defaultSearchModels {
if let index = self.defaultSearchModels?.firstIndex(where: { (model) -> Bool in
return !model.content.lowercased().contains(searchText.lowercased())//
}) {
self.defaultSearchModels?.remove(at: index)
}
}
defaultModels = self.defaultSearchModels ?? []
}
}
else if selectedSegmentIndex == 1
{
guard let rnCacheModels = rnCacheModels else {return}
rnSearchModels = rnCacheModels
if searchText == "" {
rnModels = rnCacheModels
} else {
guard let rnSearchModels = rnSearchModels else {return}
for _ in rnSearchModels {
if let index = self.rnSearchModels?.firstIndex(where: { (model) -> Bool in
return !model.content.lowercased().contains(searchText.lowercased())//
}) {
self.rnSearchModels?.remove(at: index)
}
}
rnModels = self.rnSearchModels ?? []
}
}
else
{
guard let webCacheModels = webCacheModels else {return}
webSearchModels = webCacheModels
if searchText == "" {
webModels = webCacheModels
} else {
guard let webSearchModels = webSearchModels else {return}
for _ in webSearchModels {
if let index = self.webSearchModels?.firstIndex(where: { (model) -> Bool in
return !model.content.lowercased().contains(searchText.lowercased())//
}) {
self.webSearchModels?.remove(at: index)
}
}
webModels = self.webSearchModels ?? []
}
}
}
//MARK: - private
func reloadLogs(needScrollToEnd: Bool = false, needReloadData: Bool = true) {
if selectedSegmentIndex == 0
{
if defaultReloadDataFinish == false {return}
if defaultSearchBar.isHidden != false ||
rnSearchBar.isHidden != true ||
webSearchBar.isHidden != true {
defaultSearchBar.isHidden = false
rnSearchBar.isHidden = true
webSearchBar.isHidden = true
}
if defaultTableView.isHidden != false ||
rnTableView.isHidden != true ||
webTableView.isHidden != true {
defaultTableView.isHidden = false
rnTableView.isHidden = true
webTableView.isHidden = true
}
if needReloadData == false && defaultModels.count > 0 {return}
if let arr = _OCLogStoreManager.shared()?.normalLogArray {
defaultModels = arr as! [_OCLogModel]
}
self.defaultCacheModels = self.defaultModels
self.searchLogic(CocoaDebugSettings.shared.logSearchWordNormal ?? "")
// dispatch_main_async_safe { [weak self] in
self.defaultReloadDataFinish = false
self.defaultTableView.reloadData {
self.defaultReloadDataFinish = true
}
if needScrollToEnd == false {return}
//table
// guard let count = self.defaultModels.count else {return}
if self.defaultModels.count > 0 {
// guard let firstInDefault = self.firstInDefault else {return}
self.defaultTableView.tableViewScrollToBottom(animated: !firstInDefault)
self.firstInDefault = false
}
// }
}
else if selectedSegmentIndex == 1
{
if rnReloadDataFinish == false {return}
if defaultSearchBar.isHidden != true ||
rnSearchBar.isHidden != false ||
webSearchBar.isHidden != true {
defaultSearchBar.isHidden = true
rnSearchBar.isHidden = false
webSearchBar.isHidden = true
}
if defaultTableView.isHidden != true ||
rnTableView.isHidden != false ||
webTableView.isHidden != true {
defaultTableView.isHidden = true
rnTableView.isHidden = false
webTableView.isHidden = true
}
if needReloadData == false && rnModels.count > 0 {return}
if let arr = _OCLogStoreManager.shared()?.rnLogArray {
rnModels = arr as! [_OCLogModel]
}
self.rnCacheModels = self.rnModels
self.searchLogic(CocoaDebugSettings.shared.logSearchWordRN ?? "")
// dispatch_main_async_safe { [weak self] in
self.rnReloadDataFinish = false
self.rnTableView.reloadData {
self.rnReloadDataFinish = true
}
if needScrollToEnd == false {return}
//table
// guard let count = self.rnModels.count else {return}
if self.rnModels.count > 0 {
// guard let firstInRN = self.firstInRN else {return}
self.rnTableView.tableViewScrollToBottom(animated: !firstInRN)
self.firstInRN = false
}
// }
}
else
{
if webReloadDataFinish == false {return}
if defaultSearchBar.isHidden != true ||
rnSearchBar.isHidden != true ||
webSearchBar.isHidden != false {
defaultSearchBar.isHidden = true
rnSearchBar.isHidden = true
webSearchBar.isHidden = false
}
if defaultTableView.isHidden != true ||
rnTableView.isHidden != true ||
webTableView.isHidden != false {
defaultTableView.isHidden = true
rnTableView.isHidden = true
webTableView.isHidden = false
}
if needReloadData == false && webModels.count > 0 {return}
if let arr = _OCLogStoreManager.shared().webLogArray {
webModels = arr as! [_OCLogModel]
}
self.webCacheModels = self.webModels
self.searchLogic(CocoaDebugSettings.shared.logSearchWordWeb ?? "")
// dispatch_main_async_safe { [weak self] in
self.webReloadDataFinish = false
self.webTableView.reloadData {
self.webReloadDataFinish = true
}
if needScrollToEnd == false {return}
//table
// guard let count = self.webModels.count else {return}
if self.webModels.count > 0 {
// guard let firstInWeb = self.firstInWeb else {return}
self.webTableView.tableViewScrollToBottom(animated: !firstInWeb)
self.firstInWeb = false
}
// }
}
}
//MARK: - init
override func viewDidLoad() {
super.viewDidLoad()
let tap = UITapGestureRecognizer.init(target: self, action: #selector(didTapView))
tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
deleteItem.tintColor = Color.mainGreen
segmentedControl.tintColor = Color.mainGreen
if UIScreen.main.bounds.size.width == 320 {
segmentedControl.setTitleTextAttributes([NSAttributedString.Key.font: UIFont.systemFont(ofSize: 11)], for: .normal)
} else {
segmentedControl.setTitleTextAttributes([NSAttributedString.Key.font: UIFont.systemFont(ofSize: 13)], for: .normal)
}
//notification
NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "refreshLogs_CocoaDebug"), object: nil, queue: OperationQueue.main) { [weak self] _ in
self?.refreshLogs_notification()
}
defaultTableView.tableFooterView = UIView()
defaultTableView.delegate = self
defaultTableView.dataSource = self
// defaultTableView.rowHeight = UITableViewAutomaticDimension
defaultSearchBar.delegate = self
defaultSearchBar.text = CocoaDebugSettings.shared.logSearchWordNormal
defaultSearchBar.isHidden = true
//bug
defaultTableView.estimatedRowHeight = 0
defaultTableView.estimatedSectionHeaderHeight = 0
defaultTableView.estimatedSectionFooterHeight = 0
rnTableView.tableFooterView = UIView()
rnTableView.delegate = self
rnTableView.dataSource = self
// rnTableView.rowHeight = UITableViewAutomaticDimension
rnSearchBar.delegate = self
rnSearchBar.text = CocoaDebugSettings.shared.logSearchWordRN
rnSearchBar.isHidden = true
//bug
rnTableView.estimatedRowHeight = 0
rnTableView.estimatedSectionHeaderHeight = 0
rnTableView.estimatedSectionFooterHeight = 0
webTableView.tableFooterView = UIView()
webTableView.delegate = self
webTableView.dataSource = self
// webTableView.rowHeight = UITableViewAutomaticDimension
webSearchBar.delegate = self
webSearchBar.text = CocoaDebugSettings.shared.logSearchWordWeb
webSearchBar.isHidden = true
//bug
webTableView.estimatedRowHeight = 0
webTableView.estimatedSectionHeaderHeight = 0
webTableView.estimatedSectionFooterHeight = 0
//segmentedControl
selectedSegmentIndex = CocoaDebugSettings.shared.logSelectIndex
segmentedControl.selectedSegmentIndex = selectedSegmentIndex
if selectedSegmentIndex == 0 {
selectedSegment_0 = true
} else if selectedSegmentIndex == 1 {
selectedSegment_1 = true
} else {
selectedSegment_2 = true
}
reloadLogs(needScrollToEnd: true, needReloadData: true)
//hide searchBar icon
let textFieldInsideSearchBar = defaultSearchBar.value(forKey: "searchField") as! UITextField
textFieldInsideSearchBar.leftViewMode = .never
textFieldInsideSearchBar.leftView = nil
textFieldInsideSearchBar.backgroundColor = .white
textFieldInsideSearchBar.returnKeyType = .default
let textFieldInsideSearchBar2 = rnSearchBar.value(forKey: "searchField") as! UITextField
textFieldInsideSearchBar2.leftViewMode = .never
textFieldInsideSearchBar2.leftView = nil
textFieldInsideSearchBar2.backgroundColor = .white
textFieldInsideSearchBar2.returnKeyType = .default
let textFieldInsideSearchBar3 = webSearchBar.value(forKey: "searchField") as! UITextField
textFieldInsideSearchBar3.leftViewMode = .never
textFieldInsideSearchBar3.leftView = nil
textFieldInsideSearchBar3.backgroundColor = .white
textFieldInsideSearchBar3.returnKeyType = .default
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
defaultSearchBar.resignFirstResponder()
rnSearchBar.resignFirstResponder()
webSearchBar.resignFirstResponder()
}
deinit {
//notification
NotificationCenter.default.removeObserver(self)
}
//MARK: - target action
@IBAction func didTapDown(_ sender: Any) {
if selectedSegmentIndex == 0
{
defaultTableView.tableViewScrollToBottom(animated: true)
defaultSearchBar.resignFirstResponder()
reachEndDefault = true
}
else if selectedSegmentIndex == 1
{
rnTableView.tableViewScrollToBottom(animated: true)
rnSearchBar.resignFirstResponder()
reachEndRN = true
}
else
{
webTableView.tableViewScrollToBottom(animated: true)
webSearchBar.resignFirstResponder()
reachEndWeb = true
}
}
@IBAction func didTapUp(_ sender: Any) {
if selectedSegmentIndex == 0
{
defaultTableView.tableViewScrollToHeader(animated: true)
defaultSearchBar.resignFirstResponder()
reachEndDefault = false
}
else if selectedSegmentIndex == 1
{
rnTableView.tableViewScrollToHeader(animated: true)
rnSearchBar.resignFirstResponder()
reachEndRN = false
}
else
{
webTableView.tableViewScrollToHeader(animated: true)
webSearchBar.resignFirstResponder()
reachEndWeb = false
}
}
@IBAction func resetLogs(_ sender: Any) {
if selectedSegmentIndex == 0
{
defaultModels = []
defaultCacheModels = []
// defaultSearchBar.text = nil
defaultSearchBar.resignFirstResponder()
// CocoaDebugSettings.shared.logSearchWordNormal = nil
_OCLogStoreManager.shared()?.resetNormalLogs()
// dispatch_main_async_safe { [weak self] in
self.defaultTableView.reloadData()
// }
}
else if selectedSegmentIndex == 1
{
rnModels = []
rnCacheModels = []
// rnSearchBar.text = nil
rnSearchBar.resignFirstResponder()
// CocoaDebugSettings.shared.logSearchWordRN = nil
_OCLogStoreManager.shared()?.resetRNLogs()
// dispatch_main_async_safe { [weak self] in
self.rnTableView.reloadData()
// }
}
else
{
webModels = []
webCacheModels = []
// webSearchBar.text = nil
webSearchBar.resignFirstResponder()
// CocoaDebugSettings.shared.logSearchWordWeb = nil
_OCLogStoreManager.shared().resetWebLogs()
// dispatch_main_async_safe { [weak self] in
self.webTableView.reloadData()
// }
}
}
@IBAction func segmentedControlAction(_ sender: UISegmentedControl) {
selectedSegmentIndex = segmentedControl.selectedSegmentIndex
CocoaDebugSettings.shared.logSelectIndex = selectedSegmentIndex
if selectedSegmentIndex == 0 {
rnSearchBar.resignFirstResponder()
webSearchBar.resignFirstResponder()
} else if selectedSegmentIndex == 1 {
defaultSearchBar.resignFirstResponder()
webSearchBar.resignFirstResponder()
} else {
defaultSearchBar.resignFirstResponder()
rnSearchBar.resignFirstResponder()
}
if selectedSegmentIndex == 0 && selectedSegment_0 == false {
selectedSegment_0 = true
reloadLogs(needScrollToEnd: true, needReloadData: true)
return
}
if selectedSegmentIndex == 1 && selectedSegment_1 == false {
selectedSegment_1 = true
reloadLogs(needScrollToEnd: true, needReloadData: true)
return
}
if selectedSegmentIndex == 2 && selectedSegment_2 == false {
selectedSegment_2 = true
reloadLogs(needScrollToEnd: true, needReloadData: true)
return
}
reloadLogs(needScrollToEnd: false, needReloadData: false)
}
@objc func didTapView() {
if selectedSegmentIndex == 0 {
defaultSearchBar.resignFirstResponder()
} else if selectedSegmentIndex == 1 {
rnSearchBar.resignFirstResponder()
} else {
webSearchBar.resignFirstResponder()
}
}
//MARK: - notification
@objc func refreshLogs_notification() {
if self.selectedSegmentIndex == 0 {
self.reloadLogs(needScrollToEnd: self.reachEndDefault , needReloadData: true)
} else if self.selectedSegmentIndex == 1 {
self.reloadLogs(needScrollToEnd: self.reachEndRN , needReloadData: true)
} else {
self.reloadLogs(needScrollToEnd: self.reachEndWeb , needReloadData: true)
}
}
}
//MARK: - UITableViewDataSource
extension LogViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == defaultTableView {
return defaultModels.count
} else if tableView == rnTableView {
return rnModels.count
} else {
return webModels.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "LogCell", for: indexPath) as! LogCell
if tableView == defaultTableView
{
cell.model = defaultModels[indexPath.row]
}
else if tableView == rnTableView
{
cell.model = rnModels[indexPath.row]
}
else
{
cell.model = webModels[indexPath.row]
}
return cell
}
}
//MARK: - UITableViewDelegate
extension LogViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
var logTitleString = ""
var models_: [_OCLogModel]?
if tableView == defaultTableView
{
defaultSearchBar.resignFirstResponder()
reachEndDefault = false
logTitleString = "Log"
models_ = defaultModels
}
else if tableView == rnTableView
{
rnSearchBar.resignFirstResponder()
reachEndRN = false
logTitleString = "RN"
models_ = rnModels
}
else
{
webSearchBar.resignFirstResponder()
reachEndWeb = false
logTitleString = "Web"
models_ = webModels
}
//
guard let models = models_ else {return}
let vc = JsonViewController.instanceFromStoryBoard()
vc.editType = .log
vc.logTitleString = logTitleString
vc.logModels = models
vc.logModel = models[indexPath.row]
navigationController?.pushViewController(vc, animated: true)
vc.justCancelCallback = {
tableView.reloadData()
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
var model: _OCLogModel
if tableView == defaultTableView {
model = defaultModels[indexPath.row]
} else if tableView == rnTableView {
model = rnModels[indexPath.row]
} else {
model = webModels[indexPath.row]
}
if let height = model.str?.height(with: UIFont.boldSystemFont(ofSize: 12), constraintToWidth: UIScreen.main.bounds.size.width) {
return height + 10;
}
return 0
}
}
//MARK: - UIScrollViewDelegate
extension LogViewController: UIScrollViewDelegate {
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
if scrollView == defaultTableView {
defaultSearchBar.resignFirstResponder()
reachEndDefault = false
} else if scrollView == rnTableView {
rnSearchBar.resignFirstResponder()
reachEndRN = false
} else {
webSearchBar.resignFirstResponder()
reachEndWeb = false
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if (scrollView.contentOffset.y + 1) >= (scrollView.contentSize.height - scrollView.frame.size.height) {
//bottom reached
if scrollView == defaultTableView {
reachEndDefault = true
} else if scrollView == rnTableView {
reachEndRN = true
} else {
reachEndWeb = true
}
}
}
}
//MARK: - UISearchBarDelegate
extension LogViewController: UISearchBarDelegate {
func searchBarSearchButtonClicked(_ searchBar: UISearchBar)
{
searchBar.resignFirstResponder()
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String)
{
if searchBar == defaultSearchBar
{
CocoaDebugSettings.shared.logSearchWordNormal = searchText
searchLogic(searchText)
// dispatch_main_async_safe { [weak self] in
self.defaultTableView.reloadData()
// }
}
else if searchBar == rnSearchBar
{
CocoaDebugSettings.shared.logSearchWordRN = searchText
searchLogic(searchText)
// dispatch_main_async_safe { [weak self] in
self.rnTableView.reloadData()
// }
}
else
{
CocoaDebugSettings.shared.logSearchWordWeb = searchText
searchLogic(searchText)
// dispatch_main_async_safe { [weak self] in
self.webTableView.reloadData()
// }
}
}
}

View File

@@ -0,0 +1,96 @@
//
// _NSLogHook.m
// Example_Swift
//
// Created by man 7/26/19.
// Copyright © 2020 man. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "_OCLogHelper.h"
#import "_fishhook.h"
//#import <React/RCTLog.h>
//#import "RCTLog.h"
@interface _NSLogHook : NSObject
@end
@implementation _NSLogHook
static void (*_original_nslog)(NSString *format, ...);
#pragma mark - hooks
void cocoadebug_nslog(NSString *format, ...)
{
if (![format isKindOfClass:[NSString class]]) {return;}
va_list vl;
va_start(vl, format);
NSString *str = [[NSString alloc] initWithFormat:format arguments:vl];
@try {
_original_nslog(str);
} @catch(NSException *exception) {
} @finally {
}
@try {
[_OCLogHelper.shared handleLogWithFile:@"" function:@"" line:999999999 message:str color:[UIColor whiteColor] type:CocoaDebugToolTypeNone];
} @catch(NSException *exception) {
} @finally {
}
va_end(vl);
}
#pragma mark - load
+ (void)load
{
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"enableLogMonitoring_CocoaDebug"]) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
struct rebinding nslog_rebinding = {"NSLog",cocoadebug_nslog,(void*)&_original_nslog};
rebind_symbols((struct rebinding[1]){nslog_rebinding}, 1);
});
}
}
//#pragma mark - RN
//void _RCTLogJavaScriptInternal(RCTLogLevel level, NSString *message)
//{
// if ([[NSUserDefaults standardUserDefaults] boolForKey:@"enableRNMonitoring_CocoaDebug"]) {return;}
// if (![message isKindOfClass:[NSString class]]) {return;}
//// if (level != RCTLogLevelError && level != RCTLogLevelInfo) {return;}
//
// NSString *levelStr = @"";
//
// switch (level) {
//// case RCTLogLevelTrace:
//// levelStr = @"[RCTLogTrace]";
//// break;
// case RCTLogLevelInfo:
// levelStr = @"[RCTLogInfo]";
// break;
// case RCTLogLevelWarning:
// levelStr = @"[RCTLogWarn]";
// break;
// case RCTLogLevelError:
// levelStr = @"[RCTLogError]";
// break;
//// case RCTLogLevelFatal:
//// levelStr = @"[RCTLogFatal]";
// break;
// default:
// break;
// }
//
// [_OCLogHelper.shared handleLogWithFile:[NSString stringWithFormat:@"%@\n", levelStr] function:@"" line:-1 message:message color:[UIColor whiteColor] type:CocoaDebugToolTypeRN];
//}
@end

View File

@@ -0,0 +1,21 @@
//
// Example
// man
//
// Created by man 11/11/2018.
// Copyright © 2020 man. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "_OCLogModel.h"
@interface _OCLogHelper : NSObject
//@property (nonatomic, assign) BOOL enable;
+ (instancetype)shared;
- (void)handleLogWithFile:(NSString *)file function:(NSString *)function line:(NSInteger)line message:(NSString *)message color:(UIColor *)color type:(CocoaDebugToolType)type;
@end

View File

@@ -0,0 +1,91 @@
//
// Example
// man
//
// Created by man 11/11/2018.
// Copyright © 2020 man. All rights reserved.
//
#import "_OCLogHelper.h"
#import "_OCLogStoreManager.h"
@implementation _OCLogHelper
+ (instancetype)shared
{
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
//default value for @property
//- (id)init {
// if (self = [super init]) {
// self.enable = YES;
// }
// return self;
//}
- (NSString *)parseFileInfo:(NSString *)file function:(NSString *)function line:(NSInteger)line
{
if (![file isKindOfClass:[NSString class]] || ![function isKindOfClass:[NSString class]]) {
return @"\n";
}
if ([file isEqualToString:@"XXX"] && [function isEqualToString:@"XXX"] && line == 1) {
return @"XXX|XXX|1";
}
if (line == 0) { //web
NSString *fileName = [[file componentsSeparatedByString:@"/"] lastObject] ?: @"";
return [NSString stringWithFormat:@"%@ %@\n", fileName, function];
}
if (line == 999999999) { //nslog
NSString *fileName = [[file componentsSeparatedByString:@"/"] lastObject] ?: @"";
return [NSString stringWithFormat:@"%@ %@\n", fileName, function];
}
if (line == -1) { //RN
return file;
}
NSString *fileName = [[file componentsSeparatedByString:@"/"] lastObject] ?: @"";
return [NSString stringWithFormat:@"%@[%ld]%@\n", fileName, (long)line, function];
}
- (void)handleLogWithFile:(NSString *)file function:(NSString *)function line:(NSInteger)line message:(NSString *)message color:(UIColor *)color type:(CocoaDebugToolType)type
{
// if (!self.enable && type != CocoaDebugToolTypeRN) {return;}
if (!file || !function || !message || !color) {return;}
//1.
NSString *fileInfo = [self parseFileInfo:file function:function line:line];
//2.
_OCLogModel *newLog = [[_OCLogModel alloc] initWithContent:message color:color fileInfo:fileInfo isTag:NO type:type];
// if (line == 0 && ![fileInfo isEqualToString:@"XXX|XXX|1"]) {
// newLog.logType = CocoaDebugLogType...
// }
if (type == CocoaDebugToolTypeRN) {
newLog.logType = CocoaDebugLogTypeRN;
}
if ([file isEqualToString:@"[WKWebView]"]) {
newLog.logType = CocoaDebugLogTypeWeb;
}
[[_OCLogStoreManager shared] addLog:newLog];
//3.
[[NSNotificationCenter defaultCenter] postNotificationName:@"refreshLogs_CocoaDebug" object:nil userInfo:nil];
}
@end

View File

@@ -0,0 +1,44 @@
//
// Example
// man
//
// Created by man 11/11/2018.
// Copyright © 2020 man. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
typedef NS_ENUM(NSInteger, CocoaDebugLogType) {
CocoaDebugLogTypeNormal = 0,
CocoaDebugLogTypeRN,
CocoaDebugLogTypeWeb
};
typedef NS_ENUM (NSInteger, CocoaDebugToolType) {
CocoaDebugToolTypeNone,
CocoaDebugToolTypeRN,
CocoaDebugToolTypeJson,
CocoaDebugToolTypeProtobuf
};
@interface _OCLogModel : NSObject
@property (nonatomic, copy) NSData *contentData;
@property (nonatomic, copy) NSString *Id;
@property (nonatomic, copy) NSString *fileInfo;
@property (nonatomic, copy) NSString *content;
@property (nonatomic, strong) NSDate *date;
@property (nonatomic, strong) UIColor *color;
@property (nonatomic, assign) BOOL isTag;
@property (nonatomic, assign) BOOL isSelected;
@property (nonatomic, copy) NSString *str;
@property (nonatomic, copy) NSAttributedString *attr;
@property (nonatomic, assign) CocoaDebugLogType logType;
- (instancetype)initWithContent:(NSString *)content color:(UIColor *)color fileInfo:(NSString *)fileInfo isTag:(BOOL)isTag type:(CocoaDebugToolType)type;
@end

110
Pods/CocoaDebug/Sources/Logs/_OCLogModel.m generated Normal file
View File

@@ -0,0 +1,110 @@
//
// Example
// man
//
// Created by man 11/11/2018.
// Copyright © 2020 man. All rights reserved.
//
#import "_OCLogModel.h"
#import "_OCLoggerFormat.h"
#import "_NetworkHelper.h"
@implementation _OCLogModel
- (instancetype)initWithContent:(NSString *)content color:(UIColor *)color fileInfo:(NSString *)fileInfo isTag:(BOOL)isTag type:(CocoaDebugToolType)type
{
if (self = [super init]) {
if ([fileInfo isEqualToString:@"XXX|XXX|1"]) {
if (type == CocoaDebugToolTypeProtobuf) {
fileInfo = @"Protobuf\n";
} else {
fileInfo = @"\n";
}
}
//
if (type == CocoaDebugToolTypeNone) {
if ([fileInfo isEqualToString:@" \n"]) {//nslog
fileInfo = @"NSLog\n";
} else if ([fileInfo isEqualToString:@"\n"]) {//color
fileInfo = @"\n";
}
}
//RN (java script)
if ([fileInfo isEqualToString:@"[RCTLogError]\n"]) {
fileInfo = @"[error]\n";
} else if ([fileInfo isEqualToString:@"[RCTLogInfo]\n"]) {
fileInfo = @"[log]\n";
}
//
self.Id = [[NSUUID UUID] UUIDString];
self.fileInfo = fileInfo;
self.date = [NSDate date];
self.color = color;
self.isTag = isTag;
if ([content isKindOfClass:[NSString class]]) {
self.contentData = [content dataUsingEncoding:NSUTF8StringEncoding];
}
//
if (content.length > 1000) {
content = [content substringToIndex:1000];
}
self.content = content;
/////////////////////////////////////////////////////////////////////////
NSInteger startIndex = 0;
NSInteger lenghtDate = 0;
NSString *stringContent = @"";
stringContent = [stringContent stringByAppendingFormat:@"[%@]", [_OCLoggerFormat formatDate:self.date]];
lenghtDate = [stringContent length];
startIndex = [stringContent length];
if (self.fileInfo) {
stringContent = [stringContent stringByAppendingFormat:@"%@%@", self.fileInfo, self.content];
} else {
stringContent = [stringContent stringByAppendingFormat:@"%@", self.content];
}
NSMutableAttributedString *attstr = [[NSMutableAttributedString alloc] initWithString:stringContent];
[attstr addAttribute:NSForegroundColorAttributeName value:self.color range:NSMakeRange(0, [stringContent length])];
NSRange range = NSMakeRange(0, lenghtDate);
[attstr addAttribute:NSForegroundColorAttributeName value: [[_NetworkHelper shared] mainColor] range: range];
[attstr addAttribute:NSFontAttributeName value: [UIFont boldSystemFontOfSize:12] range: range];
NSRange range2 = NSMakeRange(startIndex, self.fileInfo.length);
if ([self.fileInfo isEqualToString:@"[error]\n"]) {
[attstr addAttribute: NSForegroundColorAttributeName value: [UIColor systemRedColor] range: range2];
} else {
[attstr addAttribute: NSForegroundColorAttributeName value: [UIColor systemGrayColor] range: range2];
}
[attstr addAttribute: NSFontAttributeName value: [UIFont boldSystemFontOfSize:12] range: range2];
//
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineBreakMode = NSLineBreakByCharWrapping;
NSRange rang3 = NSMakeRange(0, attstr.length);
[attstr addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:rang3];
//
self.str = stringContent;
self.attr = [attstr copy];
}
return self;
}
@end

View File

@@ -0,0 +1,28 @@
//
// Example
// man
//
// Created by man 11/11/2018.
// Copyright © 2020 man. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "_OCLogModel.h"
@interface _OCLogStoreManager : NSObject
@property (nonatomic, strong) NSMutableArray<_OCLogModel *> *normalLogArray;
@property (nonatomic, strong) NSMutableArray<_OCLogModel *> *rnLogArray;
@property (nonatomic, strong) NSMutableArray<_OCLogModel *> *webLogArray;
+ (instancetype)shared;
- (void)addLog:(_OCLogModel *)log;
- (void)removeLog:(_OCLogModel *)log;
- (void)resetNormalLogs;
- (void)resetRNLogs;
- (void)resetWebLogs;
@end

View File

@@ -0,0 +1,127 @@
//
// Example
// man
//
// Created by man 11/11/2018.
// Copyright © 2020 man. All rights reserved.
//
#import "_OCLogStoreManager.h"
#import "_NetworkHelper.h"
@implementation _OCLogStoreManager
+ (instancetype)shared
{
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (id)init
{
self = [super init];
if (self) {
self.normalLogArray = [NSMutableArray arrayWithCapacity:1000 + 100];
self.rnLogArray = [NSMutableArray arrayWithCapacity:1000 + 100];
self.webLogArray = [NSMutableArray arrayWithCapacity:1000 + 100];
}
return self;
}
- (void)addLog:(_OCLogModel *)log
{
if (![log.content isKindOfClass:[NSString class]]) {return;}
//log,
for (NSString *prefixStr in [_NetworkHelper shared].onlyPrefixLogs) {
if (![log.content hasPrefix:prefixStr]) {
return;
}
}
//log,
for (NSString *prefixStr in [_NetworkHelper shared].ignoredPrefixLogs) {
if ([log.content hasPrefix:prefixStr]) {
return;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
if (log.logType == CocoaDebugLogTypeNormal)
{
//normal
if ([self.normalLogArray count] >= 1000) {
if (self.normalLogArray.count > 0) {
[self.normalLogArray removeObjectAtIndex:0];
}
}
[self.normalLogArray addObject:log];
}
else if (log.logType == CocoaDebugLogTypeRN)
{
//rn
if ([self.rnLogArray count] >= 1000) {
if (self.rnLogArray.count > 0) {
[self.rnLogArray removeObjectAtIndex:0];
}
}
[self.rnLogArray addObject:log];
}
else
{
//web
if ([self.webLogArray count] >= 1000) {
if (self.webLogArray.count > 0) {
[self.webLogArray removeObjectAtIndex:0];
}
}
[self.webLogArray addObject:log];
}
}
- (void)removeLog:(_OCLogModel *)log
{
if (log.logType == CocoaDebugLogTypeNormal)
{
//normal
[self.normalLogArray removeObject:log];
}
else if (log.logType == CocoaDebugLogTypeNormal)
{
//rn
[self.rnLogArray removeObject:log];
}
else
{
//web
[self.webLogArray removeObject:log];
}
}
- (void)resetNormalLogs
{
[self.normalLogArray removeAllObjects];
}
- (void)resetRNLogs
{
[self.rnLogArray removeAllObjects];
}
- (void)resetWebLogs
{
[self.webLogArray removeAllObjects];
}
@end

View File

@@ -0,0 +1,15 @@
//
// Example
// man
//
// Created by man 11/11/2018.
// Copyright © 2020 man. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface _OCLoggerFormat : NSObject
+ (NSString *)formatDate:(NSDate *)date;
@end

View File

@@ -0,0 +1,21 @@
//
// Example
// man
//
// Created by man 11/11/2018.
// Copyright © 2020 man. All rights reserved.
//
#import "_OCLoggerFormat.h"
@implementation _OCLoggerFormat
+ (NSString *)formatDate:(NSDate *)date
{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.timeZone = [NSTimeZone systemTimeZone];
formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss.SSS";
return [formatter stringFromDate:date];
}
@end

20
Pods/CocoaDebug/Sources/Logs/_ObjcLog.h generated Normal file
View File

@@ -0,0 +1,20 @@
//
// Example
// man
//
// Created by man 11/11/2018.
// Copyright © 2020 man. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface _ObjcLog : NSObject
+ (void)logWithFile:(const char *)file
function:(const char *)function
line:(NSUInteger)line
color:(UIColor *)color
message:(id)format, ...;
@end

57
Pods/CocoaDebug/Sources/Logs/_ObjcLog.m generated Normal file
View File

@@ -0,0 +1,57 @@
//
// Example
// man
//
// Created by man 11/11/2018.
// Copyright © 2020 man. All rights reserved.
//
#import "_ObjcLog.h"
#import "_OCLogHelper.h"
#import "NSObject+CocoaDebug.h"
#import <JavaScriptCore/JavaScriptCore.h>
@implementation _ObjcLog
+ (void)logWithFile:(const char *)file
function:(const char *)function
line:(NSUInteger)line
color:(UIColor *)color
message:(id)format, ...
{
if (format)
{
va_list args;
va_start(args, format);
if ([format isKindOfClass:[NSString class]])
{
// NSLogv(format, args);
[_OCLogHelper.shared handleLogWithFile:[NSString stringWithUTF8String:file] function:[NSString stringWithUTF8String:function] line:line message:[[NSString alloc] initWithFormat:format arguments:args] color:color type:CocoaDebugToolTypeNone];
}
else if ([format isKindOfClass:[JSValue class]])
{
id format_ = [format toString];
if ([format_ isEqualToString:@"[object Object]"])
{
format_ = [format toDictionary];
// NSLogv([NSString stringWithFormat:@"%@",format_], args);
[_OCLogHelper.shared handleLogWithFile:[NSString stringWithUTF8String:file] function:[NSString stringWithUTF8String:function] line:line message:[NSString stringWithFormat:@"%@",format_] color:color type:CocoaDebugToolTypeNone];
}
else
{
// NSLogv([NSString stringWithFormat:@"%@",format], args);
[_OCLogHelper.shared handleLogWithFile:[NSString stringWithUTF8String:file] function:[NSString stringWithUTF8String:function] line:line message:[NSString stringWithFormat:@"%@",format] color:color type:CocoaDebugToolTypeNone];
}
}
else
{
// NSLogv([NSString stringWithFormat:@"%@",format], args);
[_OCLogHelper.shared handleLogWithFile:[NSString stringWithUTF8String:file] function:[NSString stringWithUTF8String:function] line:line message:[NSString stringWithFormat:@"%@",format] color:color type:CocoaDebugToolTypeNone];
}
va_end(args);
}
}
@end

View File

@@ -0,0 +1,49 @@
//
// Example
// man
//
// Created by man 11/11/2018.
// Copyright © 2020 man. All rights reserved.
//
import Foundation
public class _SwiftLogHelper: NSObject {
var enable: Bool = true
@objc public static let shared = _SwiftLogHelper()
private override init() {}
fileprivate func parseFileInfo(file: String?, function: String?, line: Int?) -> String? {
guard let file = file, let function = function, let line = line, let fileName = file.components(separatedBy: "/").last else {return nil}
return "\(fileName)[\(line)]\(function)\n"
}
public func handleLog(file: String?, function: String?, line: Int?, message: Any..., color: UIColor?) {
let stringContent = message.reduce("") { result, next -> String in
return "\(result)\(result.count > 0 ? " " : "")\(next)"
}
commonHandleLog(file: file, function: function, line: (line ?? 0), message: stringContent, color: color)
}
private func commonHandleLog(file: String?, function: String?, line: Int, message: String, color: UIColor?) {
guard enable else {
return
}
//1.
let fileInfo = parseFileInfo(file: file, function: function, line: line)
//2.
if let newLog = _OCLogModel.init(content: message, color: color, fileInfo: fileInfo, isTag: false, type: .none) {
_OCLogStoreManager.shared().addLog(newLog)
}
//3.
NotificationCenter.default.post(name: NSNotification.Name("refreshLogs_CocoaDebug"), object: nil, userInfo: nil)
}
}