1.NSObject和id的區(qū)別
NSObject和id都可以指向任何對象
NSObject對象會在編譯時進行檢查
id類型不需要編譯時檢查 不需要強制類型轉(zhuǎn)換
2.id類型, nil , Nil ,NULL和NSNULL的區(qū)別?
- id類型 是一個獨特的數(shù)據(jù)類型 可以轉(zhuǎn)換為任何數(shù)據(jù)類型 id類型的變量可以存放任何數(shù)據(jù)的對象 在內(nèi)部處理上
這種類型被定義為指向?qū)ο蟮闹羔?實際上是一個指向這種對象的實例變量的指針 id聲明的對象具有運行時特性
即可以指向任意的對象
- nil 是一個實例對象的值 如果要把一個class的對象設(shè)置為空的時候 就用nil
- NIl 是一個類對象的值 如果要把一個class的對象設(shè)置為空的時候 用Nil
- NULL 指向基本數(shù)據(jù)類型的空指針
NSNULL 是一個對象 用在不能使用nil的場合
3.SMutableDictionary 中使用setValueForKey 和 setObjectForKey有什么區(qū)別?
如果調(diào)用setValue仍然是調(diào)用了setObject方法 如果參數(shù)value為nil 則會調(diào)用removeObject移除這個鍵值對
- setObjectForKey 是SMutableDictionary特有的 value不能為nil 否則會崩潰
- setValueForKey 是kvc的 key必須是字符串類型 setObject的key可以是任意類型
4.NSCache 和NSDictionary 區(qū)別?
@NSCache 可以提供自動刪減緩存功能 而且保證線程安全 與字典不同 不會拷貝鍵
@NSCache可以設(shè)置緩存上限 限制對象個數(shù)和總緩存開銷 定義了刪除緩存對象的時機 這個機制只對NSCache起到指導作用,不會一定執(zhí)行
@NSPurgeableData搭配NSCache使用党窜,可以自動清除數(shù)據(jù)
5.什么是面向過程?(POP--Procedure Oriented Programming)
“面向過程”(Procedure Oriented)是一種以過程為中心的編程思想。就是分析出解決問題所需要的步驟卵史,然后
用函數(shù)把這些步驟一步一步實現(xiàn)姓赤,使用的時候一個一個依次調(diào)用就可以了另萤。注重的是實現(xiàn)過程!
6.什么是面向?qū)ο?(OOP--Object Oriented Programming)
“面向?qū)ο蟆笔且环N以對象為中心的編程思想浑槽。
面向?qū)ο蟮娜筇匦裕?
@封裝
隱藏對象的屬性和實現(xiàn)細節(jié)兢哭,僅對外提供公共訪問方式领舰,將變化隔離,便于使用迟螺,提高復用性和安全性提揍。
@繼承
提高代碼復用性;建立了類之間的關(guān)系煮仇;子類可以擁有父類的所有成員變量的方法;繼承是多態(tài)的前提谎仲。
@多態(tài)
父類或接口定義的引用變量可以指向子類或具體實現(xiàn)類的實例對象浙垫。提高了程序的拓展性。
正因為面向?qū)ο缶幊逃兄N特性郑诺,繼承夹姥、封裝、多態(tài)辙诞,從而使得面向?qū)ο缶幊谈哂腥菀鬃屓私邮苷奘郏N近與
人們的生活,比面向?qū)ο缶幊谈臃奖闩c快捷飞涂,一定程度上降低了程序員的工作量旦部,使程序的可讀性也得到了提高,代碼的效率也得到了提高
7. 為什么說OC是一門動態(tài)語言较店?
動態(tài)語言:是指程序在運行時可以改變其結(jié)構(gòu)士八,新的函數(shù)可以被引進,已有的函數(shù)可以被刪除等在結(jié)構(gòu)上的變化
動態(tài)類型語言: 就是類型的檢查是在運行時做的。
OC的動態(tài)特性可從三方面:
動態(tài)類型(Dynamic typing): 最終判定該類的實例類型是在運行期間
動態(tài)綁定(Dynamic binding):在運行時確定調(diào)用的方法
動態(tài)加載(Dynamic loading):在運行期間加載需要的資源或可執(zhí)行代碼
8.簡要說明const,宏,static,extern區(qū)分以及使用?
const
const常量修飾符,經(jīng)常使用的字符串常量梁呈,一般是抽成宏婚度,但是蘋果不推薦我們抽成宏,推薦我們使用const常量官卡。
- const 作用:限制類型
- 使用const修飾基本變量, 兩種寫法效果一致 , b都是只讀變量
const int b = 5;
int const b = 5;
- 使用const修飾指針變量的變量
第一種: const int *p = &a 和 int const *q = &a; 效果一致,*p 的值不能改,p 的指向可以改;
第二種: int * const p = &a; 表示 p 的指向不能改,*p 的值可以改
第三種:
const int * const p = &a; *p 值和 p 的指向都不能改
const 在*左邊, 指向可變, 值不可變
const 在*的右邊, 指向不可變, 值可變
const 在*的兩邊, 都不可變
宏
* 基本概念:宏是一種批量處理的稱謂蝗茁。一般說來醋虏,宏是一種規(guī)則或模式,或稱語法替換 哮翘,用于說明某一特定輸入
(通常是字符串)如何根據(jù)預定義的規(guī)則轉(zhuǎn)換成對應的輸出(通常也是字符串)颈嚼。這種替換在預編譯時進行,稱作宏
展開忍坷。編譯器會在編譯前掃描代碼粘舟,如果遇到我們已經(jīng)定義好的宏那么就會進行代碼替換,宏只會在內(nèi)存中copy一
份佩研,然后全局替換柑肴,宏一般分為對象宏和函數(shù)宏。 宏的弊端:如果代碼中大量的使用宏會使預編譯時間變長旬薯。
const與宏的區(qū)別晰骑?
* 編譯檢查 宏沒有編譯檢查,const有編譯檢查绊序;
* 宏的好處 定義函數(shù)硕舆,方法 const不可以;
* 宏的壞處 大量使用宏骤公,會導致預編譯時間過長
static
* 修飾局部變量: 被static修飾局部變量抚官,延長生命周期,跟整個應用程序有關(guān)阶捆,程序結(jié)束才會銷毀,被 static 修飾局部變量凌节,只會分配一次內(nèi)存
* 修飾全局變量: 被static修飾全局變量,作用域會修改洒试,也就是只能在當前文件下使用
extern
聲明外部全局變量(只能用于聲明倍奢,不能用于定義)
常用用法(.h結(jié)合extern聯(lián)合使用)
如果在.h文件中聲明了extern全局變量,那么在同一個類中的.m文件對全局變量的賦值必須是:數(shù)據(jù)類型+變量名
(與聲明一致)=XXXX結(jié)構(gòu)垒棋。并且在調(diào)用的時候卒煞,必須導入.h文件。代碼如下:
.h
@interface ExternModel : NSObject
extern NSString *lhString;
@end
.m
@implementation ExternModel
NSString *lhString=@"hello";
@end
調(diào)用的時候:例如:在viewController.m中調(diào)用叼架,則可以引入:ExternModel.h畔裕,否則無法識別全局變量。當
然也可以通過不導入頭文件的方式進行調(diào)用(通過extern調(diào)用)碉碉。
9.什么是指針常量和常量指針柴钻?
常量指針本質(zhì)是指針,常量修飾它垢粮,表示這個指針乃是一個指向常量的指針(變量)贴届。
指針指向的對象是常量,那么這個對象不能被更改。
指針常量的本質(zhì)是一個常量毫蚓,而用指針修飾它占键,那么說明這個常量的值應該是一個指針。
指針常量的值是指針元潘,這個值因為是常量畔乙,所以不能被賦值
10.靜態(tài)庫和動態(tài)庫的區(qū)別
靜態(tài)庫
@以.a和.framework為文件后綴名
@鏈接時會被完整的復制到可執(zhí)行文件中 被多次使用就有多份拷貝
動態(tài)庫
@以.tbd和.framework為文件后綴名
@鏈接時不復制 程序運行時由系統(tǒng)動態(tài)加載到內(nèi)存 系統(tǒng)只加載一次 多個程序共用 節(jié)省內(nèi)存
靜態(tài)庫.a和framework的區(qū)別是.a主要是二進制文件 不包含資源 需要自己添加頭文件 .framework可以包含頭文件和資源信息
11.函數(shù)指針和 Block區(qū)別
相同點
@都是一個代碼片段
@函數(shù)指針類型和Block類型都可以作為變量和函數(shù)類型的類型
不同點
@函數(shù)指針只能指向預先定義好的函數(shù)代碼塊 函數(shù)地址是在編譯連接時就已經(jīng)確定好的 從內(nèi)存的角度看 函數(shù)指針
只不過是指向代碼區(qū)的一段可執(zhí)行代碼
@block本質(zhì)是oc對象 是NSObject的子類 是程序運行過程中在棧內(nèi)存動態(tài)創(chuàng)建的對象 可以向其發(fā)送copy消息
將block對象拷貝到堆內(nèi)存 以延長其生命周期
12.ViewController 生命周期
- initWithCoder:(NSCoder *)aDecoder:(如果使用storyboard或者xib)
- loadView:加載view
- viewDidLoad:view加載完畢
- viewWillAppear:控制器的view將要顯示
- viewWillLayoutSubviews:控制器的view將要布局子控件
- viewDidLayoutSubviews:控制器的view布局子控件完成
- viewDidAppear:控制器的view完全顯示
- viewWillDisappear:控制器的view即將消失的時候
- viewDidDisappear:控制器的view完全消失的時候
- dealloc 控制器銷
13.CALayer的frame,bounds翩概,anchorPoint,position
frame 左上角相對于坐標系的位置
bounds 左上角相對于自身坐標系的位置
anchorPoint 錨點在自身坐標系中的相對位置 通常用于做相對的tranform交換
position 錨點在supLayer坐標系中的位置
14.layoutSubview和drawRect
layoutSubviews調(diào)用情況
init初始化UIView不會觸發(fā)調(diào)用
addSubview會觸發(fā)調(diào)用
改變view的width和height的時候回觸發(fā)調(diào)用
一個UIScrollView滾動會觸發(fā)調(diào)用
旋轉(zhuǎn)screen會觸發(fā)調(diào)用
改變一個UIView大小的時候會觸發(fā)superView的layoutSubviews事件
直接調(diào)用setLayoutSubviews會觸發(fā)調(diào)用
-(void)viewWillAppear:(BOOL)animated會觸發(fā)一次調(diào)用
-(void)viewDidAppear:(BOOL)animated 看情況牲距,可能有調(diào)用
drawRect調(diào)用情況
如果UIView沒有設(shè)置frame大小,直接導致drawRect不能被自動調(diào)用钥庇。
drawRect在loadView和viewDidLoad這兩個方法之后調(diào)用
調(diào)用sizeToFit后自動調(diào)用drawRect
通過設(shè)置contentMode值為UIViewContentModeRedraw牍鞠。那么每次設(shè)置或者更改frame自動調(diào)用drawRect。
直接調(diào)用setNeedsDisplay或者setNeedsDisplayInRect會觸發(fā)調(diào)用
15. layoutIfNeeded , layoutSubViews和 setNeedsLayout區(qū)別
@layoutIfNeeded 方法一點被調(diào)用,主線程會立即強制重新布局,它會從當前視圖開始,一直到完成所有子視圖的布局
@layoutSubViews 用來自定義視圖尺寸,他是系統(tǒng)自動調(diào)用的,開發(fā)者不能手動調(diào)用,可以重寫改方法,讓系統(tǒng)在
調(diào)整布局時候按照我們希望的方式進行布局.這個方法在旋轉(zhuǎn)屏幕,滑動或者觸摸屏幕,修改子視圖時候被觸發(fā).
@setNeedsLayout 和 layoutIfNeeded相似,唯一不同的是他不會立即強制視圖重新布局,而是在下一個布局
周期才會觸發(fā)更新.他主要用于多個視圖布局先后更新的場景
16.程序啟動過程
main 函數(shù)執(zhí)行前
1.首先當程序啟動時评姨,系統(tǒng)會讀取程序的可執(zhí)行文件(mach-o), 從里面獲取動態(tài)加載器(dylb)的路徑;
2.加載dylb, dylb會初始化運行環(huán)境难述,配合ImageLoader將二進制文件加載到內(nèi)存中去;
3.動態(tài)鏈接依賴庫, 初始化依賴庫,初始化 runtime;
4.runtime 會對項目中的所有類進行類結(jié)構(gòu)初始化吐句,調(diào)用所有的 load 方法;
5.最后 dylb 會返回 main 函數(shù)地址胁后,main 函數(shù)被調(diào)用,進入程序入口
main 函數(shù)執(zhí)行后
1.內(nèi)部會調(diào)用 UIApplicationMain 函數(shù)嗦枢,創(chuàng)建一個UIApplication對象和它的代理攀芯,就是我們項目中的 Appdelegate 類
2.開啟一個事件循環(huán)(main runloop), 監(jiān)聽系統(tǒng)事件
3.程序啟動完畢時,通知代理Appdelegate, 調(diào)用 didFinishLaunching 代理方法文虏,在這里會創(chuàng)建 UIWindow,設(shè)置它的rootViewController,
4.最后調(diào)用 self.window makeKeyAndVisable顯示窗口
17.UIScrollView 原理
UIScrollView繼承自UIView敲才,內(nèi)部有一個 UIPanGestureRecongnizer手勢。 frame是相對父視圖坐標系
來決定自己的位置和大小择葡,而bounds是相對于自身坐標系的位置和尺寸的。改視圖 bounds 的 origin 視圖本
身沒有發(fā)生變化剃氧,但是它的子視圖的位置卻發(fā)生了變化敏储,因為 bounds 的 origin 值是基于自身的坐標系,當自
身坐標系的位置被改變了朋鞍,里面的子視圖肯定得變化已添, bounds 和 panGestureRecognize 是實現(xiàn)
UIScrollView 滑動效果的關(guān)鍵技術(shù)點
18.使用 drawRect 有什么影響?
@drawRect 方法依賴 Core Graphics 框架來進行自定義的繪制
@缺點:它處理 touch 事件時每次按鈕被點擊后,都會用 setNeddsDisplay 進行強制
@重繪;而且不止一次滥酥,每次單點事件觸發(fā)兩次執(zhí)行更舞。這樣的話從性能的角度來 說,對 CPU 和內(nèi)存來說都是欠佳的坎吻。
特別是如果在我們的界面上有多個這樣的 UIButton 實例缆蝉,那就會很糟糕了
@這個方法的調(diào)用機制也是非常特別. 當你調(diào)用 setNeedsDisplay 方法時, UIKit 將會 把當前圖層標記為
dirty,但還是會顯示原來的內(nèi)容,直到下一次的視圖渲染周期,才會 將標記為 dirty 的圖層重新建立
Core Graphics 上下文,然后將內(nèi)存中的數(shù)據(jù)恢復出 來, 再使用 CGContextRef 進行繪制
19.masksToBounds 和clipsToBounds
masksToBounds 是指子 layer 在超出父 layer時是否被裁剪,YES表示參見,NO 表示不裁剪, 默認是NO
clipsToBounds 是指子 View 在超出父 View時是否被裁剪
20.什么是隱式動畫和顯示動畫
隱式動畫是系統(tǒng)框架自動完成的。Core Animation在每個runloop周期中自動開始一次新的事務(wù),即使你不顯式的用[CATransaction begin]開始一次事務(wù)刊头,任何在一次runloop循環(huán)中屬性的改變都會被集中起來黍瞧,然后做一次0.25秒的動畫。在iOS4中原杂,蘋果對UIView添加了一種基于block的動畫方法:+animateWithDuration:animations:印颤。這樣寫對做一堆的屬性動畫在語法上會更加簡單,但實質(zhì)上它們都是在做同樣的事情穿肄。CATransaction的+begin和+commit方法在+animateWithDuration:animations:內(nèi)部自動調(diào)用年局,這樣block中所有屬性的改變都會被事務(wù)所包含,多用于簡單動畫效果
[UIView animateWithDuration:1 animations:^{
view.center = self.view.center;
}];
顯式動畫,Core Animation提供的顯式動畫類型咸产,既可以直接對layer層屬性做動畫矢否,也可以覆蓋默認的圖層行為。我們經(jīng)常使用的CABasicAnimation锐朴,CAKeyframeAnimation兴喂,CATransitionAnimation,CAAnimationGroup等都是顯式動畫類型焚志,這些CAAnimation類型可以直接提交到CALayer上衣迷。顯式動畫可用于實現(xiàn)更為復雜的動畫效果
CABasicAnimation *positionAnima = [CABasicAnimation animationWithKeyPath:@"position.y"];
positionAnima.duration = 0.8;
positionAnima.fromValue = @(self.imageView.center.y);
positionAnima.toValue = @(self.imageView.center.y-30);
positionAnima.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
positionAnima.repeatCount = HUGE_VALF;
positionAnima.repeatDuration = 2;
positionAnima.removedOnCompletion = NO;
positionAnima.fillMode = kCAFillModeForwards;
[self.imageView.layer addAnimation:positionAnima forKey:@"AnimationMoveY"];
21.SafeArea, SafeAreaLayoutGuide, SafeAreaInsets 關(guān)鍵詞的比較說明
由于 iphoneX 采用了劉海設(shè)計,iOS11引入了安全區(qū)域(SafeArea)概念
SafeArea是指App 顯示內(nèi)容的區(qū)域,不包括StatusBar,Navigationbar,tabbar,和 toolbar, 在
iPhoneX 中一般是指扣除了statusBar(44像素),和底部home indicator(高度為34像素)的區(qū)域.這樣操作不會被劉海或者底部手勢影響了.
SafeAreaLayoutGuide 是指 Safe Area 的區(qū)域范圍和限制, 在布局設(shè)置中,可以取得他的上下左右4個邊界位置進行相應的布局
SafeAreaInsets限定了Safe Area區(qū)域與整個屏幕之間的布局關(guān)系,一般用上下左右4個值來獲取 SafeArea 與屏幕邊緣之間的距離
22.內(nèi)存泄漏可能會出現(xiàn)的幾種原因
第一種可能:第三方框架不當使用酱酬;
第二種可能:block循環(huán)引用壶谒;
第三種可能:delegate循環(huán)引用;
第四種可能:NSTimer循環(huán)引用
第五種可能:非OC對象內(nèi)存處理
第六種可能:地圖類處理
第七種可能:大次數(shù)循環(huán)內(nèi)存暴漲
23.是否可以把比較耗時的操作放在 NSNotification中?
如果在異步線程發(fā)的通知膳沽,那么可以執(zhí)行比較耗時的操作;
如果在主線程發(fā)的通知汗菜,那么就不可以執(zhí)行比較耗時的操作
24.NSOperation取消線程方式?
1.通過 cancel 取消未執(zhí)行的單個操作
NSOperationQueue *queue1 = [[NSOperationQueue alloc]init];
NSBlockOperation *block1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"block11");
}];
NSBlockOperation *block2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"block22");
}];
NSBlockOperation *block3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"block33");
}];
[block3 cancel];
[queue1 addOperations:@[block1,block2,block3] waitUntilFinished:YES];
2.移除隊列里面所有的操作,但正在執(zhí)行的操作無法移除
[queue1 cancelAllOperations];
3.掛起隊列挑社,使隊列任務(wù)不再執(zhí)行陨界,但正在執(zhí)行的操作無法掛起
queue1.suspended = YES;
4.我們可以自定義NSOperation,實現(xiàn)取消正在執(zhí)行的操作痛阻。其實就是攔截main方法菌瘪。
main方法:
1、任何操作在執(zhí)行時阱当,首先會調(diào)用start方法俏扩,start方法會更新操作的狀態(tài)(過濾操作,如過濾掉處于“取消”狀態(tài)的操作)。
2弊添、經(jīng)start方法過濾后录淡,只有正常可執(zhí)行的操作油坝,就會調(diào)用main方法嫉戚。
3刨裆、重寫操作的入口方法(main),就可以在這個方法里面指定操作執(zhí)行的任務(wù)彼水。
4崔拥、main方法默認是在子線程異步執(zhí)行的。
25.什么是序列化和反序列化凤覆,用來做什么
序列化 把對象轉(zhuǎn)化為字節(jié)序列的過程
反序列 化把直接序列恢復成對象
作用 把對象寫到文件或者數(shù)據(jù)庫中链瓦,并且讀取出來
26.沙盒目錄結(jié)構(gòu)是怎樣的
Documents:常用目錄,iCloud備份目錄盯桦,存放數(shù)據(jù),這里不能存緩存文件,否則上架不被通過
Library
Caches:存放體積大又不需要備份的數(shù)據(jù),SDWebImage緩存路徑就是這個
Preference:設(shè)置目錄慈俯,iCloud會備份設(shè)置信息
tmp:存放臨時文件,不會被備份拥峦,而且這個文件下的數(shù)據(jù)有可能隨時被清除的可能
27.使用 NSUserDefaults 時贴膘,如何處理布爾的默認值?(比如返回 NO略号,不知道是真的 NO 還是沒有設(shè)置過)
如果使用 - (void)setBool:(BOOL)value forKey:(NSString *)defaultName;方法,來進行存儲,就可以獲取到正確的 bool 值
如果使用 - (void)setObject:(nullable id)value forKey:(NSString *)defaultName;,需要在獲取到值后在轉(zhuǎn)為 bool類型
28.當數(shù)據(jù)庫中的某項數(shù)據(jù)未 null 時候,通過FMDB獲取的數(shù)據(jù)為
[NSNull null]