2019年年初iOS招人心得筆記 答案 (二)

11、Objective-C與C、C++之間的聯(lián)系和區(qū)別?

OC

  1. OC是C的超集,擴展了C語言使它具備面向對象設計的能力。例如類、消息、繼承;同時在OC的代碼中可以有C和C++語句,它可以調用C的函數(shù),也可以通過C++對象訪問方法;
  2. OC不同于C++,盡管都有面向對象的能力,但他們分屬不同的學派,OC屬于SmallTalk學派,C++屬于Simula 67學派(一種早期的面向對象語言)。
  3. OC可以底層系統(tǒng)編程,另一方面可以支持利用動態(tài)架構進行開發(fā)。

OC于C++的比較

兩者都是面向對象設計語言,有很多相似之處,但屬于不同的學派,也有不同之處:

  1. 繼承:OC不支持多繼承,C++支持多繼承
  2. 函數(shù)調用:OC通過傳遞消息實現(xiàn)函數(shù)調用,而C++直接進行函數(shù)調用
  3. 定型:OC是動態(tài)類型,所以它的類庫比C++容易操作。OC在運行時可以允許根據(jù)字符串名字訪問方法和類,還可以動態(tài)鏈接和添加庫。而C++,對象的靜態(tài)類型決定你是否可以發(fā)消息給它。
  4. 接口:OC采用協(xié)議(正式和非正式)的形式定義接口,而C++采用虛函數(shù)的形式定義接口
  5. 方法重載:OC不支持方法重載,C++支持方法重載。方法重載就是方法名相同,參數(shù)個數(shù)相同,但是參數(shù)類型不同或者返回值不同。

兩者的主要差別是因為OC即支持動態(tài)類型也支持靜態(tài)類型。對于id類型的變量,變量只是一個容器,本身是沒有類型的,或者只是屬于最基本的類型,所以也不需要強制類型轉換。因為編譯器不會檢查變量類型是否正確,只是運行時如果類型不正確才會產(chǎn)生異常。

而C++是靜態(tài)語言,編譯時會檢查類型,所以必須要加上強制類型轉換,否則編譯器就會報錯。

12、UICollectionView自定義layout如何實現(xiàn)?

  1. 創(chuàng)建UICollectionViewLayout子類
  2. 創(chuàng)建UICollectionViewLayoutAttributes子類,用于描述每個cell的size,frame,transform屬性。
  3. 重寫prepare方法,并在方法內(nèi)部實現(xiàn)各個cell的size、center等的計算。
  4. 重寫layoutAttributesForElements和layoutAttributesForItem方法,方法內(nèi)部返回UICollectionViewLayoutAttributes實例用于對cell進行布局。
  5. 如果有自定義attribute屬性,可以放在UICollectionViewLayoutAttributes類中,并在cell實現(xiàn)類的applyLayoutAttributes方法中為每個cell進行屬性賦值。

13、進程和線程的區(qū)別?同步異步的區(qū)別?并行和并發(fā)的區(qū)別?

  • 進程和線程
    進程:一個正在運行的程序可以看做一個進程。(例如:正在運行的QQ就是一個進程),進程擁有獨立運行所需的全部資源。
    線程:程序中獨立運行的代碼段。(例如:接收QQ消息的代碼)
    一個進程是由一或多個線程組成。進程只負責資源的調度和分配,線程才是程序真正的執(zhí)行單元,負責代碼的執(zhí)行。

  • 同步和異步
    同步是指:當程序1調用程序2時,程序1停下不動,直到程序2完成回到程序1,程序1才繼續(xù)執(zhí)行下去。
    異步是指:當程序1調用程序2時,程序1徑直繼續(xù)自己的下一個動作,不受程序2的影響。
    或者
    同步是指:發(fā)送方發(fā)出數(shù)據(jù)后,等接受方發(fā)揮響應以后才發(fā)下一個數(shù)據(jù)包的通信方式
    異步是指:發(fā)送方發(fā)出數(shù)據(jù)后,不等接收方發(fā)回響應,接著發(fā)送下一個數(shù)據(jù)包的通訊方式。

  • 并行和并發(fā)
    并行(parallel):同一時刻可以互不干擾的同時做幾件事


    并行.png

并發(fā)(concurrency):統(tǒng)一時間段做幾件事


并發(fā).png

并發(fā)的解決方案:

  1. 隊列和緩沖區(qū)
  2. 爭搶鎖資源
  3. 預處理
  4. 并行
  5. 提速
  6. 消息中間件(RabbitMQ)

參考鏈接
http://www.itdecent.cn/p/c334f8198f9b

14、線程間通信?

線程間通信的體現(xiàn):
一個線程傳遞數(shù)據(jù)給另一個線程
在一個線程中執(zhí)行玩特定任務后,轉到另一個線程繼續(xù)執(zhí)行任務

常用的線程間通信的方法

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;作者:Smallwolf_JS

15、GCD的一些常用的函數(shù)?(group,barrier,信號量,線程同步)

GCD的使用很簡單:

  1. 創(chuàng)建一個隊列(串行隊列和并行隊列)
  2. 將任務追加到等待隊列中,然后系統(tǒng)就會根據(jù)任務的類型執(zhí)行(同步執(zhí)行和異步執(zhí)行)

dispatch_queue_create
dispatch_barrier_async
dispatch_after
dispatch_once
dispatch_apply

dispatch_group
dispatch_group_notify
dispatch_group_wait
dispatch_group_enter
dispatch_group_leave

信號量的作用在于處理多線程任務訪問資源限制的問題,有時候也用于上鎖和解鎖的問題。
dispatch_semaphore_create
dispatch_semaphore_signal 增加信號量
dispatch_semaphore_wait 減少信號量

/**
 * 線程安全:使用 semaphore 加鎖
 * 初始化火車票數(shù)量、賣票窗口(線程安全)、并開始賣票
 */
- (void)initTicketStatusSave {
    NSLog(@"currentThread---%@", [NSThread currentThread]);
    NSLog(@"semaphore---begin");
    
    self.semaphoreLock = dispatch_semaphore_create(1);
    
    self.ticketSurplusCount = 50;
    
    dispatch_queue_t queue1 = dispatch_queue_create("net.bujige.testqueue1", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue2 = dispatch_queue_create("net.bujige.testqueue2", DISPATCH_QUEUE_SERIAL);
    
    __weak typeof(self) weakSelf = self;
    
    dispatch_async(queue1, ^{
        [weakSelf saleTicketSafe];
    });
    
    dispatch_async(queue2, ^{
        [weakSelf saleTicketSafe];
    });
}
/**
 * 售賣火車票(線程安全)
 */
- (void)saleTicketSafe {
    while (1) {
        //相當于加鎖
        dispatch_semaphore_wait(self.semaphoreLock, DISPATCH_TIME_FOREVER);
        
        if (self.ticketSurplusCount > 0) {
            self.ticketSurplusCount--;
            NSLog(@"%@", [NSString stringWithFormat:@"剩余票數(shù):%zd 窗口: %@", self.ticketSurplusCount, [NSThread currentThread]]);
            [NSThread sleepForTimeInterval:0.2];
        } else {
            NSLog(@"所有火車票已售完");
            dispatch_semaphore_signal(self.semaphoreLock);
            break;
        }
        //相當于解鎖
        dispatch_semaphore_signal(self.semaphoreLock);
        
    }
}

參考鏈接:
http://www.itdecent.cn/p/2d57c72016c6
http://www.itdecent.cn/p/189a09d669de

16、如何訪問并修改一個類的私有屬性?

訪問以及修改私有屬性的兩種方式:
KVC
runtime
objc_msgSend() 通過私有屬性的setter和getter方法實現(xiàn)

KVC

setValue:forKey:
valueForKey:

-(void)way1{
    PrivateVariablesClass *classA = [[PrivateVariablesClass alloc] init];
    [classA setValue:@(4) forKey:@"_priviteNum"];
    [classA setValue:self.view forKey:@"_priviteView"];
    [classA showPropertyPrivateVariablesClass];
}

runtime

-(void)way2{
    PrivateVariablesClass *classA = [[PrivateVariablesClass alloc] init];
    
    unsigned int outCount = 0;
    Ivar *ivars = class_copyIvarList([PrivateVariablesClass class], &outCount);
    
    for (int i = 0; i < outCount; i ++) {
        Ivar ivar = ivars[i];
        
        const char *ivarName = ivar_getName(ivar);
        
        //這里要注意ARC下, 這個會報錯
        /**
         在修改NSInteger型變量的時候,ARC下,編譯器不允許你將NSInteger類型的值賦值給id,在buildsetting中將Objective-C Automatic Reference Counting修改為No即可。但是這樣工程就會變成MRC,所以,如果是非對象類型就不建議用object_setIvar這樣的方法去修改了。
         */
 
        int a = strcmp(ivarName, "_priviteNum");
        if (strcmp(ivarName, "_priviteNum") == 0) {
            //這種方式傳值int類型會報錯,不能傳入
            object_setIvar(classA, ivar, 22);
        }
        
        if (strcmp(ivarName, "_priviteView") == 0) {
            object_setIvar(classA, ivar, self.view);
        }
    }
    
    [classA showPropertyPrivateVariablesClass];
}

使用ivar_getName()獲取屬性名并使用object_setIvar()修改屬性值,使用獲取的屬性名通過valueForKey:修改屬性值

objc_msgSend()

-(void)way3{
    PrivateVariablesClass *classA = [[PrivateVariablesClass alloc] init];
    ((void (*)(id, SEL, int))(void *) objc_msgSend)((id)classA, @selector(setPriviteNum:) , 33);
    ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)classA, @selector(setPriviteView:) , self.view);
    [classA showPropertyPrivateVariablesClass];
}

17、數(shù)據(jù)持久化的幾個方案(fmdb用沒用過)

  • plist文件(屬性列表)
  • preference(偏好設置)
  • NSKeyedArchiver(歸檔)
  • SQLite 3
  • CoreData

FMDB的三個主要的類:

  • FMDatabase
    一個FMDatabase對象就代表一個單獨的SQLite數(shù)據(jù)庫,用來執(zhí)行SQL語句
  • FMResultSet
    使用FMResultSet執(zhí)行查詢后的結果集
  • FMDatabaseQueue
    用于在多線程中執(zhí)行多個查詢和更新,它是線程安全的

CoreData

iOS10以后使用NSPersistentContainer來管理數(shù)據(jù)庫對象。NSPersistentContainer中包括NSManagedObjectContext、NSManagedObjectModel、NSPersistentStoreCoordinator。

不是太復雜的模型修改,CoreData都可以自動遷移數(shù)據(jù),我們只需要重新生成table映射的model文件即可。

數(shù)據(jù)庫文件默認存放在Library/Application Support文件夾中

參考鏈接
http://www.itdecent.cn/p/7616cbd72845
http://www.itdecent.cn/p/6e048f7c5812

18、說一下AppDelegate的幾個方法?從后臺到前臺調用了哪些方法?第一次啟動調用了哪些方法?從前臺到后臺調用了哪些方法?

  1. 應用啟動,并進行初始化時調用:aaplication:didFimnishLanuchingWithOptions:
  2. 應用進入前臺并處于活動狀態(tài)時候調用:applicationDidBecomeActive:
  3. 應用從活動狀態(tài)進入到非活動狀態(tài):applicationWillResignActive:
  4. 應用進入到后臺時候調用的方法:applicationDidEnterBackground:
  5. 應用進入到前臺時候調用的方法:appplicationWillEnterForeground:
  6. 應用被終止的狀態(tài):applicationWillTeminate:

從后臺到前臺調用了哪些方法?
appplicationWillEnterForeground:
applicationDidBecomeActive:

第一次啟動調用了哪些方法?
aaplication:didFimnishLanuchingWithOptions:
applicationDidBecomeActive:

從前臺到后臺調用了哪些方法?
applicationWillResignActive:
applicationDidEnterBackground:

19、NSCache優(yōu)于NSDictionary的幾點?

  1. NSCache具有自動刪除的功能,以減少系統(tǒng)占用的內(nèi)存
  2. NSCache是線程安全的,不需要加線程鎖;
  3. 鍵對象不會像NSMutableDictionary中那樣被復制。(NSCache的key只是對對象的strong引用,對象不需要實現(xiàn)NSCopying協(xié)議,NSCache也不會像NSDictionary一樣復制對象)。

20、知不知道Designated Initializer?使用它的時候有什么需要注意的問題?

指定初始化函數(shù) vs 便利初始化函數(shù)

  1. 子類如果有指定初始化函數(shù),那么指定初始化函數(shù)實現(xiàn)時必須調用它的直接父類的指定初始化函數(shù)。


    image.png
  2. 子類如果有指定初始化函數(shù),那么便利初始化函數(shù)必須調用自己的其他初始化函數(shù)(包括指定初始化函數(shù)以及其他的便利初始化函數(shù)),不能調用super的初始化函數(shù)。


    image.png
  3. 如果子類提供了指定初始化函數(shù),那么一定要實現(xiàn)所有父類的指定初始化函數(shù)。


    image.png
image.png

當 initWithCoder: 遇到 NS_DESIGNATED_INITIALIZER

  • 如果父類沒有實現(xiàn)NSCoding協(xié)議,那么應該調用父類的指定初始化函數(shù)
  • 如果父類實現(xiàn)了NSCoding協(xié)議,那么子類的initWithCoder:的實現(xiàn)中需要調用父類的initWithCoder:方法

實現(xiàn)NSCoding協(xié)議的時候,我們可以顯示的聲明 initWithCoder: 為指定初始化函數(shù)(一個類可以有多個指定初始化函數(shù),比如UIViewController)即可完美解決問題,既滿足了指定初始化函數(shù)的三個規(guī)則,又滿足了NSCoding協(xié)議的三條原則。

總計歸納

  • 便利初始化函數(shù)只能調用自己類中的其他初始化方法
  • 指定初始化函數(shù)才有資格調用父類的指定初始化函數(shù)
image.png

參考文章
https://www.cnblogs.com/smileEvday/p/designated_initializer.html

21、實現(xiàn)description方法能取到什么效果?

NSLog(@"%@",object);
調試的時候方便打印對自己有用的信息

22、objc使用什么機制管理對象內(nèi)存?

ARC自動引用計數(shù)

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

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

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,674評論 1 32
  • 1.設計模式是什么? 你知道哪些設計模式,并簡要敘述?設計模式是一種編碼經(jīng)驗,就是用比較成熟的邏輯去處理某一種類型...
    龍飝閱讀 2,303評論 0 12
  • 中國向來就是禮尚往來的國家。禮數(shù)也一直是我們從小到大學習的規(guī)矩。 比如,朋友結婚,邀請你吃飯,你會帶紅包參加婚禮,...
    阿_方閱讀 308評論 0 0
  • 文 集:1年100萬字作 者:爬格子的兔子 關注戰(zhàn)隼、大錘、李笑來、彭小六等人或聽過樊登讀書會的朋友,對元認知這個...
    王大大來了吖閱讀 717評論 2 7
  • 場景1:上班很累,還要做家務,做飯。 我的回答:老公,今天上班從早上8點到下午3點,給我忙的一口水都沒喝,現(xiàn)在下了...
    周程程愛說大實話閱讀 155評論 0 0

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