iOS面試了20幾家總結(jié)出來(lái)的面試題(下)

27. SDWebImage是怎么做緩存的?

  • 首先說(shuō),緩存采用了二級(jí) 緩存策略。 圖片緩存的時(shí)候, 在內(nèi)存有緩存, 在磁盤(pán)中也有緩存, 其中內(nèi)存緩存是用NSCache做的 (下面會(huì)有NSCache的說(shuō)明)。

一、如何做緩存的步驟: 0、下載圖片 1、將圖片緩存在內(nèi)存中 2、判斷圖片的格式png或jpeg,將圖片轉(zhuǎn)成NSData數(shù)據(jù) 3、獲取圖片的存儲(chǔ)路徑, 其中圖片的文件名是通過(guò)傳入Key經(jīng)過(guò)MD5加密后獲得的 4、將圖片存在進(jìn)磁盤(pán)中。

二、如何獲取圖片的? 1、在內(nèi)存緩存中找 2、如果內(nèi)存中找不到, 會(huì)去默認(rèn)磁盤(pán)目錄中尋找, 如果找不到,在去自定義磁盤(pán)目錄中尋找 3、如果磁盤(pán)也找不到就會(huì)下載圖片 4、獲取圖片數(shù)據(jù)之后, 將圖片數(shù)據(jù)從NSData轉(zhuǎn)化UIImage。其中轉(zhuǎn)化根據(jù)圖片的類(lèi)型進(jìn)行轉(zhuǎn)化 5、默認(rèn)對(duì)圖片進(jìn)行解壓縮,生成位圖圖片 6、將位圖圖片返回

三、圖片是如何被解壓縮的? 1、判斷圖片是否是動(dòng)態(tài)圖片,如果是,不能解壓縮 2、判斷圖片是否透明,如果是,不能解壓縮 3、判斷圖片的顏色空間是不是RGB如果不是、不能解壓縮 4、根據(jù)圖片的大小創(chuàng)建一個(gè)上下文 5、將圖片繪制在上下文中 6、從上下文中讀取一個(gè)不透明的位圖圖像,該圖像就是解壓縮后的圖像 7、將位圖圖像返回

如果你正在面試,或者正準(zhǔn)備跳槽,不妨看看我精心總結(jié)的iOS大廠(chǎng)面試資料https://gitee.com/Mcci7/i-oser 來(lái)獲取一份詳細(xì)的大廠(chǎng)面試資料 為你的跳槽加薪多一份保障

接上說(shuō) NSCache

  • 這個(gè)NSCache說(shuō)白了就是做緩存專(zhuān)用的一個(gè)系統(tǒng)類(lèi)
  • 類(lèi)似可變字典一樣,但是NSCache是線(xiàn)程安全的, 系統(tǒng)類(lèi)自動(dòng)做好了加鎖和釋放鎖等一系列的操作, 還有一個(gè)重要的是如果內(nèi)存不足的時(shí)候NSCache會(huì)自動(dòng)釋放掉存儲(chǔ)的對(duì)象,不需要開(kāi)發(fā)者手動(dòng)干預(yù)。
  • 來(lái)看一眼NSCache提供的屬性和相關(guān)方法
//名稱(chēng)
@property (copy) NSString *name;

//NSCacheDelegate代理
@property (nullable, assign) id<NSCacheDelegate> delegate;

//通過(guò)key獲取value,類(lèi)似于字典中通過(guò)key取value的操作
- (nullable ObjectType)objectForKey:(KeyType)key;

//設(shè)置key、value
- (void)setObject:(ObjectType)obj forKey:(KeyType)key; // 0 cost

/*
設(shè)置key、value
cost表示obj這個(gè)value對(duì)象的占用的消耗?可以自行設(shè)置每個(gè)需要添加進(jìn)緩存的對(duì)象的cost值
這個(gè)值與后面的totalCostLimit對(duì)應(yīng),如果添加進(jìn)緩存的cost總值大于totalCostLimit就會(huì)自動(dòng)進(jìn)行刪除
感覺(jué)在實(shí)際開(kāi)發(fā)中直接使用setObject:forKey:方法就可以解決問(wèn)題了
*/
- (void)setObject:(ObjectType)obj forKey:(KeyType)key cost:(NSUInteger)g;

//根據(jù)key刪除value對(duì)象
- (void)removeObjectForKey:(KeyType)key;

//刪除保存的所有的key-value
- (void)removeAllObjects;

/*
當(dāng)NSCache緩存的對(duì)象的總cost值大于這個(gè)值則會(huì)自動(dòng)釋放一部分對(duì)象直到占用小于該值
非嚴(yán)格限制意味著如果保存的對(duì)象超出這個(gè)大小也不一定會(huì)被刪除
這個(gè)值就是與前面setObject:forKey:cost:方法對(duì)應(yīng)
*/
@property NSUInteger totalCostLimit;    // limits are imprecise/not strict

/*
緩存能夠保存的key-value個(gè)數(shù)的最大數(shù)量
當(dāng)保存的數(shù)量大于該值就會(huì)被自動(dòng)釋放
非嚴(yán)格限制意味著如果超出了這個(gè)數(shù)量也不一定會(huì)被刪除
*/
@property NSUInteger countLimit;    // limits are imprecise/not strict
/*
這個(gè)值與NSDiscardableContent協(xié)議有關(guān),默認(rèn)為YES
當(dāng)一個(gè)類(lèi)實(shí)現(xiàn)了該協(xié)議,并且這個(gè)類(lèi)的對(duì)象不再被使用時(shí)意味著可以被釋放
*/
@property BOOL evictsObjectsWithDiscardedContent;

@end

//NSCacheDelegate協(xié)議
@protocol NSCacheDelegate <NSObject>
@optional
//上述協(xié)議只有這一個(gè)方法,緩存中的一個(gè)對(duì)象即將被刪除時(shí)被回調(diào)
- (void)cache:(NSCache *)cache willEvictObject:(id)obj;
@end**
復(fù)制代碼

countLimit注意一下這個(gè)屬性, 這個(gè)屬性就是設(shè)置最大緩存數(shù)量,啥意思呢? 這玩意就和棧差不多, 先進(jìn)先出(叫什么FIFO?)原則。比如你countLimit設(shè)置為5 那么當(dāng)你緩存第6個(gè)對(duì)象的時(shí)候, 原本第一個(gè)就被移除了。 所以這便就有有一個(gè)風(fēng)險(xiǎn),也可能會(huì)是面試點(diǎn),為什么,通過(guò)key去取值的時(shí)候,一定要判斷一個(gè)獲取的對(duì)象是否為nil?答:就因?yàn)楹苡锌赡苣承?duì)象被釋放(頂)掉了。

又又又可能出現(xiàn)的面試題!NSCache里面緩存的對(duì)象,在什么場(chǎng)景下會(huì)被釋放?

如果你正在面試,或者正準(zhǔn)備跳槽,不妨看看我精心總結(jié)的iOS大廠(chǎng)面試資料https://gitee.com/Mcci7/i-oser 來(lái)獲取一份詳細(xì)的大廠(chǎng)面試資料 為你的跳槽加薪多一份保障

  • 回答之前,先說(shuō)一情況,在某C中創(chuàng)建了NSCache對(duì)象,點(diǎn)擊手機(jī)的Home或者任何方式進(jìn)入后臺(tái),會(huì)發(fā)現(xiàn)NSCache中的代理方法被執(zhí)行了,于是NSCache對(duì)象會(huì)釋放掉所有對(duì)象,還有的是,如果發(fā)生內(nèi)存警告也會(huì)釋放掉所有對(duì)象。所以, 這道題應(yīng)該如下這么回答!
  • NSCache自身釋放了,其中存儲(chǔ)的對(duì)象也就釋放了。
  • 手動(dòng)調(diào)用釋放方法removeObjectForKey、removeAllObjects
  • 緩存對(duì)象個(gè)數(shù)大于countLimit
  • 緩存總消耗大于totalCostLimit
  • 程序進(jìn)入后臺(tái)
  • 收到內(nèi)存警告

28.SDWebImage實(shí)現(xiàn)原理是什么? 它是如何解決tableView的復(fù)用時(shí)出現(xiàn)圖片錯(cuò)亂問(wèn)題的呢

  • 原理如上,
  • 錯(cuò)亂是在UIImageView+WebCache文件中這個(gè)方法每次都會(huì)調(diào)用 [self sd_cancelCurrentImageLoad];

29. 為什么刷新UI要在主線(xiàn)程操作

  • UIKit并不是一個(gè)線(xiàn)程安全的類(lèi),所以涉及多個(gè)線(xiàn)程同時(shí)對(duì)UI進(jìn)行操作會(huì)造成影響。

  • 為什么不把UIKit框架設(shè)置為線(xiàn)程安全呢?

  • 因?yàn)榫€(xiàn)程安全需要加鎖,我們都知道加鎖就會(huì)消耗性能,影響處理速度,影響渲染速度,我們通常自己在寫(xiě)@property時(shí)都會(huì)寫(xiě)nonatomic來(lái)追求高性能高效率。

  • 假設(shè)能夠異步設(shè)置view的屬性,那我們究竟是希望這些改動(dòng)能夠同時(shí)生效,還是按照各自runloop的進(jìn)度去改變這個(gè)view的屬性呢?

  • 假設(shè)UITableView在其他線(xiàn)程去移除了一個(gè)cell,而在另一個(gè)線(xiàn)程卻對(duì)這個(gè)cell所在的index進(jìn)行一些操作,這時(shí)候可能就會(huì)引發(fā)crash。

  • 如果在后臺(tái)線(xiàn)程移除了一個(gè)view,這個(gè)時(shí)候runloop周期還沒(méi)有完結(jié),用戶(hù)在主線(xiàn)程點(diǎn)擊了這個(gè)“將要”消失的view,那么究竟該不該響應(yīng)事件?在哪條線(xiàn)程進(jìn)行響應(yīng)?

  • 在Cocoa Touch框架中,UIApplication初始化工作是在主線(xiàn)程進(jìn)行的。而界面上所有的視圖都是在UIApplication 實(shí)例的葉子節(jié)點(diǎn)(內(nèi)存管理角度),所以所有的手勢(shì)交互操作都是在主線(xiàn)程上才能響應(yīng)

30. RunTime

類(lèi)的結(jié)構(gòu)體:

//Class也表示一個(gè)結(jié)構(gòu)體指針的類(lèi)型
typedef struct objc_class *Class;

struct objc_class {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class _Nullable super_class                              OBJC2_UNAVAILABLE;
    const char * _Nonnull name                               OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;
    struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;
    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;
復(fù)制代碼

分類(lèi)結(jié)構(gòu)體

struct category_t {
    const char *name;
    classref_t cls;
    struct method_list_t *instanceMethods; // 對(duì)象方法
    struct method_list_t *classMethods; // 類(lèi)方法
    struct protocol_list_t *protocols; // 協(xié)議
    struct property_list_t *instanceProperties; // 屬性
    // Fields below this point are not always present on disk.
    struct property_list_t *_classProperties;

    method_list_t *methodsForMeta(bool isMeta) {
        if (isMeta) return classMethods;
        else return instanceMethods;
    }

    property_list_t *propertiesForMeta(bool isMeta, struct header_info *hi);
};
復(fù)制代碼

引申1. class_copyIvarList與class_copyPropertyList的區(qū)別?

  • 1.class_copyIvarList:能夠獲取.h和.m中的所有屬性以及大括號(hào)中聲明的變量,獲取的屬性名稱(chēng)有下劃線(xiàn)(大括號(hào)中的除外)。
  • 2.class_copyPropertyList:只能獲取由property聲明的屬性,包括.m中的,獲取的屬性名稱(chēng)不帶下劃線(xiàn)。

引申2. class_ro_t和class_rw_t的區(qū)別?

  • class_rw_t提供了運(yùn)行時(shí)對(duì)類(lèi)拓展的能力,
  • class_ro_t存儲(chǔ)的大多是類(lèi)在編譯時(shí)就已經(jīng)確定的信息。
  • 二者都存有類(lèi)的方法、屬性(成員變量)、協(xié)議等信息,不過(guò)存儲(chǔ)它們的列表實(shí)現(xiàn)方式不同。簡(jiǎn)單的說(shuō)class_rw_t存儲(chǔ)列表使用的二維數(shù)組,class_ro_t使用的一維數(shù)組。
  • class_ro_t存儲(chǔ)于class_rw_t結(jié)構(gòu)體中,是不可改變的。保存著類(lèi)的在編譯時(shí)就已經(jīng)確定的信息。
  • 運(yùn)行時(shí)修改類(lèi)的方法,屬性,協(xié)議等都存儲(chǔ)于class_rw_t中

31. NSNotification

  • NSNotificationCent 子線(xiàn)程中發(fā)出通知,也要在主線(xiàn)程中刷新UI
// 比如
   dispatch_async(dispatch_get_main_queue(), ^{
       // 刷新UI
   });
復(fù)制代碼
  • NSNotificationCenter用完之后不移除, 會(huì)崩潰么?
  • 有時(shí)候會(huì)導(dǎo)致crash。比如在通知事件中處理數(shù)據(jù)或者UI事件,但是由于通知的不確定性造成事件的不確定,有異步操作在通知事件中處理等都可能造成崩潰。
  • 而且通知的崩潰很難檢測(cè)。

32. 什么情況使用 weak 關(guān)鍵字,相比 assign 有什么不同?(輪回系列)

  • weak 這個(gè)詞兒解決了一件事情,就是內(nèi)存的事情
  • 在ARC中weak的出現(xiàn)解決了一些循環(huán)引用的問(wèn)題, 比如delegate, xib連線(xiàn)出來(lái)的控件一般也是weak(也可以用strong )
  • weak表明了一種“非擁有的關(guān)系”,不保留新值,也不釋放舊值。
  • assign也是如此,但常用的assign一般用于基本數(shù)據(jù)類(lèi)型(CGFloat 或 NSlnteger等)
  • assign可以用于非OC對(duì)象,也可以用于OC對(duì)象(MRC時(shí)代使用), 但是weak必須用在OC對(duì)象。

引申 1.關(guān)鍵字copy 的用法?

  • block用Copy是MRC時(shí)代留下來(lái)的傳統(tǒng)。在MRC中方法內(nèi)部的block是在棧區(qū)的, 使用copy可以把它放到堆區(qū)。 在ARC中寫(xiě)不寫(xiě)都行,用Strong也是可以的。
  • NSString、NSArray、NSDictionary也經(jīng)常使用copy, 因?yàn)槔锩嬗袑?duì)應(yīng)的可變的子類(lèi)型,為了確保安全性, 建議使用copy修飾

引申 2.@property 的本質(zhì)是什么?ivar、getter、setter 是如何生成并添加到這個(gè)類(lèi)中的。

  • @property = ivar(實(shí)例變量) + getter + setter
  • 自動(dòng)合成

33. 說(shuō)說(shuō)內(nèi)存管理?

  • 其實(shí)遇到這道題,挺糾結(jié)的,有些TMD面試官就是習(xí)慣搞人,從這個(gè)玩意里面 能往死給你嗑! 你要看過(guò)相關(guān)內(nèi)存管理的詳細(xì)原理,你會(huì)發(fā)現(xiàn)這里面的C++操作很多,沒(méi)學(xué)過(guò)C++的人能看個(gè)八九不離十,可是也只是能說(shuō)個(gè)大其概,但是內(nèi)部細(xì)節(jié)還是得用C++來(lái)說(shuō),廢話(huà)不多說(shuō), 直接上說(shuō)所謂得面試答案。
  • 粗糙版本這么回答,
  • 版本一: 內(nèi)存中每一個(gè)對(duì)象都有一個(gè)屬于自己的引用計(jì)數(shù)器。當(dāng)某個(gè)對(duì)象A被另一個(gè)對(duì)象引用時(shí),A的引用計(jì)數(shù)器就+1,如果再有一個(gè)對(duì)象引用到A,那么A的引用計(jì)數(shù)器就再+1。當(dāng)其中某個(gè)對(duì)象不再引用A了,A的引用計(jì)數(shù)器會(huì)-1。直到A的引用計(jì)數(shù)減到了0,那么就沒(méi)有人再需要它了,就是時(shí)候把它釋放掉了
  • 版本二:對(duì)象通過(guò) alloc copy new 生成得得對(duì)象在MRC年代需要手動(dòng)管理內(nèi)存, 利用得技術(shù)是returnCount引用計(jì)數(shù)器,來(lái)管理對(duì)象得釋放時(shí)機(jī),alloc創(chuàng)建對(duì)象引用計(jì)數(shù)器 + 1, retain持有關(guān)系 引用計(jì)數(shù)器 +1,release 引用計(jì)數(shù)器 - 1。 如果當(dāng)前對(duì)象得returnCount = 0 對(duì)象就會(huì)被在dealloc方法里面適當(dāng)時(shí)機(jī)進(jìn)行釋放(啥時(shí)候釋放?)如果當(dāng)前returnCount大于0得時(shí)候,就會(huì)一直被持有。
  • 稍微詳細(xì)版本的,首先當(dāng) alloc copy new 生成得對(duì)象里面 在內(nèi)部底層源碼也同時(shí)和當(dāng)前對(duì)象相關(guān)聯(lián)得SideTable, 其內(nèi)部有三個(gè)屬性, 一個(gè)是一把自旋鎖,一個(gè)是引用計(jì)數(shù)器相關(guān),一個(gè)是維護(hù)weak生命得屬性得表, 其中retain、release 對(duì)利用鍵值對(duì)會(huì)對(duì)當(dāng)前對(duì)象得引用計(jì)數(shù)器進(jìn)行加減操作(位移),如果當(dāng)前引用計(jì)數(shù)器為0得時(shí)候,其dealloc內(nèi)部會(huì)刪除當(dāng)前的引用計(jì)數(shù)器,并且釋放當(dāng)前對(duì)象。
  • 詳情請(qǐng)查看www.itdecent.cn/p/ef6d9bf8f…

雜項(xiàng)

  • 1、imageName與imageWithContentsOfFile區(qū)別?
  • imageWithContentsOfFile: 加載本地目錄圖片,并不會(huì)緩存,占用內(nèi)存小, 不能加載image.xcassets里面的圖片資源。 相同的圖片會(huì)被重復(fù)加載到內(nèi)存中
  • imageName:加載到內(nèi)存中, 會(huì)緩存起來(lái), 占用內(nèi)存較大,相同的圖片不會(huì)被重復(fù)加載到內(nèi)存當(dāng)中,會(huì)讀取image.xcassets的圖片圖片資源。

使用 imageNamed 創(chuàng)建的 UIImage 會(huì)被立即加入到 NSCache 中(解碼后的 Image Buffer),直到收到內(nèi)存警告的時(shí)候才會(huì)釋放不使用的 UIImage。而 imageWithContentsOfFile 會(huì)每次重新申請(qǐng)內(nèi)存,相同圖片不會(huì)緩存,所以 xcassets 內(nèi)的

  • 如果不斷重復(fù)讀取同一個(gè)圖片,則使用imageName

  • 如果不需要重復(fù)讀取同一個(gè)圖片,并且需要低內(nèi)存,則使用imageWithContentsOfFile

  • 2.IBOutlet連出來(lái)的視圖屬性為什么可以被設(shè)置成weak?

  • 因?yàn)殒溄又甔code 內(nèi)部把鏈接的控件 放進(jìn)了一個(gè)_topLevelObjectsToKeepAliveFromStoryboard的私有數(shù)組中,這個(gè)數(shù)組強(qiáng)引用這所有top level的對(duì)象 所以用weak也無(wú)傷大雅。

    1. id 為什么不能用點(diǎn)語(yǔ)法?
  • 點(diǎn)語(yǔ)法就是setter和getter方法, 然而id類(lèi) 無(wú)法確定所指的類(lèi)是什么類(lèi)型, 尋不到setter個(gè)getter方法,id類(lèi)型的對(duì)象 只能用【】方法調(diào)用方法

  • 4.id和NSObject的區(qū)別?

    • id是struct objc_object結(jié)構(gòu)體指針,可以指向任何OC對(duì)象,當(dāng)然不包括NSInteger等類(lèi)型,因?yàn)檫@些數(shù)據(jù)類(lèi)型不是OC對(duì)象。
  • 另外OC的基類(lèi)不止有NSObject一個(gè),還有個(gè)NSProxy虛類(lèi)。所以說(shuō)id類(lèi)型和NSObject并不是等價(jià)的。

  • 5 . OC中 Null 與 nil的區(qū)別

    • NULL是指指針是空值,用來(lái)判斷C 指針;
    • nil是指一個(gè)OC對(duì)象(指針)為空;
    • Nil是指一個(gè)OC類(lèi)為空;
    • NSNull則用于填充集合元素;這個(gè)類(lèi)只有一個(gè)方法null,并且是單例的;
  • 6 . 自旋鎖和互斥鎖

  • 相同點(diǎn):都能保證同一時(shí)間只有一個(gè)線(xiàn)程訪(fǎng)問(wèn)共享資源,都能保證系統(tǒng)安全

  • 不同點(diǎn):

互斥鎖:如果共享數(shù)據(jù)已經(jīng)有了其他線(xiàn)程加鎖了,線(xiàn)程會(huì)進(jìn)行休眠狀態(tài)等待鎖,一旦被訪(fǎng)問(wèn)的資源被解鎖,則等待資源的線(xiàn)程會(huì)被喚醒。信號(hào)量dispatch_semaphore 為互斥鎖   @synchronized是NSLock的封裝 屬于互斥鎖  互斥鎖一般用于等待時(shí)間較長(zhǎng)的情況
**適用于**:線(xiàn)程等待鎖的時(shí)間較長(zhǎng)

自旋鎖:如果共享數(shù)據(jù)已經(jīng)有其他線(xiàn)程加鎖了,線(xiàn)程會(huì)以死循環(huán)的方式等待鎖,一旦被訪(fǎng)問(wèn)的資源被解鎖,則等待資源的線(xiàn)程會(huì)立即執(zhí)行。OSSpinLock 屬于自旋鎖   自旋鎖一般用于時(shí)間較短的情況,OSSpinLock
**適用于**:線(xiàn)程等待鎖的時(shí)間較端
復(fù)制代碼
  • 7 . 進(jìn)程和線(xiàn)程的區(qū)別

  • 進(jìn)程是指在系統(tǒng)中正在運(yùn)行的一個(gè)應(yīng)用程序

  • 線(xiàn)程是進(jìn)程中的一個(gè)實(shí)體,一個(gè)進(jìn)程想要執(zhí)行任務(wù), 必須至少有一條線(xiàn)程,應(yīng)程序啟動(dòng)的時(shí)候會(huì)默認(rèn)開(kāi)啟一條線(xiàn)程,也就是主線(xiàn)程

  • 一個(gè)進(jìn)程擁有多個(gè)線(xiàn)程

  • 8 LayoutSubviews和drawRect調(diào)用時(shí)機(jī)

LayoutSubviews調(diào)用時(shí)機(jī)

  • init初始化不會(huì)調(diào)用LayoutSubviews方法
  • addsubView 時(shí)候會(huì)調(diào)用
  • 改變一個(gè)View的frame的時(shí)候調(diào)用
  • 滾動(dòng)UIScrollView導(dǎo)致UIView重新布局的時(shí)候會(huì)調(diào)用
  • 手動(dòng)調(diào)用setNeedsLayout或者layoutIfNeeded

drawRect調(diào)用時(shí)機(jī)

  • drawRect 掉用是在Controller->loadView, Controller->viewDidLoad 兩方法之后掉用的.所以不用擔(dān)心在 控制器中,這些View的drawRect就開(kāi)始畫(huà)了.、

  • 9 cocoaPods里面pod install和update的區(qū)別?

**pod install **

  • 一般是第一次想要為項(xiàng)目添加pod的時(shí)候使用的,當(dāng)然也可以在添加和移除庫(kù)使用
  • 每次pod install的時(shí)候,pod install 回為每一個(gè)安裝的pod庫(kù)在Podfile.lock文件中寫(xiě)入其版本號(hào),并且鎖定當(dāng)前版本號(hào)。
  • 如果pod install的時(shí)候,不會(huì)更新其版本庫(kù),而是去下載新的或者移除當(dāng)前版本

pod update

  • 當(dāng)執(zhí)行了pod update的時(shí)候,cocoaPods不會(huì)考慮Podfile.lock中的版本。直接去更新當(dāng)前所有的庫(kù)到最新,然后Podfile.lock會(huì)更新這一次的版本號(hào)。
  • 10 frame和masonry哪個(gè)性能好?為什么
  • 有的相對(duì)布局最終都會(huì)轉(zhuǎn)換成Frame絕對(duì)布局 中間多了一層轉(zhuǎn)換的操作

  • 11 . iOS從iOS9 - 13的特性

iOS9

從HTTP升級(jí)到HTTPS App瘦身 下面有講 這里不贅述( App瘦身 ) 新增UIStackView

iOS10

新增通知推送相關(guān)的操作。自定義通知彈窗,自定義通知類(lèi)型(地理位置,時(shí)間間隔,日歷等)

iOS11

無(wú)線(xiàn) 調(diào)試

齊劉海兒,導(dǎo)航條,安全距離等

iOS12

啟動(dòng)速度優(yōu)化

    應(yīng)用啟動(dòng)速度提升40%
    鍵盤(pán)響應(yīng)速度提升50%
    相機(jī)啟動(dòng)速度提升70%

復(fù)制代碼

iOS13

黑暗模式 詳情請(qǐng)查閱 www.itdecent.cn/p/0da3b107f…


二、App包以及啟動(dòng)過(guò)程

App瘦身

1、App如何瘦身?

  • 刪除陳舊代碼、刪除陳舊xib/sb,刪除無(wú)用的圖片資源(檢測(cè)未使用圖片的工具LSUnusedResources
  • 無(wú)損壓縮圖片,本地音視頻壓縮。以直接減少圖片大小
  • 使用webP格式的圖片(加載速度比較慢,但可以達(dá)到瘦身的效果)
  • 減小類(lèi)名稱(chēng)的長(zhǎng)度(高性能的話(huà)可以試一試)
  • 減少使用靜態(tài)庫(kù)
  • 一些主題類(lèi)的東西提供下載功能,不直接打包在應(yīng)用包里面,按需加載資源
  • iOS9 之后的新特性 應(yīng)用程序切片(App Slicing)、中間代碼(Bitcode)和按需加載資源(On Demand Resources)

Slicing: 這個(gè)過(guò)程是iOS9出來(lái)之后 不需要程序員干預(yù)的一個(gè)瘦身的過(guò)程,簡(jiǎn)單來(lái)說(shuō)就是我們?cè)偕蟼鱅PA包到iTunes Connect,然后AppStore會(huì)對(duì)app進(jìn)行切片,切成特定的機(jī)型想要的數(shù)據(jù),比如@3x給max用,@2x就自動(dòng)剔除了。 是一個(gè)自動(dòng)的過(guò)程、 Bitcode:是一種中間碼,如果配置了Bitcode(Xcode7以后默認(rèn)開(kāi)啟)的程序會(huì)在App Store Connect上被重新編譯等一系列操作,進(jìn)而蘋(píng)果內(nèi)部會(huì)對(duì)可執(zhí)行文件進(jìn)行優(yōu)化,也就是說(shuō)不需要我們干預(yù)什么東西,也操作不了, 如果后面蘋(píng)果有更牛逼的優(yōu)化操作,也是蘋(píng)果的事情, 跟我們個(gè)人開(kāi)發(fā)者一毛錢(qián)關(guān)系沒(méi)有。 On Demand Resources 按需加載, 是程序員自己手動(dòng)操作,說(shuō)白了就是在用的時(shí)候去下載某些資源, 但是我們自己在配置的時(shí)候都需要配置,要額外寫(xiě)一些代碼啥的,等我們提交到市場(chǎng)的時(shí)候, 蘋(píng)果內(nèi)部會(huì)把我們按需加載的資源從包里面做了一些抽離操作啥的, 讓我們的包在下載的時(shí)候更小,舉個(gè)例子,就是吃雞里面沙漠地圖如果玩家不自己下載, 就玩不了沙漠。

on-demond resource(ODR)具體請(qǐng)查看原理版本:www.itdecent.cn/p/bacedd8a3…

或者詳細(xì)使用版本:www.cocoachina.com/articles/12…

關(guān)于 slicing, bitcode, on-demond resource(ODR)的參考資源blog.csdn.net/zhuod/artic…


2、app啟動(dòng)時(shí)候都經(jīng)歷了什么?

啟動(dòng)分為兩種。 一種是之前啟動(dòng)過(guò),按了一下home鍵,然后再點(diǎn)啟動(dòng),這個(gè)啟動(dòng)叫熱啟動(dòng),另外就是第一次啟動(dòng)app,或者啟動(dòng)殺死之后的app 叫做冷啟動(dòng)

根據(jù)info.plist里面的設(shè)置加載,建立沙箱,權(quán)限檢查等

加載可執(zhí)行文件 加載動(dòng)態(tài)庫(kù) objc運(yùn)行時(shí)的初始化處理(類(lèi)的注冊(cè),category注冊(cè),selector唯一性檢查等等) 初始化,包括+load方法 執(zhí)行main函數(shù) Application 初始化,到 applicationDidFinishLaunchingWithOptions 執(zhí)行完 渲染屏幕,到viewDidAppear 執(zhí)行完畢,展現(xiàn)給用戶(hù)

  • mian之前

根據(jù)info.plist里面的設(shè)置加載,建立沙箱,權(quán)限檢查等

加載可執(zhí)行文件 加載動(dòng)態(tài)庫(kù) objc運(yùn)行時(shí)的初始化處理(類(lèi)的注冊(cè),category注冊(cè),selector唯一性檢查等等) 初始化,包括+load方法

  • mian之后
    • 如圖
    • 加載流程如下:
      圖丟了?。。。?!百度去吧!

3、優(yōu)化啟動(dòng)時(shí)間

  • 啟動(dòng)時(shí)間是用戶(hù)點(diǎn)擊App圖標(biāo),到第一個(gè)界面展示的時(shí)間。

注意:?jiǎn)?dòng)時(shí)間在小于400ms是最佳的,因?yàn)閺狞c(diǎn)擊圖標(biāo)到顯示Launch Screen,到Launch Screen消失這段時(shí)間是400ms。啟動(dòng)時(shí)間不可以大于20s,否則會(huì)被系統(tǒng)殺掉。

  • 以main函數(shù)作為分水嶺,啟動(dòng)時(shí)間其實(shí)包括了兩部分:
    • main函數(shù)之前(分析并加載動(dòng)態(tài)庫(kù),注冊(cè)需要的類(lèi)(包括系統(tǒng)的類(lèi)),Category中的方法也會(huì)注冊(cè)到對(duì)用的類(lèi)中,執(zhí)行必要的初始化方法( +load方法)等等
    • main函數(shù)到第一個(gè)界面的viewDidAppear:。
  • 所以,優(yōu)化也是從兩個(gè)方面進(jìn)行的,個(gè)人建議優(yōu)先優(yōu)化后者,因?yàn)榻^大多數(shù)App的瓶頸在自己的代碼里。

mian函數(shù)之前的啟動(dòng)優(yōu)化

  • 減少動(dòng)態(tài)庫(kù)的數(shù)量(這是目前為止最耗時(shí)的了, 基本上占了95%以上的時(shí)間)
  • 合并動(dòng)態(tài)庫(kù),比如自己寫(xiě)的UI控件合并成自己的UIKit
  • 確認(rèn)動(dòng)態(tài)庫(kù)是optional還是required。如果該Framework在當(dāng)前App支持的所有iOS系統(tǒng)版本都存在,那么就設(shè)為required,否則就設(shè)為optional,因?yàn)閛ptional會(huì)有些額外的檢查
  • 合并Category(UIView+Frame,UIView+AutoLayout合并成一個(gè))
  • 將不必需在+load方法中做的事情,延時(shí)放到+initialize。

mian函數(shù)之后的啟動(dòng)優(yōu)化 首先分析一下從main函數(shù)開(kāi)始執(zhí)行,到第一個(gè)頁(yè)面顯示, 這段時(shí)間做了哪些事情

  1. 執(zhí)行didFinishLaunchingWithOptions方法
  2. 初始化Window,初始化基礎(chǔ)ViewContreoller(一般是UINavigationController+UITabViewController)
  3. 獲取數(shù)據(jù)(本地和遠(yuǎn)程)
  4. 最后展示給用戶(hù)
  5. 減少創(chuàng)建線(xiàn)程(高性能iOS開(kāi)發(fā)一書(shū)中提到,線(xiàn)程不僅僅有創(chuàng)建時(shí)的時(shí)間開(kāi)銷(xiāo),還會(huì)消耗內(nèi)核的內(nèi)存,即應(yīng)用的內(nèi)存空間。 每個(gè)線(xiàn)程大約消耗 1KB 的內(nèi)核內(nèi)存空間。線(xiàn)程創(chuàng)建的耗時(shí)(不包含啟動(dòng)時(shí)間),其區(qū)間范圍在 4000~5000 微秒,即 4~5 毫秒。創(chuàng)建線(xiàn)程后啟動(dòng)線(xiàn)程的耗時(shí)區(qū)間為 5~100 毫秒,平均大約在 29 毫秒。這是很大的時(shí)間開(kāi)銷(xiāo),若在應(yīng)用啟動(dòng)時(shí)開(kāi)啟多個(gè)線(xiàn)程,則尤為明顯。線(xiàn)程的啟動(dòng)時(shí)間之所以如此之長(zhǎng),是因?yàn)槎啻蔚纳舷挛那袚Q所帶來(lái)的開(kāi)銷(xiāo)。所以線(xiàn)程在開(kāi)發(fā)過(guò)程中也避免濫用)
  6. 合并或者刪減不必要的類(lèi)(或者分類(lèi))和函數(shù)objc的類(lèi)越多,函數(shù)越多啟動(dòng)越慢
  7. 在設(shè)計(jì)師可接受的范文盡量使用小的圖片
  • AppDelegate

通常優(yōu)化的一般來(lái)說(shuō),還是從AppDelegate先入手優(yōu)化

didFinishLaunchingWithOptions
applicationDidBecomeActive
復(fù)制代碼

優(yōu)化的核心思想就是,能延時(shí)的延時(shí), 不能延時(shí)的盡量放到后臺(tái)去優(yōu)化。

- 日志、統(tǒng)計(jì)等必須在 APP 一啟動(dòng)就最先配置的事件。仍然把它留在 didFinishLaunchingWithOptions 里啟動(dòng)。
- 項(xiàng)目配置、環(huán)境配置、用戶(hù)信息的初始化 、推送、IM等事件,這些功能在用戶(hù)進(jìn)入 APP 主體的之前是必須要加載完的,把他放到廣告頁(yè)面的viewDidAppear啟動(dòng)。
- 其他 SDK 和配置事件,由于啟動(dòng)時(shí)間不是必須的,所以我們可以放在第一個(gè)界面的 viewDidAppear 方法里,這里完全不會(huì)影響到啟動(dòng)時(shí)間。
- 每次用NSLog方式打印會(huì)隱式的創(chuàng)建一個(gè)Calendar,因此需要?jiǎng)h減啟動(dòng)時(shí)各業(yè)務(wù)方打的log,或者僅僅針對(duì)內(nèi)測(cè)版輸出log
- 盡量不要在didFinishLaunchingWithOptions 里面創(chuàng)建和開(kāi)啟多線(xiàn)程
復(fù)制代碼

參考文獻(xiàn)www.itdecent.cn/p/f40fdd879… 其文章內(nèi)部作者談到了美團(tuán)關(guān)于啟動(dòng)優(yōu)化的相關(guān)分析,看似似曾相似,沒(méi)記錯(cuò)的畫(huà)《高性能iOS應(yīng)用開(kāi)發(fā)》這本書(shū)就是美團(tuán)這幾個(gè)哥們兒翻譯的吧,實(shí)現(xiàn)方式和書(shū)中頗為相似。


3、App電量消耗

  • 1.定位
  • 2.網(wǎng)絡(luò)請(qǐng)求
  • 3.CPU處理
  • 4.GPU處理
  • 5.Bluetooth

定位優(yōu)化

1.盡量不要實(shí)時(shí)更新

2.定位精度盡量不要太高

網(wǎng)絡(luò)優(yōu)化

1.減少、壓縮網(wǎng)絡(luò)數(shù)據(jù)

2.能使用緩存就使用緩存,減少網(wǎng)絡(luò)請(qǐng)求 3.斷點(diǎn)續(xù)傳 4.批量傳輸 5.設(shè)置適合的超時(shí)時(shí)間,用戶(hù)可以取消耗時(shí)的網(wǎng)絡(luò)請(qǐng)求 6.網(wǎng)絡(luò)不可用時(shí)就不要再執(zhí)行網(wǎng)絡(luò)請(qǐng)求了

CPU/GPU優(yōu)化

相關(guān)離屏渲染操作盡量避免 內(nèi)存管理處理好 使用懶加載 使用繪制 圖片與imageView相同大小避免多余運(yùn)算 Timer的時(shí)間間隔不宜太短,滿(mǎn)足需求即可 線(xiàn)程適量,不宜過(guò)多,不要阻塞主線(xiàn)程 適當(dāng)使用多線(xiàn)程 減少視圖刷新:確保必要的時(shí)候才刷新,能刷新1行cell最好只刷新一行;

為了優(yōu)化耗電我們還可以做: 1.盡量不要使用定時(shí)器 2.優(yōu)化I/O操作(文件的讀寫(xiě)操作) 2.1最好不要頻繁讀寫(xiě)小數(shù)據(jù),最好批量讀寫(xiě) 2.2數(shù)據(jù)量比較大的時(shí)候可以考慮使用數(shù)據(jù)庫(kù) 2.3讀寫(xiě)大量重要數(shù)據(jù)時(shí),考慮用dispatch_io,其提供了基于GCD的異步操作文件I/O的API。用dispatch_io系統(tǒng)會(huì)優(yōu)化磁盤(pán)訪(fǎng)問(wèn)

高性能iOS應(yīng)用開(kāi)發(fā)中提到一下幾點(diǎn)

  • 1、CPU優(yōu)化
  • 數(shù)據(jù)處理(例如文本格式優(yōu)化)
  • 待處理的數(shù)據(jù)大小----更大的顯示屏允許軟件在單個(gè)視圖中展示更多的信息,但這也意味著要處理更多的數(shù)據(jù)
  • 處理數(shù)據(jù)的算法和數(shù)據(jù)結(jié)構(gòu)
  • 執(zhí)行更新的次數(shù),尤其是在數(shù)據(jù)更新之后,觸發(fā)應(yīng)用的狀態(tài)或者UI進(jìn)行更新(比如刷新單行cell)
  • 服務(wù)器中的數(shù)據(jù)盡量不要在客戶(hù)端上處理(例如服務(wù)器字符串,在客戶(hù)端進(jìn)行拆分操作)
  • 按需加載(例如tableViewcell 不需要一下子全部渲染,快速滑動(dòng)的時(shí)候 過(guò)程中的留白處理。)
  • 2、網(wǎng)絡(luò)
  • 在進(jìn)行網(wǎng)絡(luò)請(qǐng)求之前,先檢查是否有網(wǎng)絡(luò)連接。(沒(méi)網(wǎng)絡(luò)的時(shí)候,不要請(qǐng)求網(wǎng)絡(luò))
  • 避免沒(méi)有連接WiFi的情況下進(jìn)行高帶寬的消耗操作(因?yàn)?G、4G等手機(jī)網(wǎng)絡(luò)耗電量遠(yuǎn)大于WIFi信號(hào)),例如視頻流在4G或者非Wifi情況下應(yīng)該給出響應(yīng)的提示。
  • 3、定位
  • 盡量不要實(shí)時(shí)更新
  • 定位精度盡量不要太高

三、算法

定義相關(guān)

  1. 鏈表和數(shù)組的區(qū)別是什么? 鏈表和字典的區(qū)別是什么?

數(shù)組在內(nèi)存中是逐個(gè)存放的,鏈表每隔節(jié)點(diǎn)沒(méi)有相對(duì)固定的位置關(guān)系

數(shù)組被聲明后,大小就固定了,不能進(jìn)行動(dòng)態(tài)擴(kuò)充。 鏈表可以動(dòng)態(tài)生成節(jié)點(diǎn),并且添加到已有的鏈表后面 數(shù)組存在越界問(wèn)題,鏈表則不存在 數(shù)組的插入刪除的時(shí)間復(fù)雜度是O(n),鏈表O(1) 數(shù)組的查詢(xún)下標(biāo)時(shí)間復(fù)雜度為O(1), 鏈表為O(n) 根據(jù)值查詢(xún)的時(shí)間復(fù)雜度,鏈表和數(shù)組都是O(n)

  1. 如何檢測(cè)鏈表中是否有環(huán)?

思路 假設(shè)有兩個(gè)學(xué)生A和B在跑道上跑步,兩人從相同起點(diǎn)出發(fā),假設(shè)A的速度為2m/s,B的速度為1m/s,結(jié)果會(huì)發(fā)生什么?

答案很簡(jiǎn)單,A繞了跑道一圈之后會(huì)追上B! 將這個(gè)問(wèn)題延伸到鏈表中,跑道就是鏈表,我們可以設(shè)置兩個(gè)指針,a跑的快,b跑的慢,如果鏈表有環(huán),那么當(dāng)程序執(zhí)行到某一狀態(tài)時(shí),a==b。如果鏈表沒(méi)有環(huán),程序會(huì)執(zhí)行到a==NULL,結(jié)束。

1、 調(diào)換A和B

//    int a = 10;
//    int b = 20;
//
//    a = a + b;
//    b = a - b;
//    a = a - b;
//
//    NSLog(@"a = %d , b = %d", a, b);
//
//
//    a = a*b;
//    b = a/b;
//    a = a/b;
//
//    NSLog(@"1 =====    : a = %d , b = %d", a, b);
復(fù)制代碼

2、最大公約數(shù)

//    int n = 20,v = 30,temp = 0,max,min;
//
//    if (n>v) {
//        max = n;
//        min = v;
//    } else {
//        max = v;
//        min = n;
//    }
//
//
//    while (min != 0) {
//        temp = max - min;
//        max = min;
//        min = temp;
//    }
//
//    NSLog(@"%d", max);
復(fù)制代碼

3、打印2 - 100 的素?cái)?shù)(質(zhì)數(shù)) 除了1和自身被整除的.

//    NSMutableArray *primeNumberArray =[NSMutableArray array];
//    for(int i=2; i<=100; i++) {
//
//        NSInteger n = 0;
//
//        for(int j = 1; j <= i; j++) {
//
//            if(i % j == 0) {
//                n = n + 1;
//            }
//        }
//
//        if(n == 2) {
//            [primeNumberArray addObject:@(i)];
//        }
//    }
//
//    NSLog(@"primeNumber = %@",primeNumberArray);
//
復(fù)制代碼

4、 字符串倒敘

//    NSString *string = @"hei Son 我是你father";
//    NSMutableString *string1 = [NSMutableString string];
//    for (NSInteger i = string.length; i>0; i--) {
//        [string1 appendString:[string substringWithRange:NSMakeRange(i -1,1)]];
//    }
//
//    NSLog(@"%@", string1);
//
復(fù)制代碼

5、 尋找出字符串中有那些中文

//    for (int i = 0; i < string.length; i++) {
//        NSString *str1 = [string substringWithRange:NSMakeRange(i, 1)];
//        const char *cStr = [str1 UTF8String];
//        if (strlen(cStr) == 3 ) {  // oc中 中文三個(gè)字節(jié)
//            NSLog(@"%@", str1);
//        }
//    }
復(fù)制代碼

6. 排序

  • 冒泡排序

比較相鄰的元素。如果第一個(gè)比第二個(gè)大,就交換他們兩個(gè)。

對(duì)每一對(duì)相鄰元素做同樣的工作,從開(kāi)始第一對(duì)到結(jié)尾的最后一對(duì)。在這一點(diǎn),最后的元素應(yīng)該會(huì)是最大的數(shù)。 針對(duì)所有的元素重復(fù)以上的步驟,除了最后一個(gè)。 持續(xù)每次對(duì)越來(lái)越少的元素重復(fù)上面的步驟,直到?jīng)]有任何一對(duì)數(shù)字需要比較

for (int i = 0; i<result.count-1; i++) {
        for (int j = 0; j<result.count-1-i; j++) {
            NSInteger left = [result[j] integerValue];
            NSInteger right = [result[j+1] integerValue];
            if (left>right) {
                [result exchangeObjectAtIndex:j withObjectAtIndex:j+1];
            }
        }
    }
NSLog(@"%@",result);
時(shí)間復(fù)雜度O(n^2)
復(fù)制代碼
  • 選擇排序

選擇排序就是通過(guò)遍歷數(shù)組找出每次遍歷數(shù)組的最小元素的下標(biāo),然后將其按順序從第一位依次排列

     //self.array = @[@2,@4,@3,@1];
     NSMutableArray *mutableArray = [self.array mutableCopy];//oc數(shù)組中不能存儲(chǔ)基本數(shù)據(jù)類(lèi)型,所以快速賦值完成后,系統(tǒng)默認(rèn)數(shù)組元素為NSNumber類(lèi)型
    if (mutableArray == nil || [mutableArray count] == 0)
    {
        return;
    }
    for (int i = 0; i < [mutableArray count]; i++)
    {
        NSInteger minIdx = i;//默認(rèn)最小值的索引為i
        for (int j = i+1; j < [mutableArray count]; j++)//通過(guò)循環(huán)尋找當(dāng)前數(shù)組中最小值的索引值
        {
            if (NSOrderedAscending == [mutableArray[j] compare:mutableArray[minIdx]])//NSNumber類(lèi)判斷大小方法,這句話(huà)的意思是當(dāng)mutableArray[j] <mutableArray[minIdx]時(shí)
            {
                minIdx = j;//更新數(shù)組中最小值的索引值
            }
        }
        [mutableArray exchangeObjectAtIndex:i withObjectAtIndex:minIdx];//將每次循環(huán)結(jié)束后找到的最小值交換到數(shù)組的第i位
        NSLog(@"%@",mutableArray);
    }
}
時(shí)間復(fù)雜度為O(n)。最壞情況下仍為O(n^2)
復(fù)制代碼
  • 升序/降序
NSMutableArray *priceArray = [NSMutableArray arrayWithObjects:@"0.2",@"5",@"44",@"67",@"98.5",@"1.55", nil];

[priceArray sortUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2)  {
     if ([obj1 integerValue] < [obj2 integerValue]){
         return NSOrderedAscending;
     } else {
       return NSOrderedDescending;
     }
}];

這里再次得到的priceArray即為升序排列的數(shù)組;
若果想要得到降序的調(diào)換一下return的位置即可
復(fù)制代碼

7 尋找最近的公共View

// 所有View的父View
+ (NSArray *)superViews:(UIView *)view{
    if (view==nil) {
        return @[];
    }
    NSMutableArray *result = [NSMutableArray array];
    while (view!=nil) {
        [result addObject:view];
        view = view.superview;
    }
    return [result copy];
}

// 相互對(duì)比兩個(gè)節(jié)點(diǎn)中的view,出現(xiàn)一樣就返回
+ (UIView *)commonView_1:(UIView *)viewA  andView:(UIView *)viewB{
    NSArray *arr1 = [self superViews:viewA];
    NSArray *arr2 = [self superViews:viewB];
    for (NSUInteger i =0; i<arr1.count; ++i) {
        UIView *targetView = arr1[i];
        for (NSUInteger j=0; j<arr2.count; ++j) {
            if (targetView == arr2[j]) {
                return targetView;
            }
        }
    }
    return nil;
}

// 利用NSSet中的hash表,可以將上面代碼進(jìn)行進(jìn)一步優(yōu)化
+ (UIView *)commomView_2:(UIView *)viewA andView:(UIView *)viewB{
    NSArray *arr1 = [self superViews:viewA];
    NSArray *arr2 = [self superViews:viewB];
    NSSet *set = [NSSet setWithArray:arr2];
    for (NSUInteger i =0; i<arr1.count; ++i) {
        UIView *targetView = arr1[i];
        if ([set containsObject:targetView]) {
            return targetView;
        }
    }
   return nil;
}
復(fù)制代碼

8.數(shù)組題:如何在有序數(shù)組中找出和等于給定值的兩個(gè)元素?

NSArray *arr = @[@"1", @"12", @"13", @"23", @"31", @"43", @"52", @"66", @"88", @"111", @"127", @"199"];
[self confirmNumbers:arr total:199];
----

- (void)confirmNumbers:(NSArray *)array total:(NSInteger)totalNmuber  {
    if (array.count <= 1) { return; }

    NSInteger tempAddCount = 0;
    NSInteger tempDeleltCount = 0;

    for (int i = 0; i <= array.count; i++) {
        NSInteger tNamber = [array[tempAddCount] integerValue] + [array[array.count-1-tempDeleltCount] integerValue];
        if (tNamber == totalNmuber) {
            NSLog(@"%ld, %ld,  第一個(gè)元素%@ - 后面的元素%@", (long)tempAddCount, (long)tempDeleltCount, array[tempAddCount] ,array[array.count-tempDeleltCount-1]);
            break;
        } else if (tNamber < totalNmuber) {
            tempAddCount ++;
        } else {
            tempDeleltCount ++;
        }
        if (i == array.count - 1) {
            NSLog(@"啥都沒(méi)匹配著");
            break;
        }
    }

}
復(fù)制代碼

9 用遞歸寫(xiě)一個(gè)算法,計(jì)算從1到100的和。

NSLog(@"%ld", [self getSumResult:100]);

- (NSInteger)getSumResult:(NSInteger)number {
    if (number <=0 ) {
        return number;
    }

    return number + [self getSumResult:number - 1];
}
// 遞歸效率差的原因是 每一次調(diào)用函數(shù)(自己)都是要有內(nèi)存開(kāi)銷(xiāo)的,影響CUP的效率
復(fù)制代碼

10.打亂一個(gè)數(shù)組

  NSArray* arr = @[@"1",@"2",@"3"];
    arr = [arr sortedArrayUsingComparator:^NSComparisonResult(NSString *str1, NSString *str2) {
        int seed = arc4random_uniform(2);
        if (seed) {
            return [str1 compare:str2];
        } else {
            return [str2 compare:str1];
        }
    }];
復(fù)制代碼

11。 iOS數(shù)組去重有那些方案


// 方案一
    NSArray *originalArr = @[@1, @2, @3, @1, @3];
    NSMutableArray *resultArrM = [NSMutableArray array];

    for (NSString *item in originalArr) {
        if (![resultArrM containsObject:item]) {
          [resultArrM addObject:item];
        }
    }
    NSLog(@"result : %@", resultArrM);

// 方案二
     NSArray *originalArr = @[@1, @2, @3, @1, @3];
    NSMutableDictionary *dictM = [NSMutableDictionary dictionary];
    for (NSNumber *n in originalArr) {
        [dict setObject:n forKey:n];
    }
    NSLog(@"%@",[dictM allValues]);

// 方案三
       NSArray *originalArr = @[@1, @2, @3, @1, @3];
    NSSet *set = [NSSet setWithArray:originalArr];
    NSLog(@"result: %@", [set allObjects]);

// 方案四
    NSArray *originalArr = @[@1, @2, @3, @1, @3];
    NSArray *result = [originalArr valueForKeyPath:@"@distinctUnionOfObjects.self"];
復(fù)制代碼

三、軟技術(shù)篇 ###1.開(kāi)發(fā)過(guò)程中, 你碰到那些技術(shù)難點(diǎn)?是怎么解決的?

  • 其實(shí)這個(gè)題主要還是面試官看想了解你的真實(shí)項(xiàng)目經(jīng)驗(yàn), 如果你回答的東西,根本就算不上是什么技術(shù)問(wèn)題,而是基礎(chǔ)問(wèn)題那估計(jì)也沒(méi)什么聊下去的必要了, 舉個(gè)例子,你回答的是“我在開(kāi)發(fā)過(guò)程中總是發(fā)現(xiàn)UITableView這個(gè)控件寫(xiě)起來(lái)比較麻煩, 而且還總是報(bào)數(shù)組越界的問(wèn)題” 那么對(duì)不起, 你最多能找一個(gè)實(shí)習(xí)的工作。因?yàn)槟隳苷f(shuō)出這個(gè)問(wèn)題,我估計(jì)你上面的硬核面試題,一半兒都不知道咋回事!
  • 其實(shí)這題也沒(méi)那么高大上,說(shuō)一下你真實(shí)開(kāi)發(fā)過(guò)程中遇到的難點(diǎn),說(shuō)的越高大上越好, 最好是把面試官說(shuō)懵逼了,當(dāng)然如果你有自信的話(huà),最好別夸大,萬(wàn)一你遇上一個(gè)恰好在這個(gè)領(lǐng)域人家更牛逼呢?
  • 舉個(gè)例子“我在開(kāi)發(fā)我們項(xiàng)目的時(shí)候, 涉及到圖像處理的問(wèn)題,就比如說(shuō)現(xiàn)在網(wǎng)絡(luò)上比較火的用SDWebImage下載超清大圖的時(shí)候出現(xiàn)的崩潰問(wèn)題,因?yàn)閐ecodeImageWithImage 這個(gè)方法用于對(duì)圖片進(jìn)行壓縮并且緩存起來(lái),以保證tableview/collectionview交互更加流暢,但是如果用此方法加載超清大圖的時(shí)候, 會(huì)適得其反,有可能導(dǎo)致上G的內(nèi)存消耗, 解決辦法是對(duì)于高清圖片,應(yīng)該放在圖片解壓之后,禁止緩存解壓后的數(shù)據(jù)。 代碼如下

 - SD4.X的解決辦法
[[SDImageCache sharedImageCache] setShouldDecompressImages:NO];
[[SDWebImageDownloader sharedDownloader] setShouldDecompressImages:NO];

- SD5.0 及以上的解決辦法
SDWebImageAvoidDecodeImage添加了這個(gè)枚舉,意思是在子線(xiàn)程程解壓縮圖片
[self.imageView sd_setImageWithURL:self.url placeholderImage:[UIImage imageNamed:@"logo"] options:SDWebImageAvoidDecodeImage];
復(fù)制代碼
  • 更多詳情請(qǐng)查看 也必須看!

  • www.itdecent.cn/p/b36e96d6d…

  • www.itdecent.cn/p/64be3aed2…

  • 在舉個(gè)例子“由于在開(kāi)發(fā)過(guò)程中,用到的所有圖片必須是原圖, 問(wèn)題就出現(xiàn)了, 如果幾張圖片是超清的超大圖片,把這些圖片全部渲染到一個(gè)畫(huà)布中并且進(jìn)行隨機(jī)形狀的超高清拼圖, 這個(gè)過(guò)程會(huì)出現(xiàn)一個(gè)奇怪的問(wèn)題,就是繪制的結(jié)果是大概率會(huì)變成 一張純白色的沒(méi)有任何圖案的圖片,出現(xiàn)的原因是因?yàn)樵贏pp內(nèi)部如果正在運(yùn)行的內(nèi)存達(dá)到一定的值得時(shí)候繪制圖像的上下文就會(huì)獲取一個(gè)空白的圖片,解決辦法因?yàn)槭歉怕适录詢(xún)?nèi)部做了一個(gè)循環(huán)渲染的機(jī)制,在特定次數(shù)范圍內(nèi),如果出現(xiàn)繪制成功的話(huà)返回正常的圖片,如果沒(méi)有正確繪制,則做一個(gè)內(nèi)部的提示語(yǔ)App內(nèi)部沒(méi)有任何反應(yīng), 所以如果制作跟圖片相關(guān)的項(xiàng)目,特別涉及到自定義系統(tǒng)相冊(cè)的功能,最好優(yōu)化好內(nèi)存問(wèn)題,因?yàn)閮?nèi)存優(yōu)化不好,導(dǎo)致的問(wèn)題有很多系統(tǒng)層級(jí)的BUG。而且很難找到問(wèn)題的原因。

  • ** 這就把面試官引向了一個(gè)優(yōu)化內(nèi)存的事情。比如優(yōu)化內(nèi)存的工具, 檢測(cè)內(nèi)存泄漏,循環(huán)引用的工具等等。 下面會(huì)一一介紹。**

2.過(guò)程中, 你用過(guò)什么調(diào)試工具?

  • instrument
Leaks(泄漏):一般的查看內(nèi)存使用情況,檢查泄漏的內(nèi)存,并提供了所有活動(dòng)的分配和泄漏模塊的類(lèi)對(duì)象分配統(tǒng)計(jì)信息以及內(nèi)存地址歷史記錄;
- locations(內(nèi)存分配):跟蹤過(guò)程的匿名虛擬內(nèi)存和堆的對(duì)象提供類(lèi)名和可選保留/釋放歷史; 
Leaks(泄漏):一般的查看內(nèi)存使用情況,檢查泄漏的內(nèi)存,并提供了所有活動(dòng)的分配和泄漏模塊的類(lèi)對(duì)象分配統(tǒng)計(jì)信息以及內(nèi)存地址歷史記錄;
- locations(內(nèi)存分配):跟蹤過(guò)程的匿名虛擬內(nèi)存和堆的對(duì)象提供類(lèi)名和可選保留/釋放歷史; 
復(fù)制代碼

iOS大廠(chǎng)面試資料查看更多 來(lái)獲取一份詳細(xì)的大廠(chǎng)面試資料 為你的跳槽加薪多一份保障

結(jié)語(yǔ)

這是陸陸續(xù)續(xù)面試中總結(jié)出來(lái)的, 總之,有的問(wèn)題回答的比較撿漏, 有的問(wèn)題模棱兩可,有些面試官的反饋比較扎實(shí),有些面試官說(shuō)回答的泰國(guó)籠統(tǒng)不夠細(xì)致,反正這東西見(jiàn)仁見(jiàn)智吧。

作者:執(zhí)筆續(xù)春秋
鏈接:https://juejin.cn/post/6854573212169142285

?著作權(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)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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