該了解的iOS(二)之核心

該了解的iOS(二)之核心

iOS的核心篇章我主要說深入理解設(shè)計(jì)模式、組件化,模塊化,插件化和app運(yùn)行時(shí)的質(zhì)量監(jiān)控等知識(shí)點(diǎn),不是說別的篇章不是核心篇章,如優(yōu)化,靜、動(dòng)態(tài)分析等,我會(huì)有專門的篇章來詳解它們,不能使一篇文章讀下來找不到重點(diǎn)。

深入理解設(shè)計(jì)模式

設(shè)計(jì)模式中有六大基本原則,它們是設(shè)計(jì)模式的核心指導(dǎo)思想,分別為:

  • 單一職責(zé)原則(single responsibility principle):實(shí)現(xiàn)類要職責(zé)單一
  • 里氏替換原則(liskov substitution principle):不要破壞繼承體系
  • 依賴倒置原則(dependence inversion principle):面向接口編程
  • 接口隔離原則(interface segregation principle):在設(shè)計(jì)接口的時(shí)候要精簡(jiǎn)單一
  • 迪米特法則(law of demeter):降低耦合
  • 開放封閉原則(open close principle):對(duì)外擴(kuò)展開放,修改關(guān)閉

六大原則的遵循,并不是是和否的選擇,更不要刻意去追求,“物極必反,過猶不及”,靈活使用。
設(shè)計(jì)模式又分為創(chuàng)建型(工廠,單例),結(jié)構(gòu)型(代理,組合),行為型(策略,觀察者)等三個(gè)方面.

  1. 單例模式:一般會(huì)封裝一個(gè)靜態(tài)屬性,并提供靜態(tài)實(shí)例的創(chuàng)建方法
static singleton *__singleton = nil;
+ (singleton *)sharedSingleton {
static dispatch_once_t oneToken;

    dispatch_once(&oneToken, ^{

        __singleton = [[singleton alloc]init];

    });
    return __singleton;
}

其中static singleton *__singleton = nil;為靜態(tài)變量,
類方法為(singleton *)sharedSingleton ,
dispatch_once_t 的函數(shù)是GCD提供的,在整個(gè)生命周期只執(zhí)行一次
  1. 委托模式:委托是為了降低一個(gè)對(duì)象的復(fù)雜度和耦合度,使其能夠具有通用性而將其一些處理置于委托對(duì)象中的編碼方法,它通過delegate屬性保持委托對(duì)象,使它來實(shí)現(xiàn)協(xié)議。那委托對(duì)象如何建立引用關(guān)系呢?對(duì)象.delegate = self。如一些復(fù)雜的控件(UITableView),除了實(shí)現(xiàn)委托協(xié)議,還需要實(shí)現(xiàn)數(shù)據(jù)協(xié)議,委托對(duì)象主要對(duì)控件對(duì)象的事件和狀態(tài)作出響應(yīng),而數(shù)據(jù)源對(duì)象是為控件提供數(shù)據(jù)。
  2. 觀察者模式:觀察者模式中兩個(gè)具體應(yīng)用就是(通知,KVO),通知機(jī)制是“一對(duì)多”的對(duì)象間通信,不僅有本地通知還有遠(yuǎn)程通知。KVO是在對(duì)象屬性發(fā)生變化時(shí)通知會(huì)被直接發(fā)送給觀察者
  3. MVC模式:這個(gè)已經(jīng)眾所周知的了,其實(shí)它是一種復(fù)合設(shè)計(jì)模式,由(觀察者+策略+組合)模式等組成,具體就是不同而異,可以用成MVP,MVVM,都是根據(jù)你項(xiàng)目來合理使用了。
分層架構(gòu)設(shè)計(jì)

衡量一個(gè)軟件架構(gòu)的好壞是它的可復(fù)用性和可擴(kuò)展性來滿足用戶不斷變化的需求,我認(rèn)為采用分層架構(gòu)的設(shè)計(jì),實(shí)現(xiàn)低耦合,高內(nèi)聚。

  1. 表示層:用戶與系統(tǒng)交互的組件集合
  2. 業(yè)務(wù)邏輯層:系統(tǒng)的核心業(yè)務(wù)處理層
  3. 數(shù)據(jù)持久層:數(shù)據(jù)持久層用戶訪問信息系統(tǒng),對(duì)文件進(jìn)行讀寫操作
  4. 信息系統(tǒng)層:系統(tǒng)的數(shù)據(jù)來源,可以是數(shù)據(jù)庫(kù),文件或者網(wǎng)絡(luò)數(shù)據(jù)等

組件化、模塊化、插件化

  • 組件:強(qiáng)調(diào)復(fù)用,避免重復(fù)造輪子。在開發(fā)過程中,一些核心技術(shù)或者常用框架,出于安全性和穩(wěn)定性的考慮,不想被外界知道,所以會(huì)把核心代碼打包成庫(kù),只暴露出頭文件以供使用。
  • 模塊:強(qiáng)調(diào)職責(zé),這是一個(gè)可實(shí)現(xiàn)的單元,其核心是內(nèi)聚和分離,如登錄注冊(cè)可分離成獨(dú)立的模塊
  • 插件化:強(qiáng)調(diào)化大為小,插件化在運(yùn)行時(shí)合并模塊。

組件模塊化思想是軟件開發(fā)的基本思想,組件化的目的就是復(fù)用代碼模塊,解除業(yè)務(wù)和代碼的耦合,組件間彼此分離,便于開發(fā),測(cè)試,維護(hù)和獨(dú)立編譯。解決主工程打包時(shí)組件間重復(fù)引用的問題,引入bridge組件庫(kù)或pod添加,避免組件間直接耦合,具體請(qǐng)看:http://www.itdecent.cn/p/210825875f39

質(zhì)量監(jiān)控

有時(shí)會(huì)說“沒有崩潰,就沒有我”,在快速迭代的過程中可能因?yàn)橹饔^原因,如技術(shù)有限,知識(shí)盲點(diǎn),粗心導(dǎo)致的crash,或者客觀原因版本升級(jí),手機(jī)卡頓,網(wǎng)絡(luò)卡頓等導(dǎo)致的crash。雖然我們不能阻止崩潰,但我們可以去發(fā)現(xiàn)它,分析它,解決它。一套完美的質(zhì)量監(jiān)控應(yīng)該包括:基本驗(yàn)證,穩(wěn)定性,兼容性,安全性,功能測(cè)試和線上質(zhì)量檢測(cè)

  1. 基本驗(yàn)證:版本號(hào),簽名,賬號(hào),代碼質(zhì)量等
  2. 穩(wěn)定性:一些性能指標(biāo),如CPU,內(nèi)存,流暢度,包大小,啟動(dòng)時(shí)間,響應(yīng)速度等
  3. 兼容性:多版本適配,多網(wǎng)絡(luò),低電量等
  4. 安全性:加密,解密。惡意攻擊等
  5. 功能測(cè)試:?jiǎn)卧獪y(cè)試,自動(dòng)化測(cè)試
  6. 線上質(zhì)量檢測(cè):用戶反饋,crash收集,數(shù)據(jù)統(tǒng)計(jì)等

有一些驗(yàn)證是需要人工的,但是有一些可以通過自動(dòng)化的,去嘗試寫一些腳本保證質(zhì)量過關(guān),當(dāng)然也可以選擇一些好用的第三方平臺(tái)。

  • 關(guān)于線下性能監(jiān)控:蘋果公司官方就有一個(gè)性能監(jiān)控工具 Instruments。它是一款被集成在 Xcode 里,專門用來在線下進(jìn)行性能分析的工具.Instruments 的功能非常強(qiáng)大,比如說 Energy Log 就是用來監(jiān)控耗電量的,Leaks 就是專門用來監(jiān)控內(nèi)存泄露問題的,Network 就是用來專門檢查網(wǎng)絡(luò)情況的,Time Profiler 就是通過時(shí)間采樣來分析頁(yè)面卡頓問題的。
  • 對(duì)于線上性能監(jiān)控:監(jiān)控代碼不要侵入到業(yè)務(wù)代碼中,采用性能消耗最小的監(jiān)控方案,主要集中在 CPU 使用率、FPS 的幀率和內(nèi)存這三個(gè)方面

CPU

<!--cpu_usage 就是 CPU 使用率-->


+ (integer_t)cpuUsage {
    thread_act_array_t threads; //int 組成的數(shù)組比如 thread[1] = 5635
    mach_msg_type_number_t threadCount = 0; //mach_msg_type_number_t 是 int 類型
    const task_t thisTask = mach_task_self();
    //根據(jù)當(dāng)前 task 獲取所有線程
    kern_return_t kr = task_threads(thisTask, &threads, &threadCount);
    
    if (kr != KERN_SUCCESS) {
        return 0;
    }
    
    integer_t cpuUsage = 0;
    // 遍歷所有線程
    for (int i = 0; i < threadCount; i++) {
        
        thread_info_data_t threadInfo;
        thread_basic_info_t threadBaseInfo;
        mach_msg_type_number_t threadInfoCount = THREAD_INFO_MAX;
        
        if (thread_info((thread_act_t)threads[i], THREAD_BASIC_INFO, (thread_info_t)threadInfo, &threadInfoCount) == KERN_SUCCESS) {
            // 獲取 CPU 使用率
            threadBaseInfo = (thread_basic_info_t)threadInfo;
            if (!(threadBaseInfo->flags & TH_FLAGS_IDLE)) {
                cpuUsage += threadBaseInfo->cpu_usage;
            }
        }
    }
    assert(vm_deallocate(mach_task_self(), (vm_address_t)threads, threadCount * sizeof(thread_t)) == KERN_SUCCESS);
    return cpuUsage;
}

FPS

<!--對(duì) FPS 的監(jiān)控也可以比較簡(jiǎn)單的實(shí)現(xiàn):通過注冊(cè) CADisplayLink 得到屏幕的同步刷新率,記錄每次刷新時(shí)間,然后就可以得到 FPS-->
- (void)start {
    self.dLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(fpsCount:)];
    [self.dLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}

// 方法執(zhí)行幀率和屏幕刷新率保持一致
- (void)fpsCount:(CADisplayLink *)displayLink {
    if (lastTimeStamp == 0) {
        lastTimeStamp = self.dLink.timestamp;
    } else {
        total++;
        // 開始渲染時(shí)間與上次渲染時(shí)間差值
        NSTimeInterval useTime = self.dLink.timestamp - lastTimeStamp;
        if (useTime < 1) return;
        lastTimeStamp = self.dLink.timestamp;
        // fps 計(jì)算
        fps = total / useTime; 
        total = 0;
    }
}

內(nèi)存


<!--蘋果公司介紹說 phys_footprint 才是實(shí)際使用的物理內(nèi)存。-->

struct task_vm_info {
  mach_vm_size_t  virtual_size;       // 虛擬內(nèi)存大小
  integer_t region_count;             // 內(nèi)存區(qū)域的數(shù)量
  integer_t page_size;
  mach_vm_size_t  resident_size;      // 駐留內(nèi)存大小
  mach_vm_size_t  resident_size_peak; // 駐留內(nèi)存峰值

  ...

  /* added for rev1 */
  mach_vm_size_t  phys_footprint;     // 物理內(nèi)存
  ...

<!--取出 phys_footprint 字段的值,就能夠監(jiān)控到實(shí)際物理內(nèi)存的使用情況了-->
  
uint64_t memoryUsage() {
    task_vm_info_data_t vmInfo;
    mach_msg_type_number_t count = TASK_VM_INFO_COUNT;
    kern_return_t result = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t) &vmInfo, &count);
    if (result != KERN_SUCCESS)
        return 0;
    return vmInfo.phys_footprint;
}

東西不多,但很實(shí)用。接下來我會(huì)詳談項(xiàng)目中的網(wǎng)絡(luò)請(qǐng)求,性能優(yōu)化和一些高級(jí)知識(shí)點(diǎn)的總結(jié)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容