iOS调试信息可视化

前言

在实际开发中,调试程序必不可少,Xcode模拟器与真机调试相比,有时候会有很大区别,因此有时候我们需要在利用真机调试的时候,还能实时的打印log信息,简单的说来就是把显示在控制台中的NSLog信息实时的显示的真机设备上.

思路

首先,收集log信息并不难,下文会有代码和demo供参考.
其次,调试界面的调出应该隐蔽,防止用户调出来影响体验,只有我们程序员知道如何调出来,你可以通过三指下滑调出或者摇一摇调出调试模式,后期测试无bug之后再删除该功能即可.
最后,你调出的调试界面不应该影响你对程序的其他操作,并且该模式可以在任意时刻通过隐藏手势调出来,这就要求该调试界面必须可以挪动,可以放大缩小并且隐藏手势要写到任何地方都能响应的地方,这样就不影响你进行其他页面的操作了.

具体实现过程

对调试模式封装,继承自UIView,上代码

YYLogView.h文件

//
//  YYLogView.h
//  Log
//
//  Created by yyMae on 15/12/23.
//  Copyright (c) 2015年 yyMae. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface YYLogView : UIView
//直接初始化 添加到目标父视图即可使用
@end

YYLogView.m文件

//
//  YYLogView.m
//  Log
//
//  Created by yyMae on 15/12/23.
//  Copyright (c) 2015年 yyMae. All rights reserved.
//  调试信息可视化(NSLog信息实时显示,可缩放,可挪动)

#import "YYLogView.h"

@interface YYLogView ()<UIGestureRecognizerDelegate>
@property (nonatomic ,strong) UIView *keyView;
@property (nonatomic ,strong) UITextView *logView;
@property (nonatomic ,strong) UIButton *whiteSpotBtn;

@end
@implementation YYLogView

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self addSubview:self.keyView];
        
    }
    return self;
}

-(UIView *)keyView{
    if (_keyView==nil) {
        self.keyView=[[UIView alloc]initWithFrame:self.bounds];
        self.logView=[[UITextView alloc]initWithFrame:CGRectMake(25, 15, self.keyView.frame.size.width-50, self.keyView.frame.size.height-30)];
        [self.keyView addSubview:self.logView];
        self.keyView.userInteractionEnabled=YES;
        self.keyView.backgroundColor=[UIColor brownColor];
        self.logView.backgroundColor=[UIColor clearColor];
        self.logView.textColor=[UIColor whiteColor];
        self.logView.editable=NO;
        NSArray  *paths  =  NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
        NSString *docDir = [paths objectAtIndex:0];
        NSString *filePath = [docDir stringByAppendingPathComponent:@"dr.log"];
        NSData *data = [NSData dataWithContentsOfFile:filePath];
        NSString *result = [[NSString alloc] initWithData:data  encoding:NSUTF8StringEncoding];
        self.logView.text=result;
        
        [self addGestureRecognizerToView:self];
        [self timerAction];
        
        //添加一个可以关闭的按钮
        UIButton *closeBtn=[UIButton buttonWithType:UIButtonTypeSystem];
        closeBtn.frame=CGRectMake(0, 5, 30, 15);
        closeBtn.titleLabel.font=[UIFont systemFontOfSize:15];
        [closeBtn setTitle:@"❌" forState:UIControlStateNormal];
        [closeBtn addTarget:self action:@selector(closeLoggerView) forControlEvents:UIControlEventTouchUpInside];
        [self.keyView addSubview:closeBtn];
    }
    return _keyView;
}

//==========缩放 移动 =================
// 添加所有的手势
- (void) addGestureRecognizerToView:(UIView *)view
{
    
    
    // 缩放手势
    UIPinchGestureRecognizer *pinchGestureRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchView:)];
    [view addGestureRecognizer:pinchGestureRecognizer];
    
    // 移动手势
    UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panView:)];
    [view addGestureRecognizer:panGestureRecognizer];
}

// 处理缩放手势
- (void) pinchView:(UIPinchGestureRecognizer *)pinchGestureRecognizer
{
    UIView *view = pinchGestureRecognizer.view;
    if (pinchGestureRecognizer.state == UIGestureRecognizerStateBegan || pinchGestureRecognizer.state == UIGestureRecognizerStateChanged) {
        view.transform = CGAffineTransformScale(view.transform, pinchGestureRecognizer.scale, pinchGestureRecognizer.scale);
        pinchGestureRecognizer.scale = 1;
    }
}

// 处理拖拉手势
- (void) panView:(UIPanGestureRecognizer *)panGestureRecognizer
{
    UIView *view = panGestureRecognizer.view;
    if (panGestureRecognizer.state == UIGestureRecognizerStateBegan || panGestureRecognizer.state == UIGestureRecognizerStateChanged) {
        CGPoint translation = [panGestureRecognizer translationInView:view.superview];
        [view setCenter:(CGPoint){view.center.x + translation.x, view.center.y + translation.y}];
        [panGestureRecognizer setTranslation:CGPointZero inView:view.superview];
    }
}

- (void)timerAction{
    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.5 target:self selector:@selector(readd) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
    
}

-(void)readd{
    
    NSArray  *paths  =  NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
    NSString *docDir = [paths objectAtIndex:0];
    NSString *filePath = [docDir stringByAppendingPathComponent:@"dr.log"];
    NSData *data = [NSData dataWithContentsOfFile:filePath];
    NSString *result = [[NSString alloc] initWithData:data  encoding:NSUTF8StringEncoding];
    self.logView.text = result;
}

//关闭
-(void)closeLoggerView{
    [self removeFromSuperview];
}

@end

AppDelegate.m中收集NSLog信息,并且通过摇一摇手势调出调试界面

//
//  AppDelegate.m
//  Log
//
//  Created by yyMae on 15/12/15.
//  Copyright (c) 2015年 yyMae. All rights reserved.
//

#import "AppDelegate.h"
#import "YYLogView.h"
@interface AppDelegate ()<UIGestureRecognizerDelegate>

@property (nonatomic,strong) YYLogView *loggerView;
@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [self saveLog];
    self.loggerView=[[YYLogView alloc]initWithFrame:CGRectMake(10, 80, self.window.frame.size.width-20, 200)];
    NSLog(@"调试信息可视化");
    NSLog(@"输出");
    return YES;
}

-(void)saveLog{
    
    NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *document = [path objectAtIndex:0];
    NSString *fileName = [NSString stringWithFormat:@"dr.log"];
    NSString *logPath = [document stringByAppendingPathComponent:fileName];
    
    NSFileManager *defaulManager = [NSFileManager defaultManager];
    [defaulManager removeItemAtPath:logPath error:nil];
    
    freopen([logPath cStringUsingEncoding:NSASCIIStringEncoding], "a+", stdout);
    freopen([logPath cStringUsingEncoding:NSASCIIStringEncoding], "a+", stderr);
    
}
////摇一摇
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
{

    if (motion == UIEventSubtypeMotionShake) {

        [[[UIApplication sharedApplication]keyWindow]addSubview:self.loggerView];
        

    }
}

@end

需要学习的可以看下我写的demo

github地址:https://github.com/yyMae/Log-

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容