无侵入埋点之从UIApplicationMain函数的参数入手

11511686475_.pic.jpg

作者二亮子用写IB省出的时间出了这本书,这本书确实是一本好书,本人也会在通读全书后对书中IB知识点进行总结归纳学习 此篇文章是此书中在扩展部分非IB系列总结出来,所以单独列出来

文章目录

  • OC代码分析
    • 第一个参数 argc
    • 第二个参数 argv
    • 第三个参数 nil(principalClassName) 无侵入埋点实现方案重点在此参数
    • 第四个参数 delegateClassName
  • Swift代码分析

乍一看标题 UIApplicationMain函数怎么会和无侵入埋点扯到一块呢,下边先来慢慢分析 UIApplicationMain函数

一 OC代码分析

在OC工程中有一个main.m的文件, App启动时候首先要初始化所有的类(注意这一步是初始化类,而不是实例),然后调用main.m中的main函数
可以把APP的启动过程简单的分成两个阶段:
1 从类的初始化到Main函数的执行
2 从Main函数的执行到application:didFinishLaunchingWithOptions的执行。main函数的实现很简单如下

int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

调用UIApplicationMain函数并返回,这里需要注意一点,通常来讲,Main函数返回就代表着程序的退出,但实际上该函数并不会返回,也就是说APP不会退出,主要原因就在于RunLoop的存在,其内部是一个do-while循环,保证了程序一直运行。这是一个普遍的解决方案,并不是iOS特有的,在Android中有looper做类似的事情

1 第一个参数argc

argc 是int 类型,代表程序启动时的参数个数,默认是1

2 第二个参数argv

char *[]类型,代表各个参数的值,默认程序启动的名字

3 第三个参数 nil 无侵入埋点实现方案重点在此参数

principalClassNameNSString类型,参数必须传一个UIApplication或其子类的类名对应的字符串,用于实例化一个UIApplication及其子类对象,大多数情况传nil, 传nil就是用UIApplication类的名字对应的字符串作为参数, 相当于穿了一个 NSStringFromClass([UIApplication class]),但实际上这是一个很有用的参数, 如果要针对UIApplication来 完成一些事情的话, 那么可以自定义一个UIApplication的子类, 例如有一些各个页面都需要处理的繁琐事情, 想在某各类中集中处理, 就可以考虑自定义一个 UIApplication的子类,通过设置这个参数,在该子类中统一做这些事情, 而不是将这些事情分散到各个页面对应的VC处理。

App日志的统计类似于这样的一种需求: 如果要记录App的行为日志, 但又不想每个页面对应的VC都处理这种琐碎的事情, 而是更希望这些VC做一些他们负责的交互与业务逻辑的事情,而是更希望这些VC做这些他们自己负责的交互与业务逻辑的事情, 那么这种需求就可以用到刚刚提到的 思路来解决。自定义一个继承于UIApplication的类-----TestApplication ,在Main方法中将其定义为第三个参数 如下:

int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv,NSStringFromClass([TestApplication class]), NSStringFromClass([AppDelegate class]));
    }
}

假如UIApplication类中有一个和Event相关的API,所以可以利用这些API,完成记录行为日志的任务, 如下:

- (void)sendEvent:(UIEvent *)event{
   // 在这里处理一些统一的逻辑
   [super sendEvent:event];
}
- (BOOL)sendAction:(SEL)action to:(id)target from:(id)sender forEvent:(UIEvent *)event{
   // 在这里处理一些统一的逻辑, 例如 记录行为日志   
  return  [super sendAction:action to:target from:sender forEvent:event];    
}

sendAction:to:from:forEvent这个方法可以很好的解决现有的需求, 例如要统计登录页面中点击登录按钮的这个行为, 可以通过Target参数判断页面, 通过sender判断出发事件的按钮,通过action判断触发的事件名称,有了这些信息,就可以判断出一个行为是否是登录页面的点击登录按钮行为从而将行为记录下来, 或上报给服务器, 当然这种需求也有很多其他的解决办法,例如利用runtime和OC的消息转发机制,可以将该需求实现的更灵活,但自定义UIApplication的方法却是最为简单方便的, 如下

- (BOOL)sendAction:(SEL)action to:(id)target from:(id)sender forEvent:(UIEvent *)event{
    
    if ([target isKindOfClass:[LLLoginViewController class]] && [sender isKindOfClass:[UIButton class]] && [NSStringFromSelector(action) isEqualToString:@"loginActionClick"]) {
        // 记录登录行为日志 或上报服务器
    }    
   return  [super sendAction:action to:target from:sender forEvent:event];
}
4 第四个参数delegateClassName 也是NSString类型, 指定一个继承于UIResponder并遵循UIApplicationDelagate协议的类的实例,这个类有xcode 的模板准备,即AppDelegate类, UIApplicationMain函数会以第三个参数创建一个 UIApplication或者其子类的实例,会以第四个参数创建一个他的代理类的实例(通常是AppDelegate类的实例)我们编写代码往往从appDelegate类开始,也可以通过[UIApplication sharedApplication]获得application单例对象。当代码走到UIApplicationMain函数时,就会走到AppDelegate类里,剩下的大家基本就知道了。

二 Swift代码分析

接下来来看一下基于Swift的工程, 我们会发现,工程中并没有main.swift.但是AppDelegate里多了一个@UIApplicationMain,@UIApplicationMain会让编译器自动合成一个APP的入口, 相当于原来的main函数由编译器自动生成。可能是由于在实际的iOS开发中很少修改Main.m中的代码,所以苹果公司觉得这个文件是多余的, 干脆就由编译器自动完成这些事情吧,但是如果确实有需求要修改main函数怎么办, 例如记录行为日志 很简单,首先注释掉@UIApplicationMain,此时会发现编译会报错,这是建立一个main.swift的文件,删除里边的代码,然后添加如下代码就可以正常的编译运行了:

import UIKit
import Foundation

UIApplicationMain(
    CommandLine.argc,
    UnsafeMutableRawPointer(CommandLine.unsafeArgv)
        .bindMemory(
            to: UnsafeMutablePointer<Int8>.self,
            capacity: Int(CommandLine.argc)),
    nil,
    NSStringFromClass(AppDelegate.self)
)

要自定义UIApplication子类,可以将上面代码中传nil得参数替换成自定义的UIApplication子类的类名,例如NSStringFromClass(TestApplication.self),然后再这个文件中重写那个方法 接下来就和OC的一样了 ,可以参考OC语言进行配置了

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

推荐阅读更多精彩内容

  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,121评论 29 470
  • 在面试中,我们经常会遇到一些原理性的问题,很常识但很难用通俗的语言解释清楚,这也是大部分业务级程序员经常失误的地方...
    欧巴冰冰阅读 1,899评论 2 21
  • 1.属性readwrite,readonly,assign,retain,copy,nonatomic 各是什么作...
    曾令伟阅读 1,042评论 0 10
  • swift在AppDelegate.swift中用标签@UIApplicationMain来取代了main函数,现...
    BetterComingDay阅读 3,150评论 1 1
  • 前言: 最近几天在看《100个Swift必备tips》这本书,本篇为读书笔记,以作总结记录用。 将protocol...
    Wang66阅读 1,089评论 0 5