無侵入埋點之從UIApplicationMain函數(shù)的參數(shù)入手

11511686475_.pic.jpg

作者二亮子用寫IB省出的時間出了這本書,這本書確實是一本好書,本人也會在通讀全書后對書中IB知識點進行總結(jié)歸納學習 此篇文章是此書中在擴展部分非IB系列總結(jié)出來,所以單獨列出來

文章目錄

  • OC代碼分析
    • 第一個參數(shù) argc
    • 第二個參數(shù) argv
    • 第三個參數(shù) nil(principalClassName) 無侵入埋點實現(xiàn)方案重點在此參數(shù)
    • 第四個參數(shù) delegateClassName
  • Swift代碼分析

乍一看標題 UIApplicationMain函數(shù)怎么會和無侵入埋點扯到一塊呢,下邊先來慢慢分析 UIApplicationMain函數(shù)

一 OC代碼分析

在OC工程中有一個main.m的文件, App啟動時候首先要初始化所有的類(注意這一步是初始化類,而不是實例),然后調(diào)用main.m中的main函數(shù)
可以把APP的啟動過程簡單的分成兩個階段:
1 從類的初始化到Main函數(shù)的執(zhí)行
2 從Main函數(shù)的執(zhí)行到application:didFinishLaunchingWithOptions的執(zhí)行。main函數(shù)的實現(xiàn)很簡單如下

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

調(diào)用UIApplicationMain函數(shù)并返回,這里需要注意一點,通常來講,Main函數(shù)返回就代表著程序的退出,但實際上該函數(shù)并不會返回,也就是說APP不會退出,主要原因就在于RunLoop的存在,其內(nèi)部是一個do-while循環(huán),保證了程序一直運行。這是一個普遍的解決方案,并不是iOS特有的,在Android中有l(wèi)ooper做類似的事情

1 第一個參數(shù)argc

argc 是int 類型,代表程序啟動時的參數(shù)個數(shù),默認是1

2 第二個參數(shù)argv

char *[]類型,代表各個參數(shù)的值,默認程序啟動的名字

3 第三個參數(shù) nil 無侵入埋點實現(xiàn)方案重點在此參數(shù)

principalClassNameNSString類型,參數(shù)必須傳一個UIApplication或其子類的類名對應的字符串,用于實例化一個UIApplication及其子類對象,大多數(shù)情況傳nil, 傳nil就是用UIApplication類的名字對應的字符串作為參數(shù), 相當于穿了一個 NSStringFromClass([UIApplication class]),但實際上這是一個很有用的參數(shù), 如果要針對UIApplication來 完成一些事情的話, 那么可以自定義一個UIApplication的子類, 例如有一些各個頁面都需要處理的繁瑣事情, 想在某各類中集中處理, 就可以考慮自定義一個 UIApplication的子類,通過設(shè)置這個參數(shù),在該子類中統(tǒng)一做這些事情, 而不是將這些事情分散到各個頁面對應的VC處理。

App日志的統(tǒng)計類似于這樣的一種需求: 如果要記錄App的行為日志, 但又不想每個頁面對應的VC都處理這種瑣碎的事情, 而是更希望這些VC做一些他們負責的交互與業(yè)務(wù)邏輯的事情,而是更希望這些VC做這些他們自己負責的交互與業(yè)務(wù)邏輯的事情, 那么這種需求就可以用到剛剛提到的 思路來解決。自定義一個繼承于UIApplication的類-----TestApplication ,在Main方法中將其定義為第三個參數(shù) 如下:

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

假如UIApplication類中有一個和Event相關(guān)的API,所以可以利用這些API,完成記錄行為日志的任務(wù), 如下:

- (void)sendEvent:(UIEvent *)event{
   // 在這里處理一些統(tǒng)一的邏輯
   [super sendEvent:event];
}
- (BOOL)sendAction:(SEL)action to:(id)target from:(id)sender forEvent:(UIEvent *)event{
   // 在這里處理一些統(tǒng)一的邏輯, 例如 記錄行為日志   
  return  [super sendAction:action to:target from:sender forEvent:event];    
}

sendAction:to:from:forEvent這個方法可以很好的解決現(xiàn)有的需求, 例如要統(tǒng)計登錄頁面中點擊登錄按鈕的這個行為, 可以通過Target參數(shù)判斷頁面, 通過sender判斷出發(fā)事件的按鈕,通過action判斷觸發(fā)的事件名稱,有了這些信息,就可以判斷出一個行為是否是登錄頁面的點擊登錄按鈕行為從而將行為記錄下來, 或上報給服務(wù)器, 當然這種需求也有很多其他的解決辦法,例如利用runtime和OC的消息轉(zhuǎn)發(fā)機制,可以將該需求實現(xiàn)的更靈活,但自定義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"]) {
        // 記錄登錄行為日志 或上報服務(wù)器
    }    
   return  [super sendAction:action to:target from:sender forEvent:event];
}
4 第四個參數(shù)delegateClassName 也是NSString類型, 指定一個繼承于UIResponder并遵循UIApplicationDelagate協(xié)議的類的實例,這個類有xcode 的模板準備,即AppDelegate類, UIApplicationMain函數(shù)會以第三個參數(shù)創(chuàng)建一個 UIApplication或者其子類的實例,會以第四個參數(shù)創(chuàng)建一個他的代理類的實例(通常是AppDelegate類的實例)我們編寫代碼往往從appDelegate類開始,也可以通過[UIApplication sharedApplication]獲得application單例對象。當代碼走到UIApplicationMain函數(shù)時,就會走到AppDelegate類里,剩下的大家基本就知道了。

二 Swift代碼分析

接下來來看一下基于Swift的工程, 我們會發(fā)現(xiàn),工程中并沒有main.swift.但是AppDelegate里多了一個@UIApplicationMain,@UIApplicationMain會讓編譯器自動合成一個APP的入口, 相當于原來的main函數(shù)由編譯器自動生成。可能是由于在實際的iOS開發(fā)中很少修改Main.m中的代碼,所以蘋果公司覺得這個文件是多余的, 干脆就由編譯器自動完成這些事情吧,但是如果確實有需求要修改main函數(shù)怎么辦, 例如記錄行為日志 很簡單,首先注釋掉@UIApplicationMain,此時會發(fā)現(xiàn)編譯會報錯,這是建立一個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得參數(shù)替換成自定義的UIApplication子類的類名,例如NSStringFromClass(TestApplication.self),然后再這個文件中重寫那個方法 接下來就和OC的一樣了 ,可以參考OC語言進行配置了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,199評論 30 471
  • 在面試中,我們經(jīng)常會遇到一些原理性的問題,很常識但很難用通俗的語言解釋清楚,這也是大部分業(yè)務(wù)級程序員經(jīng)常失誤的地方...
    歐巴冰冰閱讀 1,949評論 2 21
  • 1.屬性readwrite,readonly,assign,retain,copy,nonatomic 各是什么作...
    曾令偉閱讀 1,078評論 0 10
  • swift在AppDelegate.swift中用標簽@UIApplicationMain來取代了main函數(shù),現(xiàn)...
    BetterComingDay閱讀 3,227評論 1 1
  • 前言: 最近幾天在看《100個Swift必備tips》這本書,本篇為讀書筆記,以作總結(jié)記錄用。 將protocol...
    Wang66閱讀 1,120評論 0 5