如何招一個靠譜的iOS實習生(附參考答案)

此篇文章爲 2018 年中我還在滴滴時,爲項目組招聘新的 iOS 實習同窗所作,部份內容已不適用,僅供參考。html

評論更新

如下爲某些同窗的評論,爲了不本文出發點和其它同窗觀點不一樣而浪費雙方時間,把個別評論置頂從新回覆。ios

恕我直言,如今畢業院校稍好一點的、或者在校成績好一點的實習生根本沒人去作iOS的面試

答:恕我直言,如今家庭背景稍好一點的人根本不會去工做的。算法

爲啥要學ios,移動端都混合開發了數組

答:爲啥要用嘴吃飯,如今均可以直接插管流食了,多好~緩存


如下是我列出來的可以幫助你們招到一個 靠譜的iOS實習生 須要掌握的點,再次說明下狀況:多線程

  1. 此份題適用於電面和 face to face,更加偏向於電面;
  2. 可以較爲流暢的說到每道題的點上,基本上能夠認爲是掌握了;
  3. 考慮到電面過程當中,對被電面者心理素質考驗很是大,因此,我本人抵制電面過程當中考算法(這是一個流氓行爲)此套題不涉及任何關於算法方面知識。如有此需求,推薦找專門的在線 OJ 進行測評。

概念部分

struct和class的區別?

  • struct中不能定義函數(針對面向過程語言,例如C)// 可不用
  • 使用大括號進行初始化 class和struct若是定義了構造函數,就不能用大括號初始化,若沒有,則struct能夠,class只有在全部成員變量均爲public時才行。 // 可不用
  • 默認訪問權限 class默認成員訪問權限爲private;struct默認訪問你權限爲public。 // 重點
  • 繼承方式 class默認private;struct默認public。 // 重點

說出如下指針的含義:

int **a : 指向一個指針的指針,該指針指向一個整數。
int *a[10] : 指向一個有10個指針的數組,每一個指針指向一個整數。
int (*a)[10] : 指向一個有10個整數數組的指針。
int (*a)(int) : 指向一個函數的指針,該函數有一個整數參數,並返回一個整數。
複製代碼

int 和 NSInterger 的區別:

  • 以C語言舉例,int 和 long 的字節數和當前操做系統中的指針所佔位數是相等的,也就是說,long 的長度永遠 ≥ int,而且咱們須要去考慮此時是使用 int 仍是 long 比較合適,會不會由於一時疏忽選擇了 int 而致使位數不夠形成溢出。
  • 而在 OC 中使用 NSInterger ,蘋果對其進行了一個宏定義的判斷(cmd+鼠標左鍵進去看吧),這個宏定義會自動判斷當前App運行的硬件環境,究竟是 32 位機仍是 64 位機等等,從而自動返回最大的類型,而不用咱們去思考此時到底應該是用 int 仍是 long。

深拷貝和淺拷貝的區別:

  • 淺拷貝:又稱「指針拷貝」。不增長新內存,只增長一個指針指向原來的內存區域。
  • 深拷貝:又稱「內容拷貝」。同時拷貝指正和指針所指向的內存,新增指針指向新增內存。
  • // 可對OC中的可變對象和不可變對象作拓展,此問題只是單純的概念。

內存中的區域是怎麼劃分的?

  • 用以前作的一張圖進行描述:

語言部分

nil、Nil、NULL和NSNULL的區別:

  • nil: 把對象置空,置空後是一個空對象且徹底從內存中釋放;
  • Nil: 用nil的地方都可用Nil替換,Nil表示置空一個類;
  • NULL: 表示把一個指針置空。(空指針)
  • NSNULL: 把一個OC對象置空,但想保留其容器(大小)。

category和extension的區別:

  • **category:**爲已知類增長新方法。
    • 新增方法被子類集成;
    • 新增的方法比原有類具有更高的優先級,且不可重名,防止被覆蓋;
    • 不能增長成員變量。
  • extension: 爲當前類增長私有變量和私有方法,添加的方法是必須實現的。

@Property關鍵詞及其相關關鍵字的理解:

  • 根據被修改的可能性,、@Property 中關鍵字的排列推薦爲:原子性、讀寫性、內存管理特性;
  • 原子性: automatic 和 nonautomatic。決定了該屬性是否爲原子性的,即在多線程的操做中,不能被其它線程打斷的特性,一旦使用了該變量的操做不能被完整執行時,將會回到該變量操做以前的狀態,但原子性即 automatic由於是原語操做(保證 setter/getter 的原語執行),會損耗性能,在 iOS 開發中通常不用,而在 macOS 開發中隨意。
  • 讀寫性: readOnly 和 readWrite。默認爲 readWrite,編譯器會幫助生成 serter/getter 方法,而 readOnly 只會幫助生成 getter 方法。 // 此處可拓展,非要修改 readOnly 修飾的變量怎麼辦,可用 KVC,又可繼續拓展 KVC 相關知識。
  • 內存管理特性: assign、weak、strong、unsafe_unretained。
    • assign:通常用於值類型,好比int、BOOL等(還可用於修飾OC對象);
    • weak:用於修飾引用類型(弱引用,只能修飾OC對象);
    • strong:用於修飾引用類型(強引用);
    • unsafe_unretained:只用於修飾引用類型(弱引用),與weak的區別在於,被unsafe_unretained修飾的對象被銷燬後,其指針並不會被自動置空,此時指向了一個野地址。

OC中如何定義一個枚舉?

  • 在 OC 中定義一個枚舉有三種作法:併發

    • 由於 OC 是兼容 C 的,因此可使用 C 語言風格的 enum 進行定義。
    • 使用NS_ENUM宏進行定義;
    • 使用NS_OPTIONS宏進行定義;
  • NS_ENUM爲定義通用性枚舉,只能單選,NS_OPTIONS爲定義位移枚舉,可多選。 // 枚舉爲啥要這麼分?由於涉及到是否使用 C++ 模式進行編譯有關。異步

Block和函數的關係(對Block的理解)?

  • Block 與函數指針很是相似,但Block可以訪問函數之外、詞法做用域之外的外部變量的值;
  • Block 不只實現了函數的功能,還攜帶了函數的執行環境;
  • Block 其實是指向結構體的指針;(可參考這篇文章
  • Block 會把進入其內部的基本數據類型變量當作常量處理。】
  • Block 執行的是一個回調,並不知道其中的對象合適被釋放,因此爲了防止在使用對象以前就被釋放掉了,會自動給其內部所使用的對象進行retain一次。
  • Block 使用copy修飾符進行修飾,且不能使用retain進行修飾,由於retain只是進行了一次回調,但 block 的內存仍是放在了棧空間中,在棧上的變量隨時會被系統回收,且Block在建立的時候內存默認就已經分配在棧空間中,其自己的做用域限於其建立時,一旦在超出其建立時的做用域以外使用,則會致使程序的崩潰,故使用 copy 修飾,使其拷貝到堆空間中,block 有時還會用到一些本地變量,只有將其 copy 到堆空間中,才能使用這些變量。

deletegate須要weak修飾的緣由?

  • 以圖說明,圖中所表示的是VC對tableView的持有,若是此時的tableView.deletegate對VC也是強引用,會致使循環引用,同時也給了咱們敲了警鐘,當出現兩個對象都是強引用時,萬分當心!

解釋一下這段代碼的輸出:

  • 簡寫:
Computer : NSObject
Mac : Computer

@implementation Mac

NSLog(@"%@", [self class]);
NSLog(@"%@", [super class])

@end
複製代碼
  • 兩者都會輸出Mac。函數

    • [self class]:當使用self調用方法時,從當前類方法列表中找,若沒有則再去父類中找。調用[self class]時,會轉化成objc_msgSend函數,其定義爲id objc_msgSend(id self, SEL op, ...),第一個參數是Mac實例,但其並沒有-(Class)class方法,此時去父類Computer中尋找,發現也沒有,再去其父類NSObject中找,找到了!返回的就是self其自己,可猜想其方法實現以下:
    - (Class)class {
      return object_getClass(self);
    }
    複製代碼
    • [super class]:從父類方法列表中開始找,調用父類方法。當調用[super class]時,轉換成objc_msgSendSuper函數,其定義爲id objc_msgSendSuper(struct objc_super *super, SEL op, ...),而struct objc_super結構體的定義爲:
      struct objc_super {
        __unsafe_unretained id receiver;
        __unsafe_unretained Class super_class;
      }
      複製代碼
      因此轉換成objc_msgSendSuper函數後,第一步要先去構造objc_super結構體,結構的第一個成員receiver就是self,第二個成員是(id)class_getSuperclass(object_getClass("Mac")),該函數輸出的結果爲super_class值,即Computer,第二步,則去Computer類中去找- (Class)class,發現並未找到,接着去NSObject中找,找到了!最後是使用了objc_msgSend(objc_super->receiver, @selector(class))去調用了,這個時候已經跟以前的[self class]調用輸出結果重複了,返回結果仍是Mac

iOS部分

UITableView性能調優的方法:

  • Cell重用:
    • 數據源方法優化:建立一個靜態變量重用ID,例如:static NSString *cellID = @"cellID";防止由於調用次數過多,static保證只建立一次,提升性能(感受性能的提高能夠忽略不記emmm)
    • 緩存池獲取可重用Cell的兩個方法:dequeueReusableCellWithIdentifier:(NSString *)ID會查詢可重用Cell,若註冊了原型Cell則可以查詢到,不然爲nil,故須要先判斷if(cell == nil)
    • dequeueReusableCellWithIdentifier:(NSString *)ID indexPath:(NSIndexPath *)indexPath,使用以前必須經過SB/class進行可重用Cell的註冊(registerNib/registerClass),不須要判斷nil,必定會返回cell,若緩衝區Cell不存在,會使用原型Cell從新實例化一個新Cell。
  • 儘可能使用一種類型的Cell:可以減小代碼量,減少Nib文件的數量;保證只有一種類型的Cell,實際上App運後只有N個Cell,但如有M種Cell,則實際上運行最多卻可能會是MxN 個。
  • 善用hidden隱藏subview:把全部不一樣類型的view都定義好,經過cell的枚舉類型變量及hidden顯示/隱藏不一樣類型的內容,由於在實際快速滑動中,單純的顯示/隱藏subview比實時建立快得多。
  • 提早計算並緩存Cell的高度。若是咱們不預估行高,則優先調用heightForRowAtIndexPath獲取每一個Cell即將顯示的高度,實際上就是要肯定總的tableView.contenSize,最後才又接着調用cellForRowAtIndexPath,能夠建一個frame模型,保存下提早計算好的cell高度。
  • 異步繪製:這是目前最火的tableView性能調優方法,新浪微博是這麼作的,可使用ASDK這個庫進行。
  • tableView滑動時,按需加載:識別tableView靜止或減速滑動結束後,異步加載,在快速滑動過程當中,只按需加載目標方位內的Cell。
  • 避免大量使用圖片縮放、顏色漸變、透明圖層、CALayer特效(陰影)等操做,儘可能顯示大小恰好合適的圖片資源。

內存優化方案:

  • 首先ARC。但要注意防止循環引用,避免內存泄露;
  • 懶加載。延遲建立對象,用時再建立;
  • 複用。好比tableView、collectionView單元格的複用;
  • 巧妙使用單例,而不是全都使用單例!

單例的寫法?

static User *user;
+ (User *)shareInstance {
  if (user == nil) {
    @synchronized(self) {
      // 加鎖
      user = [User alloc] init];
    }
  }
  return user;
}


+ (User *)shareInstance {
  static dispatch_onec_t onecToken;
  dispatch_onece(&onceToken, ^{
    user = [User alloc] init;
  })
  return user;
}
複製代碼

iOS的遠程推送過程?

  • 以圖講解:

iOS中多線程的概念:(單問概念)

  • 多線程優勢:提升程序執行效率。缺點:開啓線程須要必定的內存控件。
  • 同步和異步:決定了要不要開啓新的線程。同步:在當前線程中執行任務,不具有開啓新線程能力;異步:在新線程中執行任務,具有開啓新線程的能力。
  • 並行和串行:決定了任務的執行方式。並行:多個任務併發(同時)執行,相似迅雷多任務同時下載;串行:一個任務執行完畢後,再執行下一個任務,相似一個一個下載。
  • 重點: 必需要明確iOS中只有一個主線程——UI線程,且不可將耗時任務放在主線程執行,不然會形成卡頓。

總結:再次說明,實際電面過程當中,本套題只可做爲參考,並且在電面過程當中會有追問和等待的過程,因此最佳電面時間爲三十分鐘內最佳,嫌短?記好了!這招的是實習生,並且這仍是電面!!!別學啥大公司的戾氣,一個實習生的電面你要搞一個小時甚至快兩個小時,沒有必要。若是是face to face隨你問一兩個小時,但重點是這是電面!不要把這種「隔空喊話」的面試方式做爲考覈一我的是否具有對應的工做能力的最終標準,除非可以肯定之後的工做方式就是「隔空喊話」和「隔空擼碼」。

也不推薦把本套題中的內容做爲一面,一面應該是做爲了解應聘者的職業情況,基礎水平(也是就是邏輯能力),推薦本套題做爲二面,涵蓋基本的iOS開發基礎知識,並且時間可以較好的把握在三十分鐘內,三面應該側重項目實際狀況,並且最好face to face。四面就HR面了吧,儘可能不要有五面了,太難受了。其實三面是最佳的。

記住!不要套題,而應該是舉一反三,引出其它問題。

相關文章
相關標籤/搜索