Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 466|回复: 0

IOS异常日志记录与展现功能

[复制链接]
  • TA的每日心情
    奋斗
    2024-4-6 11:05
  • 签到天数: 748 天

    [LV.9]以坛为家II

    2034

    主题

    2092

    帖子

    70万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    705612
    发表于 2021-7-20 20:46:06 | 显示全部楼层 |阅读模式

    在平常的APP开发过程中经常碰到程序遇到异常闪退的问题,通过日志可以把相关的详细错误信息进行记录,本实例要记录不管在哪个页面出错都要进行记录,这边使用到的日志记录插件CocoaLumberjack,以文本的形式记录错误信息,然后再去读取各个文本的内容进行展示;当然现在有很多第三方的插件比如友盟也已经集成错误记录的功能;

    效果图如下:

    1:封装DDLogger的类

    MyFileLogger.h文件
    
    #import <Foundation/Foundation.h> #import <CocoaLumberjack.h> @interface MyFileLogger : NSObject @property (nonatomic, strong, readwrite) DDFileLogger *fileLogger; +(MyFileLogger *)sharedManager; @end
    MyFileLogger.m文件
    
    #import "MyFileLogger.h" @implementation MyFileLogger #pragma mark - Inititlization - (instancetype)init { self = [super init]; if (self) { [self configureLogging]; } return self; } #pragma mark 单例模式 static MyFileLogger *sharedManager=nil; +(MyFileLogger *)sharedManager { static dispatch_once_t once; dispatch_once(&once, ^{ sharedManager=[[self alloc]init]; }); return sharedManager; } #pragma mark - 配记日志类型 - (void)configureLogging { #ifdef DEBUG [DDLog addLogger:[DDASLLogger sharedInstance]]; [DDLog addLogger:[DDTTYLogger sharedInstance]]; #endif [DDLog addLogger:self.fileLogger]; } #pragma mark - 初始化文件记录类型 - (DDFileLogger *)fileLogger { if (!_fileLogger) { DDFileLogger *fileLogger = [[DDFileLogger alloc] init]; fileLogger.rollingFrequency = 60 * 60 * 24; // 24 hour rolling fileLogger.logFileManager.maximumNumberOfLogFiles = 7; _fileLogger = fileLogger; } return _fileLogger; } @end

    这边是设置24小时进行记录一个文件

    2:出进异常进行记录

    MyExceptionHandler.h文件
    
    #import <Foundation/Foundation.h> #import <CocoaLumberjack.h> @interface MyExceptionHandler : NSObject + (void)setDefaultHandler; + (NSUncaughtExceptionHandler *)getHandler; + (void)TakeException:(NSException *) exception; @end
    #import "MyExceptionHandler.h"
    
    void UncaughtExceptionHandler(NSException * exception)
    {
        NSArray * arr = [exception callStackSymbols]; NSString * reason = [exception reason]; NSString * name = [exception name]; NSString * url = [NSString stringWithFormat:@"========异常错误报告========\nname:%@\nreason:\n%@\ncallStackSymbols:\n%@",name,reason,[arr componentsJoinedByString:@"\n"]]; DDLogError(@"%@\n\n",url); } @implementation MyExceptionHandler + (void)setDefaultHandler { NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler); } + (NSUncaughtExceptionHandler *)getHandler { return NSGetUncaughtExceptionHandler(); } + (void)TakeException:(NSException *)exception { NSArray * arr = [exception callStackSymbols]; NSString * reason = [exception reason]; NSString * name = [exception name]; NSString * url = [NSString stringWithFormat:@"========异常错误报告========\nname:%@\nreason:\n%@\ncallStackSymbols:\n%@",name,reason,[arr componentsJoinedByString:@"\n"]]; DDLogError(@"%@",url); } @end

    这个文件也是当出现异常会执行

    3:AppDelegate配置的内容

    AppDelegate.h文件内容
    
    
    #import <UIKit/UIKit.h> #import <DDLog.h> #import <CocoaLumberjack.h> #import "MyExceptionHandler.h" #import "MyFileLogger.h" @interface AppDelegate : UIResponder <UIApplicationDelegate> @property (strong, nonatomic) UIWindow *window; @property (nonatomic, strong) MyFileLogger *logger; @end
    AppDelegate.m文件:
    
    #import "AppDelegate.h" @interface AppDelegate () @end @implementation AppDelegate static const int ddLogLevel = LOG_LEVEL_VERBOSE; - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { //初始化  [MyExceptionHandler setDefaultHandler]; self.logger=[[MyFileLogger alloc]init]; NSString *path = NSHomeDirectory();//主目录 NSLog(@"当前项目的路径:%@",path); return YES; } - (void)applicationWillResignActive:(UIApplication *)application { } - (void)applicationDidEnterBackground:(UIApplication *)application { } - (void)applicationWillEnterForeground:(UIApplication *)application { } - (void)applicationDidBecomeActive:(UIApplication *)application { } - (void)applicationWillTerminate:(UIApplication *)application { } @end

    这边重点是设置DDLOG的记录等级ddLogLevel,以及上面两个文件的初始化[MyExceptionHandler setDefaultHandler];self.logger=[[MyFileLogger alloc]init];

    实现上面的代码已经能够记录异常的内容;

    4:创建一个错误的异常代码

    - (void)viewDidLoad {
        [super viewDidLoad];
        
        NSArray *test=@[@"123",@"444"]; id testID=test[5]; }

    执行到这段代码便记录异常的内容,接着进行内容的展示,是以一个列表展示每个日志文件,然后一个详细页面进行展示;

    5:日志列表

    loggerTableViewController.h文件
    
    #import <UIKit/UIKit.h> #import <CocoaLumberjack.h> #import "AppDelegate.h" #import "LoggerDetailViewController.h" @interface loggerTableViewController : UIViewController @end
    #import "loggerTableViewController.h"
    
    #define BLSRecyclingRecordViewController_CellIdentifier @"MyTablecell"
    
    @interface loggerTableViewController ()<UITableViewDataSource, UITableViewDelegate> @property (strong, nonatomic) UITableView *myTableView; @property (nonatomic, strong) NSDateFormatter *dateFormatter; @property (nonatomic, weak) DDFileLogger *fileLogger; @property (nonatomic, strong) NSArray *logFiles; @end @implementation loggerTableViewController - (void)viewDidLoad { [super viewDidLoad]; //加载日志文件 AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate]; _fileLogger = delegate.logger.fileLogger; [self loadLogFiles]; if (!_myTableView) { _myTableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height) style:UITableViewStyleGrouped]; _myTableView.showsVerticalScrollIndicator = NO; _myTableView.showsHorizontalScrollIndicator=NO; _myTableView.dataSource = self; _myTableView.delegate = self; [_myTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:BLSRecyclingRecordViewController_CellIdentifier]; [self.view addSubview:_myTableView]; } } //读取日志的文件个数 - (void)loadLogFiles { self.logFiles = self.fileLogger.logFileManager.sortedLogFileInfos; } //时间格式 - (NSDateFormatter *)dateFormatter { if (_dateFormatter) { return _dateFormatter; } _dateFormatter = [[NSDateFormatter alloc] init]; [_dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; return _dateFormatter; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } #pragma mark - Table view data source - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { if (section==0) { return 40; } return 10; } - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { return 1; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 2; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { if (section == 0) { return self.logFiles.count; } return 1; } - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { UIView *headView=[[UIView alloc]initWithFrame:CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, 30)]; if (section==0) { UILabel *myLabel=[[UILabel alloc]initWithFrame:CGRectMake(10, 10, [[UIScreen mainScreen] bounds].size.width, 30)]; myLabel.text=@"日记列表"; [headView addSubview:myLabel]; } return headView; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:BLSRecyclingRecordViewController_CellIdentifier]; if (indexPath.section == 0) { DDLogFileInfo *logFileInfo = (DDLogFileInfo *)self.logFiles[indexPath.row]; cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; cell.textLabel.text = indexPath.row == 0 ? NSLocalizedString(@"当前", @"") : [self.dateFormatter stringFromDate:logFileInfo.creationDate]; cell.textLabel.textAlignment = NSTextAlignmentLeft; } else { cell.accessoryType = UITableViewCellAccessoryNone; cell.textLabel.textAlignment = NSTextAlignmentCenter; cell.textLabel.text = NSLocalizedString(@"清理旧的记录", @""); } return cell; } #pragma mark - Table view delegate - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:YES]; if (indexPath.section == 0) { DDLogFileInfo *logFileInfo = (DDLogFileInfo *)self.logFiles[indexPath.row]; NSData *logData = [NSData dataWithContentsOfFile:logFileInfo.filePath]; NSString *logText = [[NSString alloc] initWithData:logData encoding:NSUTF8StringEncoding]; LoggerDetailViewController *detailViewController = [[LoggerDetailViewController alloc] initWithLog:logText forDateString:[self.dateFormatter stringFromDate:logFileInfo.creationDate]]; [self.navigationController pushViewController:detailViewController animated:YES]; } else { for (DDLogFileInfo *logFileInfo in self.logFiles) { //除了当前 其它进行清除 if (logFileInfo.isArchived) { [[NSFileManager defaultManager] removeItemAtPath:logFileInfo.filePath error:nil]; } } [self loadLogFiles]; [self.myTableView reloadData]; } } @end

    这边把表格分成两部分,一部分是日志文件的列表,以及一个清除功能,清除功能主要是对先前的文件进行删除的操作,读取日志的个数及日志时间,日志详细内容

    DDLogFileInfo

    6:异常的详细信息页面

    LoggerDetailViewController.h代码
    
    #import <UIKit/UIKit.h> @interface LoggerDetailViewController : UIViewController - (id)initWithLog:(NSString *)logText forDateString:(NSString *)logDate; @end
    LoggerDetailViewController.m文件
    
    #import "LoggerDetailViewController.h" @interface LoggerDetailViewController () @property (nonatomic, strong) NSString *logText; @property (nonatomic, strong) NSString *logDate; @property (nonatomic, strong) UITextView *textView; @end @implementation LoggerDetailViewController - (void)viewDidLoad { [super viewDidLoad]; self.textView = [[UITextView alloc] initWithFrame:self.view.bounds]; self.textView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; self.textView.editable = NO; self.textView.text = self.logText; [self.view addSubview:self.textView]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } - (id)initWithLog:(NSString *)logText forDateString:(NSString *)logDate { self = [super initWithNibName:nil bundle:nil]; if (self) { _logText = logText; _logDate = logDate; self.title = logDate; } return self; } @end

    7:如果有第三方其它记录异常的使用,最好用DEBUG模式本地记录异常日志,不然日志只会被记录在一个地方

        //友盟统计加载
        [HYBUMAnalyticsHelper UMAnalyticStart];
        
        #ifdef DEBUG
        //日志框架(放在其它SDK下面 MyExceptionHandler)
        [MyExceptionHandler setDefaultHandler];
        #else
        
        #endif
    
        [MyFileLogger sharedManager];

     

     

    这样便可以实现不管在哪个页面出出异常都可以进行记录,因为实例比较小,如果要源代码可以留下邮箱统一进行发送;

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-15 05:24 , Processed in 0.069341 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表