iOS 面試總結(jié)

iOS 面試總結(jié)

UI相關(guān)面試題

系統(tǒng)的UI事件傳遞機(jī)制是怎樣的?

hidtest 和hidpoint 內(nèi)部實(shí)現(xiàn)
先判斷自己是否隱藏或者支持用戶響應(yīng)或者是否具有透明度,然后從頂部倒序開(kāi)始尋找相應(yīng)視圖

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    if (!self.userInteractionEnabled ||
        [self isHidden] ||
        self.alpha <= 0.01) {
        return nil;
    }
    
    if ([self pointInside:point withEvent:event]) {
        //遍歷當(dāng)前對(duì)象的子視圖
        __block UIView *hit = nil;
        [self.subviews enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            // 坐標(biāo)轉(zhuǎn)換
            CGPoint vonvertPoint = [self convertPoint:point toView:obj];
            //調(diào)用子視圖的hittest方法
            hit = [obj hitTest:vonvertPoint withEvent:event];
            // 如果找到了接受事件的對(duì)象推捐,則停止遍歷
            if (hit) {
                *stop = YES;
            }
        }];
        
        if (hit) {
            return hit;
        }
        else{
            return self;
        }
    }
    else{
        return nil;
    }
}

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    CGFloat x1 = point.x;
    CGFloat y1 = point.y;
    
    CGFloat x2 = self.frame.size.width / 2;
    CGFloat y2 = self.frame.size.height / 2;
    
    double dis = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
    // 67.923
    if (dis <= self.frame.size.width / 2) {
        return YES;
    }
    else{
        return NO;
    }
}

使UITableView滾動(dòng)更流暢得方案和思路都有哪些?

cpu+GPU

cpu 采用子線程進(jìn)行對(duì)象創(chuàng)建銷毀,包括進(jìn)行預(yù)排版,以及圖片的解碼,

Gpu 和異步繪制方案
kvo實(shí)現(xiàn)原理,kvc實(shí)現(xiàn)原理,通知實(shí)現(xiàn)原理

用分類做什么

1聲明私有方法

2分解體積龐大的類文件

3把framework的私有方法進(jìn)行公開(kāi)

分類的特點(diǎn)

運(yùn)行時(shí)決議

可以為系統(tǒng)類添加分類

分類可以添加哪些內(nèi)容

實(shí)例方法

類方法

協(xié)議

屬性

成員變量(使用關(guān)聯(lián)對(duì)象)

擴(kuò)展

編譯時(shí)決議

只以聲明的形式存在,多數(shù)情況下寄生于宿主類的.m中

不能為系統(tǒng)添加擴(kuò)展

代理

代理是一種軟件設(shè)計(jì)模式

代理是用代理模式實(shí)現(xiàn)

傳遞一對(duì)一

通知

使用觀察者模式來(lái)實(shí)現(xiàn)的用于跨層傳遞消息的機(jī)制

傳遞方式為一對(duì)多

kvo

kvo是Objiective-C對(duì)觀察者設(shè)計(jì)模式的又一種實(shí)現(xiàn)

Apple 使用了isa混寫(xiě)(is-swizzling)來(lái)實(shí)現(xiàn)kvo

runtime

image.png

blcok

對(duì)象、函數(shù)封裝筒愚、執(zhí)行上下文

不需要__blcok 的情況靜態(tài)局部變量寡喝、全局變量、靜態(tài)全局變量


image.png

image.png

image.png

image.png

該解決循環(huán)引用有一個(gè)問(wèn)題,就是,如果不調(diào)用該方法,那么這個(gè)環(huán)會(huì)一直存在

什么是blcok

是一個(gè)對(duì)象扔役、對(duì)函數(shù)封裝爽丹、執(zhí)行上下文

為什么block會(huì)產(chǎn)生循環(huán)引用

自循環(huán)引用,多循環(huán)引用
1乳附、如果說(shuō)當(dāng)前blcok對(duì)當(dāng)前某一成員變量進(jìn)行截獲,block會(huì)對(duì)對(duì)應(yīng)變量,有一個(gè)強(qiáng)引用,當(dāng)前block由于當(dāng)前對(duì)象有一個(gè)強(qiáng)引用,產(chǎn)生一個(gè)自循環(huán)引用,可以通過(guò)聲明為_(kāi)_weak 變量來(lái)進(jìn)行循環(huán)引用的消除
2、如果說(shuō)我們定義一個(gè)__blcok說(shuō)明符,也會(huì)產(chǎn)生循環(huán)引用,但是是區(qū)分場(chǎng)景的,一種是在arc下面是會(huì)產(chǎn)生循環(huán)引用的,而在mrc下面不會(huì).在arc下面可以通過(guò)斷環(huán)的方式去解除對(duì)應(yīng)的循環(huán)引用,但是有一個(gè)弊端色罚、如果block一直得不到調(diào)用,這個(gè)循環(huán)引用是沒(méi)有辦法解除的

怎么理解截獲變量的特性

1對(duì)于基本類型的局部變量,是對(duì)其值進(jìn)行截獲,
2對(duì)于對(duì)象類型的局部變量,是對(duì)其進(jìn)行強(qiáng)引用,連通全所有修飾符共同進(jìn)行截獲
3對(duì)于靜態(tài)的局部變量,是對(duì)其指針進(jìn)行截獲
4對(duì)于全局變量碰缔、局部、靜態(tài)全局變量不產(chǎn)生截獲

多線程

iOS 提供哪幾種多線程

1 GCD
2 NSOperation 網(wǎng)絡(luò)請(qǐng)求,圖片下載 ,可以進(jìn)行狀態(tài)改變
3 NSThread 可以實(shí)現(xiàn)常駐線程

GCD

同步/異步 和串行/并發(fā)

dispatch_barrier_async 異步柵欄調(diào)用 解決多讀單寫(xiě)的問(wèn)題


image.png

dispathc_group


7A9BF7F0-EA1C-472B-8826-660F1DB9A360.png

image.png

image.png

performSelector 方法調(diào)用必須保證當(dāng)前線程有runLoop,否則該方法會(huì)失效;

image.png

NSOperation 優(yōu)勢(shì)
添加任務(wù)依賴
任務(wù)執(zhí)行狀態(tài)控制
控制最大并發(fā)量


image.png

image.png

image.png

image.png

iOS 當(dāng)中都有哪些鎖

@synchronized 一般在創(chuàng)建單利對(duì)象的時(shí)候使用,保證在多線程環(huán)境中是唯一的

atomic 修飾屬性的關(guān)鍵字,對(duì)被修飾的對(duì)象進(jìn)行原子操作

OSSpinLock 自旋鎖,循環(huán)等待詢問(wèn),不釋放當(dāng)前資源,用于輕量級(jí)數(shù)據(jù)訪問(wèn),簡(jiǎn)單的int值 +1/-1操作

NSRecursiveLock 遞歸鎖 特點(diǎn)可以重入


image.png

NSLock 用于解決細(xì)密度的線程同步問(wèn)題,用于解決線程互斥和進(jìn)入自己的臨界區(qū)


image.png

dispatch_semaphore_t 信號(hào)量

runLoop

什么是runloop
RunLoop是通過(guò)內(nèi)部維護(hù)的事件循環(huán)來(lái)對(duì)事件/消息進(jìn)行管理的對(duì)象

沒(méi)有消息處理時(shí),休眠以避免資源占用
有消息處理時(shí)立刻被喚醒

在main函數(shù)中


image.png

image.png

滑動(dòng)tableview的時(shí)候我們的定時(shí)器還會(huì)生效嗎?

kcfRunLoopDefaultModel 滑動(dòng)tableView 會(huì)切換 UITrackingRunLoopMode 就不會(huì)生效了
解決方案,將Nstimer加入到CommonMode 中

RunLoop與線程關(guān)系
RunLoop與線程是一一對(duì)應(yīng)的

實(shí)現(xiàn)常駐線程

為當(dāng)前線程開(kāi)啟一個(gè)RunLoop
向該RunLoop中添加一個(gè)Port/Source等維持RunLoop的事件循環(huán)
啟動(dòng)該RunLoop

代碼實(shí)現(xiàn)


image.png

怎樣保證子線程數(shù)據(jù)來(lái)回更新UI的時(shí)候不打斷用戶滑動(dòng)操作?
用戶進(jìn)行滑動(dòng)的時(shí)候,runLoop在model 會(huì)被切換為 UITrackingRunLoopMode
網(wǎng)絡(luò)請(qǐng)求時(shí),是在子線程進(jìn)行操作,請(qǐng)求完成之后回來(lái)在主線程更新UI
在主線程邏輯進(jìn)行包裝,將他包裝在DefautModel下執(zhí)行.

HTTP 協(xié)議

get用于獲取資源,安全的,冪等的,可緩存

post 處理資源,非安全的,非冪等的,不可緩存

Http 無(wú)連接的,無(wú)狀態(tài)的

UDP 復(fù)用戳护、分用,差錯(cuò)檢驗(yàn)

image.png

DNS
域名到IP地址的映射,DNS解析請(qǐng)求采用UDP數(shù)據(jù)報(bào),且明文
DNS解析查詢方式,遞歸查詢,迭代查詢

DNS解析存在哪些常見(jiàn)問(wèn)題?

DNS劫持問(wèn)題:
DNS解析轉(zhuǎn)發(fā)問(wèn)題

DNS劫持與HTTP的關(guān)系是怎么樣的?
兩者之間是沒(méi)有關(guān)系的,第一解析是在客戶端本地的,是發(fā)生在與HTTP建立連接之前進(jìn)行的,2DNS解析請(qǐng)求使用UDP數(shù)據(jù)報(bào),端口號(hào)為53

DNS解析轉(zhuǎn)發(fā)

設(shè)計(jì)模式:6種

責(zé)任鏈:事件響應(yīng)機(jī)制

僑界模式
適配器模式
對(duì)象適配器和被適配器,

單例模式:

命令模式:行為參數(shù)化,降低代碼重合度

設(shè)計(jì)原則

image.png

單一職責(zé)原則:一個(gè)類只負(fù)責(zé)一件事,如:view 負(fù)責(zé)視圖展示,clayer 負(fù)責(zé)動(dòng)畫(huà)

開(kāi)關(guān)原則: 對(duì)修改關(guān)閉金抡、對(duì)擴(kuò)展開(kāi)放

接口隔離原則:使用多個(gè)專門(mén)的協(xié)議、而不是一個(gè)龐大臃腫的協(xié)議.例如:tableView ,數(shù)據(jù)返回和事件處理

依賴倒置原則:抽象不應(yīng)該依賴具體實(shí)現(xiàn),具體實(shí)現(xiàn)依賴抽象

里氏替換原則:父類可以被子類無(wú)縫替換,切原有的功能不受任何影響 例如:kvo

迪米特法制:一個(gè)對(duì)象應(yīng)當(dāng)對(duì)其他對(duì)象盡可能少的了解
高內(nèi)聚腌且、低耦合

文件緩存:
淘汰原則:1先進(jìn)先出,
LRU算法進(jìn)行淘汰,時(shí)間訪問(wèn)優(yōu)先選擇,訪問(wèn)頻率算法

網(wǎng)絡(luò)設(shè)計(jì)

網(wǎng)絡(luò)部分設(shè)計(jì)需要考慮哪些問(wèn)題?
圖片請(qǐng)求最大并發(fā)量,
請(qǐng)求超時(shí)策略:對(duì)一個(gè)數(shù)據(jù)進(jìn)行2次或者3次請(qǐng)求,失敗后,
請(qǐng)求優(yōu)先級(jí)

image.png
image.png

image.png

image.png

算法

鏈表反轉(zhuǎn)

//
//  ReversList.h
//  GCD
//
//  Created by 龔魁華 on 2020/4/23.
//  Copyright ? 2020 龔魁華. All rights reserved.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN
//定義一個(gè)鏈表
struct Node {
    int data;
    struct Node *next;
};

@interface ReversList : NSObject

//鏈表反轉(zhuǎn)
struct Node* reverseList(struct Node *head);
//構(gòu)造一個(gè)鏈表
struct Node* contructList(void);
//打印鏈表中的數(shù)據(jù)
void printList(struct Node *head);
@end

NS_ASSUME_NONNULL_END

//
//  ReversList.m
//  GCD
//
//  Created by 龔魁華 on 2020/4/23.
//  Copyright ? 2020 龔魁華. All rights reserved.
//

#import "ReversList.h"

@implementation ReversList

//鏈表反轉(zhuǎn)
struct Node* reverseList(struct Node *head){
    //定義遍歷指針,初始化為頭節(jié)點(diǎn)
    struct Node *p = head;
    //反轉(zhuǎn)后的鏈表頭部
    struct Node *newH = NULL;
    
    //遍歷鏈表
    while (p != NULL) {
        //記錄下一個(gè)結(jié)點(diǎn)
        struct Node *temp = p->next;
        //當(dāng)前結(jié)點(diǎn)的next指向鏈表頭部
        p->next = newH;
        //更改新鏈表頭部為當(dāng)前結(jié)點(diǎn)
        newH = p;
        //移動(dòng)p指針
        p = temp;
    }
    
    //返回反轉(zhuǎn)后的鏈表頭結(jié)點(diǎn)
    return newH;
}

//構(gòu)造一個(gè)鏈表
struct Node* contructList(void){
    //頭結(jié)點(diǎn)定義
    struct Node *head = NULL;
    //記錄當(dāng)前尾結(jié)點(diǎn)
    struct Node *cur = NULL;
    
    for (int i = 1; i < 5; i++) {
        struct Node *node = malloc(sizeof(struct Node));
        node->data = i;
        //頭結(jié)點(diǎn)為空,新結(jié)點(diǎn)即為頭結(jié)點(diǎn)
        if (head == NULL) {
            head = node;
        }
        //當(dāng)前結(jié)點(diǎn)的next為新結(jié)點(diǎn)
        else{
            cur->next = node;
        }
        //設(shè)置當(dāng)前結(jié)點(diǎn)為新結(jié)點(diǎn)
        cur = node;
    }
    return head;
}

//打印鏈表中的數(shù)據(jù)
void printList(struct Node *head){
    struct Node *temp = head;
    while (temp != NULL) {
        printf("node is %d\n",temp->data);
        temp = temp->next;
    }
}
@end

字符串交換

//字符串交換
void char_reverse(char *cha){
    //指向第一個(gè)字符
    char *begin = cha;
    char *end = cha + strlen(cha) -1;
    
    while (begin<end) {
        char temp = *begin;
        *(begin ++) = *end;
        *(end--) = temp;
    }
}

有序數(shù)組合并

/// 有序數(shù)組合并
/// @param a 第一個(gè)數(shù)組
/// @param aLen 數(shù)組長(zhǎng)度
/// @param b 第二個(gè)數(shù)組
/// @param bLen <#bLen description#>
/// @param result 合并后結(jié)果
void mergeList(int a[],int aLen,int b[],int bLen,int result[]){
    int p = 0;//遍歷數(shù)組a的指針
    int q = 0;//遍歷數(shù)組b的指針
    int i = 0;//記錄當(dāng)前存儲(chǔ)位置
    //任意數(shù)組沒(méi)有達(dá)到邊界則進(jìn)行遍歷
    while (p<aLen&&q<bLen) {
        //如果啊數(shù)組對(duì)應(yīng)位置的值小于b數(shù)組對(duì)應(yīng)位置的值
        if (a[p] <= b[q]) {
            //存儲(chǔ)a數(shù)組的值
            result[i] = a[p];
            //移動(dòng)a數(shù)組的遍歷指針
            p++;
        }else{
            //存儲(chǔ)b數(shù)組的值
            result[i] = b[q];
            q++;
        }
        //指向合并結(jié)果的下一個(gè)存儲(chǔ)位置
        i++;
    }
    //如果a數(shù)組有剩余
    while (p < aLen) {
        //將a數(shù)組剩余部分拼接到合并結(jié)果的后面
        result[i] = a[p++];
        i++;
    }
    
    //如果b數(shù)組有剩余
    while (q < bLen) {
        //將b數(shù)組剩余部分拼接到合并結(jié)果的后面
        result[i] = b[q++];
        i++;
    }
    
}

尋找2個(gè)view的共同父視圖

    - (NSArray <UIView *> *)finCommonSuperView:(UIView *)viewOne other:(UIView *)viewOther{
    NSMutableArray *result = [NSMutableArray array];
    //查找第一個(gè)父視圖的所有父視圖
    NSArray *arrayOne = [self findSuperViews:viewOne];
    //查找第二個(gè)父視圖的所有父視圖
    NSArray *arrayOther = [self findSuperViews:viewOther];
    int i = 0;
    //越界限制條件
    while (i<MIN(arrayOne.count, arrayOther.count)) {
        //倒序方式獲取各個(gè)視圖的父視圖
        UIView *superOne = [arrayOne objectAtIndex:arrayOne.count -i -1];
        UIView *superOther = [arrayOther objectAtIndex:arrayOther.count -i -1];
        //比較如果相等,則為共同父視圖
        if (superOne == superOther) {
            [result addObject:superOne];
            i++;
        }
        //如果不相等,則結(jié)束遍歷
        else{
            break;
        }
    }
    return result;
}

- (NSArray <UIView *> *)findSuperViews:(UIView *)view{
    //初始化為第一父視圖
    UIView *temp = view.superview;
    //保存結(jié)果數(shù)組
    NSMutableArray *result = [NSMutableArray array];
    while (temp) {
        [result addObject:temp];
        //順著superview指針一直向上查找
        temp = temp.superview;
    }
    return result;
}

無(wú)序數(shù)組中位數(shù)查找

int findMedian(int a[],int aLen){
    int low = 0;
    int high = aLen -1;
    int mid = (aLen - 1)/2;
    int div = PartSort(a,low,high);
    while (div != mid) {
        if (mid < div) {
            //左半?yún)^(qū)間查找
            div = PartSort(a,low,div - 1);
        }else{
            //右半?yún)^(qū)間查找
             div = PartSort(a,div+1,high);
        }
    }
    //找到了
    return a[mid];
}

int PartSort(int a[], int start,int end){
    int low = start;
    int high = end;
    //選取關(guān)鍵字
    int key = a[end];
    while (low<high) {
        //左邊找比key大的值
        while (low<high && a[low] <= key) {
            ++low;
        }
        //右邊著比key小的值
        while (low<high&&a[high]>=key) {
            --high;
        }
        if (low<high) {
            //找到之后交換左右的值
            int temp = a[low];
            a[low] = a[high];
            a[high] = temp;
        }
    }
    int temp = a[high];
    a[high] = a[end];
    a[end] = temp;
    return low;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末梗肝,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子铺董,更是在濱河造成了極大的恐慌巫击,老刑警劉巖,帶你破解...
    沈念sama閱讀 223,207評(píng)論 6 521
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件精续,死亡現(xiàn)場(chǎng)離奇詭異喘鸟,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)驻右,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,455評(píng)論 3 400
  • 文/潘曉璐 我一進(jìn)店門(mén)什黑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人堪夭,你說(shuō)我怎么就攤上這事愕把。” “怎么了森爽?”我有些...
    開(kāi)封第一講書(shū)人閱讀 170,031評(píng)論 0 366
  • 文/不壞的土叔 我叫張陵恨豁,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我爬迟,道長(zhǎng)橘蜜,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,334評(píng)論 1 300
  • 正文 為了忘掉前任付呕,我火速辦了婚禮计福,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘徽职。我一直安慰自己象颖,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,322評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布姆钉。 她就那樣靜靜地躺著说订,像睡著了一般抄瓦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上陶冷,一...
    開(kāi)封第一講書(shū)人閱讀 52,895評(píng)論 1 314
  • 那天钙姊,我揣著相機(jī)與錄音,去河邊找鬼埂伦。 笑死煞额,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的赤屋。 我是一名探鬼主播立镶,決...
    沈念sama閱讀 41,300評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼类早!你這毒婦竟也來(lái)了媚媒?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 40,264評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤涩僻,失蹤者是張志新(化名)和其女友劉穎缭召,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體逆日,經(jīng)...
    沈念sama閱讀 46,784評(píng)論 1 321
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嵌巷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,870評(píng)論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了室抽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片搪哪。...
    茶點(diǎn)故事閱讀 40,989評(píng)論 1 354
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖坪圾,靈堂內(nèi)的尸體忽然破棺而出晓折,到底是詐尸還是另有隱情,我是刑警寧澤兽泄,帶...
    沈念sama閱讀 36,649評(píng)論 5 351
  • 正文 年R本政府宣布漓概,位于F島的核電站,受9級(jí)特大地震影響病梢,放射性物質(zhì)發(fā)生泄漏胃珍。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,331評(píng)論 3 336
  • 文/蒙蒙 一蜓陌、第九天 我趴在偏房一處隱蔽的房頂上張望觅彰。 院中可真熱鬧,春花似錦护奈、人聲如沸缔莲。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,814評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)痴奏。三九已至,卻和暖如春厌秒,著一層夾襖步出監(jiān)牢的瞬間读拆,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,940評(píng)論 1 275
  • 我被黑心中介騙來(lái)泰國(guó)打工鸵闪, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留檐晕,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,452評(píng)論 3 379
  • 正文 我出身青樓蚌讼,卻偏偏與公主長(zhǎng)得像辟灰,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子篡石,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,995評(píng)論 2 361