1,請簡述你對協議的理解?
protocol無論是在那個領域都是一種約束,規范。在OC中的協議主要用於在各個類之間進行回調傳值。 協議有 委托方,代理方, 委托方是協議的制定者,需要聲明協議的方法,實現協議的對象。代理方,是協議的遵守着,需要遵守協議,並實現協議中的必要方法。
2,如何理解ARC自動引用計數機制?
Cocoa采用了引用計數(reference
counting)機制,每一個對象有一個關聯的“整數retainCount”用於記錄對象的使用情況。對象被引用時retaincount+1,外部
環境結束對象的使用后retainCount-1.當retaincount為0的時候,該對象被銷毀。
當我們使用alloc、new或者copy的我們需要銷毀這個對象。release函數,只是將對象的retainCount值減1,並不是刪除對象。當retainCount==0的時候,系統會發給對象一個dealloc消息,另外:千萬不要手動調用dealloc,因為我們不知道何時,何地,何人還會使用該對象。應該老老實實依賴引用計數機制完成內存管理。
釋放對象所有權的函數除了release還有autorelease,這是一種延遲操作。
3,如何理解 retain/copy/assign/release/autor release/dealloc關鍵字?
copy:建立一個索引計數為1的對象,然后釋放舊對象,主要用於nsstring;
retain:釋放舊的對象,將舊對象的值賦予輸入對象,再提高輸入對象的索引計數為1
對其他NSObject和其子類
assign: 簡單賦值,不更改索引計數
release:手動釋放對象;
dealloc:它的作用是,當對象的引用計數為0,系統會自動調用dealloc方法,回收內存。
autorelease 原理:
a.先建立一個autorelease pool
b.對象從這個autorelease pool里面生成。
c.對象生成 之后調用autorelease函數,這個函數的作用僅僅是在autorelease pool中做個標記,讓pool記得將來release一下這個對象。
d.程序結束時,pool本身也需要rerlease, 此時pool會把每一個標記為autorelease的對象release一次。如果某個對象此時retain count大於1,這個對象還是沒有被銷毀。
(weak和strong)不同的是 當一個對象不再有strong類型的指針指向它的時候 它會被釋放 ,即使還有weak型指針指向它。weak表示如果還沒有人指向它了,它就會被清除內存,同時被指向nil
4 self.name與_name的區別
1.首先通過self.xxx 通過訪問的方法的引用:包含了set和get方法。而通過下划線是獲取自己的實例變量,不包含set和get的方法。
2.self.xxx是對屬性的訪問;而xxx是對局部變量的訪問。所有被聲明為屬性的成員,再ios5之前需要使用編譯指令@synthesize 來告訴編譯器幫助生成屬性的getter和setter方法,之后這個指令可以不用認為的指定了,默認情況下編譯器會幫助我們生成。編譯器在生成getter,setter方法時是有優先級的,他首先查找當前的類中用戶是否定義屬性的getter,setter方法,如果有,則編譯器會跳過,不會再生成,使用用戶定義的方法。也就是說你在使用self.xxx時是調用一個getter方法。會使引用計數加一,而xxx不會使用引用技術加一的。
所有使用self.xxx是更好的選擇,因為這樣可以兼容懶加載,同時也避免了使用下滑線的時候忽略了self這個指針,后者容易在BLock中造成循環引用。同時,使用 _是獲取不到父類的屬性,因為它只是對局部變量的訪問。
最后總結:self方法實際上是用了get和set方法間接調用,下划線方法是直接對變量操作。
5 繼承 與 類別 的聯系與區別
聯系:
可以給一個類擴展新的方法,或修改已有的方法
區別:
1. 繼承修改的方法不會對父類原方法產生影響;類別修改的方法相當於替換了原有方法
2. 以viewController舉例,繼承一個viewController相當於建立一個新的頁面;而給一個viewController添加類別用於增加或修改原viewController上的方法
3. 類別支持開發人員針對自己構建的類,把相關的方法分組到多個單獨的文件中,對於大型而復雜的類,這有助於提高可維護性,並簡化單個源文件的管理。
4. 針對系統提供的一些類,例如:NSString,NSArray,NSNumber等類,系統本身不提倡使用繼承去擴展方法,因為這些類內部實現對繼承有所限制,所以最后使用類別來進行方法擴展。
5. 理論上類別不能新增屬性
6 Strong與Weak的區別
(weak和strong)不同的是 當一個對象不再有strong類型的指針指向它的時候 它會被釋放 ,即使還有weak型指針指向它。 一旦最后一個strong型指針離去 ,這個對象將被釋放,所有剩余的weak型指針都將被清除。 可能有個例子形容是妥當的。 想象我們的對象是一條狗,狗想要跑掉(被釋放)。 strong型指針就像是栓住的狗。只要你用牽繩掛住狗,狗就不會跑掉。如果有5個人牽着一條狗(5個strong型指針指向1個對象),除非5個牽繩都脫落 ,否着狗是不會跑掉的。 weak型指針就像是一個小孩指着狗喊到:“看!一只狗在那” 只要狗一直被栓着,小孩就能看到狗,(weak指針)會一直指向它。只要狗的牽繩脫落,狗就會跑掉,不管有多少小孩在看着它。
只要最后一個strong型指針不再指向對象,那么對象就會被釋放,同時所有的weak型指針都將會被清除。
///////////////////////////////////////////////////////////////////////////////////////////////
100.私有api與 公開api的區別
iPhone中的API除了公開的API:Published API外(或者叫文檔中記錄的API:Documented API),還有兩類API:私有API:Private API和未公開的API:UnPublished API(或者叫文檔中未記錄的API:Undocumented API)。其中私有API是指放在PrivateFrameworks框架中的API,未公開的API是指雖然放在Frameworks框架中,但是卻沒 有在蘋果的官方文檔中有使用說明、代碼介紹等記錄的API。后兩種API是有區別的,按蘋果的說法,未公開的API是還不夠成熟,可能還會變動的API, 等完全成型了后會變成公開的API,但是目前不對其提供承諾,就是系統版本升級后可能會失效。而私有API是蘋果明確不能使用的API。雖然兩者有所區 別,但是在具體使用方法上是類似的。
如何理解 動畫
7:assign是指針賦值,不對引用計數操作,使用之后如果沒有置為nil,可能就會產生野指針;而weak一旦不進行使用后,永遠不會使用了,就不會產生野指針
8:1)嘗試使用Xcode的轉換工具
2)在編譯選項中,為MRC的程序添加-fno-objc-arc標記,表明在編譯時,該文件用用MRC編譯
3)講MRC的第三方庫直接編譯成靜態庫使用
9:Object-c中沒有多繼承,Cocoa中所有的類都是NSObject的子類,多繼承在這里是用protocl委托代理來實現的
10:objective c中既有私有方法,也有私有變量。
先說私有方法,
由於Objective-C的動態消息傳遞機制,OC中不存在真正意義上的私有方法。
但是如果你不在.h文件中聲明,只在.m文件中實現,或在.m文件的Class Extension里聲明,那么基本上和私有方法差不多。
至於私有變量是可以通過@private來聲明的,例如:
@interface Sample : NSObject{
@private
NSString *tteesstt;
}
@property (nonatomic,strong) NSString *hoge;
- (void)foo;
@end
則tteesstt變量是私有的。而屬性hoge是默認公有。
現在Apple官方文檔里是用property比較多,直接定義instance variable(實例變量)少。將property定義到.m的Class Extension(類擴展)也基本上和私有變量差不多。
簡而言之,將你希望公有的放到.h文件,私有的放到.m文件。在import時只import .h文件(.m文件也是可以import的,但是我們一般不這么做)。
11、#import"".h和@class+類名的區別
1.import會包含這個類的所有信息,包括實體變量和方法,而@class只是告訴編譯器,其后面聲明的名稱是類的名稱,至於這些類是如何定義的,暫時不用考慮,后面會再告訴你。
2.在頭文件中, 一般只需要知道被引用的類的名稱就可以了。 不需要知道其內部的實體變量和方法,所以在頭文件中一般使用@class來聲明這個名稱是類的名稱。 而在實現類里面,因為會用到這個引用類的內部的實體變量和方法,所以需要使用#import來包含這個被引用類的頭文件。
3.在編譯效率方面考慮,如果你有100個頭文件都#import了同一個頭文件,或者這些文件是依次引用的,如A–>B, B–>C, C–>D這樣的引用關系。當最開始的那個頭文件有變化的話,后面所有引用它的類都需要重新編譯,如果你的類有很多的話,這將耗費大量的時間。而是用@class則不會。
4.如果有循環依賴關系,如:A–>B, B–>A這樣的相互依賴關系,如果使用#import來相互包含,那么就會出現編譯錯誤,如果使用@class在兩個類的頭文件中相互聲明,則不會有編譯錯誤出現。
所以,一般來說,@class是放在interface中的,只是為了在interface中引用這個類,把這個類作為一個類型來用的。 在實現這個接口的實現類中,如果需要引用這個類的實體變量或者方法之類的,還是需要import在@class中聲明的類進來.
12、請簡述頁面傳值都有哪些實現方式
代理、block、通知、屬性傳值、單例傳值、NSUserDefault
13、請簡述深拷貝和淺拷貝的區別
淺拷貝只復制對象的本身,對象里的屬性、包含的對象不做復制,源對象和副本指向的是同一個對象,對象的引用計數器+1,其實相當於做了一次retain操作
深拷貝則復制對象本身,對象的屬性也會復制一份。源對象和副本指向的是不同的兩個對象,源對象引用計數器不變,副本計數器設置為1
只有不可變對象創建不可變副本才是淺拷貝,其他都是深拷貝
14、系統中有哪些對象是單例
UIApplication(應用程序實例)
NSNotificationCenter(消息中心):
NSFileManager(文件管理):
NSUserDefaults(應用程序設置):
NSURLCache(請求緩存):
NSHTTPCookieStorage(應用程序cookies池):
15、請簡述你對MVC設計模式的理解
使用了MVC的應用程序被分為3個核心部件:視圖(View)、模型(Model)、控制器(Controller)。他們各司其職,既分工明確又相互合作。
Model:持有我們應用程序的數據,和定義怎么操縱它、
View:處理用戶的操作和展示Model
Controller:它的作用是協調View和Model把數據展示到View上
Controller可以直接和Model通信,也可以直接和View通信。Model和View永遠不能直接通信
16、iOS中哪些技術符合觀察者模式
在iOS開發中,會接觸到的經典觀察者模式的實現方法有NSNotificationCenter,KVO,Delegate等
17、什么是工廠方法?在基類中定義創建對象的一個接口,讓子類決定實例化那個類,工廠方法讓一個類的實例化延遲到子類中進行。工廠方法要解決的問題的對象的創建 時機,它提供了一種拓展的策略,很好的符合了開放封閉原則,工廠方法也叫作虛構造器。
18、什么是代理模式,實現代理需要注意什么
在項目中我們經常會用到代理的設計模式,這是ios的一種消息傳遞方式,也可以通過這種方式來傳遞一些參數,ios中對代理支持的很好,有代理對象、委托者、協議三部分組成。
協議:用來指定代理雙方可以做什么,必須做什么;
代理:根據指定的協議,完成委托方需要實現的功能;
委托:根據指定的協議,指定代理去完成什么功能
19 、請簡述StoryBoard和Xib的聯系和區別
聯系:
都用來描述軟件界面
都用Interface Builder工具來編輯
區別:
Xib是輕量級的,用來描述局部的UI界面
Storyboard是重量級的,用來描述整個軟件的多個界面,並且能展示多個界面之間的跳轉關系
20、請簡述UITableView對Cell的重用機制
UITableView維護了一個復用隊列,當Cell從屏幕上消失時,就會進入復用隊列。下一個Cell要顯示的時候通過復用id查詢在復用隊列是否有同一類型的Cell,若有取出來復用,若沒有就會重新創建一個Cell。重用機制通過對Cell的重復使用,來減少內存的使用。
21 、如何用UIScrollView實現無限加載多張圖片
創建一個UIScrollView,高度為屏幕的高度,寬度為三倍的屏幕寬度,設置為按屏幕滑動,設置偏移量(屏幕寬度,0)。第一個屏幕寬度和第三個屏幕寬度貼一個UIImageView顯示圖片的前一張和后一張,中間貼一個UIScrollView,大小為屏幕的大小,在上面貼一個UIImageView顯示要顯示的圖片。當向左滑動,通過UIScrollView的代理方法,檢測到之后將第一個屏幕寬度和第三個屏幕寬度上的UIImageView改為圖片的前一張和后一張,中間scrollview上的UIImageView上的圖片改為當前圖片,同時設置最外部的UIScrollView的偏移量為(屏幕寬度,0);向右滑動與向左滑動同理。
22、請簡述視圖控制器的生命周期
1、alloc 創建對象,分配空間
2、init 初始化對象
3、loadView 從xib中載入視圖
4、viewDidLoad 載入完成,可以自定義數據和控件了
5、viewWillAppear 視圖將要出現在屏幕上之前
6、viewDidAppear 視圖已經出現在屏幕上
7、viewWillDisappear 視圖將要消失
8、viewDidDisappear 視圖已經消失
9、銷毀
23 、UITableView有哪些優化方式
1、 提前計算並緩存好高度(布局),因為heightForRowAtIndexPath:是調用最頻繁的方法;
2、異步繪制,遇到復雜界面,遇到性能瓶頸時,可能就是突破口;
3、滑動時按需加載,這個在大量圖片展示,網絡加載的時候很管用
4、Cell的復用
5、盡量少使用或者不用透明的圖層
6、用異步加載數據,緩存請求結果
7、減少subView的數量
8、異步刷新
9、提前注冊
24 、請簡述iOS中的事件傳遞機制
點擊一個UIView或產生一個觸摸事件A,這個觸摸事件A會被添加到由UIApplication管理的事件隊列中(即,首先接收到事件的是UIApplication)。
UIApplication會從事件對列中取出最前面的事件(此處假設為觸摸事件A),把事件A傳遞給應用程序的主窗口(keyWindow)。
窗口會在視圖層次結構中找到一個最合適的視圖來處理觸摸事件。
事件交由第一響應者對象處理,如果第一響應者不處理,事件被沿着響應鏈向上傳遞,交給下一個響應者,直到事件被丟棄
25 、UITableView中有哪些必須要實現的數據源的方法
1、每組的行數 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
2、每行的cell -(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
26 、請簡述Http協議中get請求和post請求的區別
get和post的主要區別表現在數據傳遞上
get: 1、在請求url后面以?的形式跟上發給服務器的參數,多個參數之間用&隔開,比如http://www.test.com/login?username=123&pwd=234&type=JSON
2、由於瀏覽器和服務器對URL長度有限制,因此在URL后面附帶的參數是限制的,通常不能超過1kb
post:1、發給服務器的參數全部放在請求體中
2、理論上,POST傳遞的數據量沒有限制(具體還得看服務器的處理能力)
選擇:1)、如果要傳遞大量數據,比如文件上傳,只能用post請求
2).get的安全性比post要差些,如果包含機密\敏感信息,建議用post
3).如果僅僅是索取數據(數據查詢),建議用get
4).如果是增加、修改、刪除數據,建議使用post
27 、請簡述你對異步請求數據的理解
異步請求:通過兩個線程調用服務,一個線程發送,一個線程接受
請求行為在后台,不會導致頁面假死
28.iOS中哪些技術可以實現開辟線程,他們之間的聯系和區別是什么?
答:創建方式:
NSThread,NSOperation,GCD。
聯系:
三種編程方式都是針對線程操作來講的,從上到下,抽象度層次是從低到高的,抽象度越高的使用越簡單
區別:
•NSThread:
–優點:NSThread 比其他兩個輕量級,使用簡單
–缺點:需要自己管理線程的生命周期、線程同步、加鎖、睡眠以及喚醒等。線程同步對數據的加鎖會有一定的系統開銷
•NSOperation:
–不需要關心線程管理,數據同步的事情,可以把精力放在自己需要執行的操作上
–NSOperation是面向對象的,基於OC語言實現的API。兩種默認實現:NSInvocationOperation 和 NSBlockOperation。
•GCD:
–Grand Central Dispatch是由蘋果開發的一個多核編程的解決方案。iOS4.0+才能使用,是替代NSThread, NSOperation的高效和強大的技術
–GCD是基於C語言的API,提供了非常多強大的函數。GCD會自動管理線程的生命周期(創建線程、調度任務、銷毀線程)。程序員只需要告訴GCD想要執行什么任務,不需要編寫任何線程管理代碼。我們在編寫GCD相關代碼的時候,面對的函數,而不是方法。GCD中的函數大多數都以dispatch開頭。
29.NThread中線程是如何進行通信的?
答:線程間通信:在1個進程中,線程往往不是孤立存在的,多個線程之間需要經常進行通信
線程間通信的體現
1個線程傳遞數據給另1個線程
在1個線程中執行完特定任務后,轉到另1個線程繼續執行任務
線程間通信常用方法
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;
舉例下載圖片
// 在子線程中調用download方法下載圖片
[self performSelectorInBackground:@selector(download) withObject:nil];
-(void)download
{…//圖片下載完成
//2.回到主線程中設置圖片
//第一種方式
// [self performSelectorOnMainThread:@selector(settingImage:) withObject:image waitUntilDone:NO];
//第二種方式
// [self.imageView performSelector:@selector(setImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:NO];
//第三種方式
[self.iconView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];
}
GCD的線程通信
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 執⾏耗時的異步操作...
dispatch_async(dispatch_get_main_queue(), ^{
// 回到主線程,執⾏UI刷新操作
});
});
30.GCD中有哪些創建線程的方式
GCD全稱 Grand Central Dispatch,可稱為大中央調度。實際上GCD是管理着一個線程池,如何創建線程,如何回收線程,以及分配多少個線程,這些都是GCD來控制的。 在開發中,程序員是不用操作線程的相關事情,程序員只需要把應該做的 操作 放到相應的 隊列 里面即可。
在 GCD 中,加入了兩個非常重要的概念: 任務 和 隊列。
任務:即操作,GCD 中就是一個 Block。任務有兩種執行方式: 同步執行 和 異步執行。
同步(sync) 和 異步(async) 的主要區別在於會不會阻塞當前線程,直到 Block 中的任務執行完畢!
如果是 同步(sync) 操作,它會阻塞當前線程並等待 Block 中的任務執行完畢,然后當前線程才會繼續往下運行。
如果是 異步(async)操作,當前線程會直接往下執行,它不會阻塞當前線程。
隊列:用於存放任務。一共有兩種隊列, 串行隊列 和 並行隊列。
串行隊列 中的任務會根據隊列的定義 FIFO 的執行,一個接一個的先進先出的進行執行。
並行隊列的任務,GCD 也會 FIFO的取出來,但不同的是,它取出來一個就會放到別的線程,然后再取出來一個又放到另一個的線程。
隊列與線程管理:
三大隊列介紹種類:
一、主線程的Main queue,通過dispatch_get_main_queue獲取。
二、並行隊列global dispatch queue,通過dispatch_get_global_queue獲取,由系統創建(不需要開發人員去創建)三個不同優先級的dispatch queue。並行隊列的執行順序與其加入隊列的順序相同。
三、串行隊列serial queues一般用於按順序同步訪問,可創建任意數量的串行隊列,各個串行隊列之間是並發的。一般用dispatch_queue_create來進行創 建,非arc的情況下需要用戶手動來釋放隊列,可能會有人說,既然隊列也是一種對象,可以創建和釋放,那一定會有引用計數器了,是的,可以使用函數 dispatch_retain和dispatch_release來增加或者減少引用計數器。
兩種提交 job的方式:dispatch_async和dispatch_sync,分別是異步執行和同步執行,兩者之前的區別在於,前者在把任務提交到隊列執行 不會造成阻塞,而后者后面的代碼塊需要等到隊列中的任務執行完成后才可以執行。
1. //主線程異步執行
dispatch_async(dispatch_get_main_queue(), ^{ 。。。});
3. //主線程同步執行
dispatch_sync(dispatch_get_main_queue(), ^{。。。});
31,iOS中有哪些技術可以保證線程安全
增加互斥鎖。有效防止因多線程搶奪資源造成的安全問題。線程同步,多條線程按順序地執行任務。hu互斥鎖,就是使用了線程同步技術。
atomic加鎖。
32,ASIHttpRequest的父類是什么
NSOperation
33,請簡述AFNetWorking的實現原理
全稱是AFNetworking
雖然運行效率沒有ASI高,但是使用比ASI簡單
是對NSURLConnection和NSURLSession的各自的一層包裝
AFN的內部中的RunLoop
AFN內部開了一條專門用來訪問網絡請求的線程
在這個開線程的方法中,他把方法和dispatch_once都用static修飾了下
以保證這個方法的安全性以及只開辟一塊內存空間,而且保證他線程不死
在這個方法中他會調用另一個網絡請求入口的方法
在這個入口方法中他會創建一個RunLoop
然后添加一個NSMachPort端口,目的是為了讓他里面有Source(因為有了Source的RunLoop才能真正跑起來)
然后啟動RunLoop,通過RunLoop在里面不斷的循環,不斷的發送消息,讓他做事情.
34.你如何理解Block,Block有什么用途
block是對象,它封裝了一段代碼,這段代碼可以在任何時候執行。
block可以作為函數參數或者函數的返回值,而其本身又可以帶輸入參數或返回值。它和傳統的函數指針很類似,但是有區別:block是inline的,並且它對局部變量是只讀的。
35.請簡述TCP和UDP的區別
TCP(Transmission Control Protocol,傳輸控制協議)是基於連接的協議,也就是說,在正式收發數據前,必須和對方建立可靠的連接
UDP(User Data Protocol,用戶數據報協議)是與TCP相對應的協議。它是面向非連接的協議,它不與對方建立連接,而是直接就把數據包發送過去!
區別
是否連接 :面向連接 面向非連接
傳輸可靠性:可靠 不可靠
應用場合 :傳輸大量數據 少量數據
速度 :慢 快
36.請問怎樣保證定位更省電
開啟API並獲取到位置信息后,就手動stop()。
37 、請簡述SDWebImage的實現原理
SDWebImage 中為 UIView 提供了一個分類叫做 WebCache, 這個分類中有一個最常用的接口,sd_setImageWithURL:placeholderImage:, 這個分類同時提供了很多類似的方法, 這些方法最終會調用一個同時具有 optionprogressBlock completionBlock 的方法, 而在這個類最終被調用的方法首先會檢查是否傳入了 placeholderImage 以及對應的參數, 並設置 placeholderImage.
然后會獲取 SDWebImageManager 中的單例調用一個 downloadImageWithURL:... 的方法來獲取圖片, 而這個 manager 獲取圖片的過程有大體上分為兩部分, 它首先會在 SDWebImageCache 中尋找圖片是否有對應的緩存, 它會以 url 作為數據的索引先在內存中尋找是否有對應的緩存, 如果緩存未命中就會在磁盤中利用 MD5 處理過的 key 來繼續查詢對應的數據, 如果找到了, 就會把磁盤中的緩存備份到內存中.
然而, 假設我們在內存和磁盤緩存中都沒有命中, 那么 manager 就會調用它持有的一個 SDWebImageDownloader 對象的方法downloadImageWithURL:... 來下載圖片, 這個方法會在執行的過程中調用另一個方法addProgressCallback:andCompletedBlock:forURL:createCallback: 來存儲下載過程中和下載完成的回調, 當回調塊是第一次添加的時候, 方法會實例化一個 NSMutableURLRequest 和 SDWebImageDownloaderOperation, 並將后者加入 downloader 持有的下載隊列開始圖片的異步下載.
而在圖片下載完成之后, 就會在主線程設置 image 屬性, 完成整個圖像的異步下載和配置.
38、請簡述xml和json數據各有什么優勢
XML 更適合數據定義,數據存儲。它對數據的表達使得這個數據脫離你程序的上下文仍然存在意義並且可以被解讀。所以 XML 適合作為配置文件,以及數據存儲,存盤文件格式等等。
JSON 更適合數據傳輸。JSON數據體積相對於XML小,對於傳輸而言,雙方必然需要遵循協商好的協議,因而 JSON 對數據的表達並不需要在數據傳輸的雙方以外仍然具有可解讀的意義,只要傳輸的雙方能讀懂即可。
39、請簡述線程和進程有什么聯系和區別
定義:進程是系統進行資源分配和調度的一個獨立單位;
線程是進程的實體,是cpu調度和分派的基本單位
關系:一個線程可以創建和撤銷另一個線程;同一個進程中的多個線程之間 可以並發執行。
區別:1)簡而言之,一個程序至少有一個進程,一個進程至少有一個線程
2)線程的划分尺度小於進程,使得多線程程序的並發性高
3)進程在執行過程中擁有獨立的內存單元,而多個線程共享內存, 從而極大的提高了程序的運行效率
4)線程不能獨立執行,必須依存於應用程序中,由應用程序提供多個 線程執行控制
5)多線程的意義在於一個應用程序中,有多個執行部分可以同時執 行。但操作系統不會將多線程看做多個應用,來實現進程的調度和管 理及資源分配。
40、請簡述NSUserDefaults的使用場景和使用注意事項
NSUserDefaults支持的數據類型有:NSNumber(NSInteger.float.double),NSString,NSDate,NSArray,NSDictionary,BOOL,如果你想存儲其他類 型的對象,你要將其歸檔並創建一個NSData來實現存儲。如需數據永久保存到NSUserDefaults,只需要簡單的儲存成鍵值對,注意保存時的key的唯一性,如對相同key賦值則會覆蓋以前的數據。
41、iOS中數據庫使用什么技術實現的
sqlite和CoreData
常用數據庫: SQLServer 2000-----保存游戲的所有用戶的信息
Oracle
mysql------網上php網站使用較多
特點: 網絡數據庫, 支持的功能多, 程序比較大
移動開發常用: sqlite數據庫
特點: 足夠小, 足夠快(本地數據庫), 使用比較簡單
常用軟件: MesaSQlite數據庫操作軟件
數據庫操作語言: SQL(結構化查詢語言)
常用開源庫: FMDB
CoreData是iOS開發中經常使用的數據持久化的技術。但其操作過程稍微繁瑣,即使你只是實現簡單的存取,不涉及請求優化,也要進行許多配置工作,代碼量在動輒幾十行,對新手來說也需要較大時間成本。
MagicalRecord是OC的一個庫,協助方便CoreData的工作。其吸收了Ruby on Rails的Active Record模式,目標是:
簡化Core Data相關代碼
允許清晰,簡單,單行獲取
當需要優化請求的時候,仍然允許修改NSFetchRequest
安裝
1、在 github 上下載MagicalRecord
2、下載完成,將MagicalRecord 文件夾拖到Xcode中,添加進項目。添加CoreData framework。
3、在PCH文件中添加 CoreData+MagicalRecord.h
4、Option: 如果你在使用MagicalRecord方法的時候不想帶MR_ 前綴,e.g. 直接用findAll 代替 MR_findAll,就在PCH中在CoreData+MagicalRecord.h之前增加 #defin MR_SHORTHAND 即可。
環境需求
MagicalRecord 需要的環境:
iOS 5.x 及以上, Mac OS 10.7及以上
ARC
iOS4,無ARC ,可以使用兼容版本,1.8.3
用法
創建Model
創建一個Model.xcdatamodeld ,添加一個Person Entity,添加age firstname lastname 三個屬性。最后使用Editor > Create NSManagedObject Subclass ORM生成Person類。
初始化
在AppDelegate中:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
[MagicalRecord setupCoreDataStackWithStoreNamed:@"Model.sqlite"];
// ...
return YES;
}
- (void)applicationWillTerminate:(NSNotification *)aNotification
{
[MagicalRecord cleanUp];
}
這樣就搞定初始化啦!!
增
Person *person = [Person MR_createEntity];
person.firstname = @"Frank";
person.lastname = @"Zhang";
person.age = @26;
[[NSManagedObjectContext MR_defaultContext] MR_save];
查
//查找數據庫中的所有Person。
NSArray *persons = [Person MR_findAll];
//查找所有的Person並按照first name排序。
NSArray *personsSorted = [Person MR_findAllSortedBy:@"firstname" ascending:YES];
//查找所有age屬性為25的Person記錄。
NSArray *personsAgeEuqals25 = [Person MR_findByAttribute:@"age" withValue:[NSNumber numberWithInt:25]];
//查找數據庫中的第一條記錄
Person *person = [Person MR_findFirst];
改
Person *person = ...;//此處略
person.lastname = object;
[[NSManagedObjectContext MR_defaultContext] MR_save];
刪
Person *person = ...;//此處略
[person MR_deleteEntity];
[[NSManagedObjectContext MR_defaultContext] MR_save];
more
MagicalRecord 官方
Magical Record入門教程
Using CoreData with MagicalRecord
Magical Record: how to make programming with Core Data pleasant
來自:http://www.cnblogs.com/mybkn/p/3328183.html
42,請簡述什么是主鍵、什么是外鍵
主關鍵字是表中的一個或多個字段,它的值用於唯一地標識表中的某一條記錄。主關鍵字是被挑選出來,主關鍵字 作表的行的唯一標識的候選關鍵字。
如果公共關鍵字在一個關系中是主關鍵字,那么這個公共關鍵字被稱為另一個關系的外鍵。
43,iOS中如何實現數據模型的存儲
(1) 用戶默認設置 – 這種情況通常不需要用戶干預,如游戲通關信息,Video
播放記錄,或者 App 退出之后,下次進入時,希望恢復到退出時的情況。
(2) 設置束(Settings Bundle)-- 提供了一個通過 iPhone、iPad的設置
(Settings)應用程序進行配置的接口。
(3) 直接訪問文件系統 – 讀寫屬於當前 App 的 iOS 文件系統部分的文件。
(4) SQLite 數據庫 -- 是嵌入式的和輕量級的 SQL 數據庫,SQLite 是由 C實現的。
(5) 遠端數據庫 – 這個一般由 App 調用遠端的 RESTFul WCF 服務,將JSON
或者 XML 數據傳遞給遠端的 Web 服務,讀寫數據庫的邏輯完全在 Web 服 務端實現。比如,用戶在iPhone/iPad 終端 App 提交了訂單,訂單數據當然需要寫入遠端 SQL Server 或Oracle 數據庫
44,請簡述iOS的沙盒機制
出於安全的目的,應用程序只能將自己的數據和偏好設置寫入到幾個特定的位置上。當應用程序被安裝到設備上時,系統會為其創建一個家目錄,這個家目錄就是應用程序的沙盒。
45,如何實現真機調試
准備工作:
• 一個蘋果開發者賬號
• 一個應用ID,對應你想要調試的項目,注意申請App ID時填寫bundle identifier必須與你的項目中的bundle identifier完全對應
• 一台iOS設備,其操作系統版本要與你使用的SDK版本相匹配
第一步:獲取設備ID
打開你的項目,然后將設備接入到你的開發機中,打開organizer,在Device tab頁下可以看到你剛剛接入的設備
第二部:添加設備
打開開發者中心的設備管理頁面,點擊Add Devices 按鈕,將剛剛粘貼的設備ID輸入,並為此設備命名,注意,每一個個人開發者賬號最多只能添加一百台設備
第三部:生成Provisioning File
同樣在開發者中心,點擊Provision File管理界面,點擊New Profile按鈕,為Provisioning file命名,選擇我們要調試的APP Id, 並將我們想要進行調試的設備,這里的設備可以多選。點擊Submmit,過一段時間后就會,pending狀態的Provsioning file 變成Active狀態,便可以下載了。
第四步,導入Provisioning File
雙擊Provisioning File導入,此時會彈出Organizer,並顯示所有的已經導入的Provisioning File,如果導入的Provisioning File有效,那么其后的圖標會顯示為綠色。導入成功后,在Organizer-> device中找到我們添加的設備,點擊“Delopyment for XXX”按鈕,中途會出現若干對話框輸入證書對應的密碼,取消即可,至此,設備的設置已經完成,如果正常,設備名后的燈狀標示會編程綠色。
第五步:代碼簽名與運行
點擊項目名,在出現的界面中會分別看到Projects和Targets兩個tab 頁。分別點擊Project與Targets,將Build Setting-》Code Signing中的Debug部分簽名由Don't Sigining設為我們導入的Provisioning File代表的選項。注意Projects與Targets連個都要設置。將運行設備設為我們剛剛添加的設備,Command + R,程序就可以在設備上運行。
后記:常見問題
整個過程中比較容易出的問題有:
• 生成Provisioning File 是沒有添加正確的設備,注意所有需要調試的設備都要勾選
• 代碼沒有選擇簽名,或選擇了錯誤的簽名選項,或只對Project或Targets中的一個進行了簽名設置
• 真機調試需要的Provisioning File要為Development版本的(默認),如果只有Distribution版本的是無法調試的
46、如何查找項目中的內存泄露
1.靜態分析
通過靜態分析我們可以最初步的了解到代碼的一些不規范的地方或者是存在的內存泄漏,這是我們第一步對內存泄漏的檢測。當然有一些警告並不是我們關心的可以略過。
2.通過instruments來檢查內存泄漏
這個方法能粗略的定位我們在哪里發生了內存泄漏。方法是完成一個循環操作,如果內存增長為0就證明我們程序在該次循環操作中不存在內存泄漏,如果內存增長不為0那證明有可能存在內存泄漏,當然具體問題需要具體分析。
3.代碼測試內存泄漏
在做這項工作之前我們要注意一下,在dealloc的方法中我們是否已經釋放了該對象所擁有的所有對象。觀察對象的生成和銷毀是否配對。准確的說就是init(創建對象的方法)和dealloc是否會被成對觸發(簡單說來就是走一次創建對象就有走一次dealloc該對象)。
47、項目中的支付環節如何實現的
這里以支付寶為例:
1.與支付寶進行去簽約,獲得商戶ID(partner)和賬號ID(seller)
2.下載響應的公鑰、私鑰(加密簽名用)
3.下載支付寶SDK
4.生成訂單信息
5.調用支付寶客戶端,用支付寶客戶端跟支付寶安全服務區打交道
6.支付完畢返回支付結果給客戶端和服務器
48 如何實現項目上線到AppStore
第一步購買Apple開發者賬號,使用賬號登陸Apple官網,創建證書 下載證書,創建CSR文件,第二步 登陸https://itunesconnect.apple.com 創建應用程序信息,第三步打開你要上線的項目的工程文件 選中X-code 里的product->Archive。 打包你要上線的項目,然后等待蘋果公司審核,審核成功就能上線。
49 請簡述你在項目中遇到過哪些問題,如何解決的
遇到過很多的問題,比如1第三方庫崩潰,解決辦法,首先查出哪個第三方庫崩潰,可以去github 上重新下載這個更新后的第三方庫。2有些項目經理需要你做出來的功能你不能實現,解決辦法:換一種思路去實現或者和項目經理溝通看有沒有其他可以代替這個功能而且你能做出來的或者去百度去github 上問問別人,總之一定要解決。。3Api問題,可以找服務器端的工作人員商量,可以自己下載別的第三方庫來解析這個Api。
50.請簡述你理解的內存管理。
創建對象並使用后需要釋放,否則會出現內存泄露。
內存管理分為手動內存管理MRC和自動內存管理ARC,
在手動內存管理機制下,如果使用alloc,copy(MutableCopy),retain一個對象時,在使用完畢需要向該對象發送release,或者autorelease消息來釋放這個對象,其他方法創建的對象不需要管理內存。
在自動內存管理機制下,系統維護的自動釋放池會自動處理。
51、如何實現流媒體格式的視頻邊播放,邊緩存?
1.需要在視頻播放器和服務器之間添加一層類似代理的機制,視頻播放器不再直接訪問服務器,而是訪問代理對象,代理對象去訪問服務器獲得數據,之后返回給視頻播放器,同時代理對象根據一定的策略緩存數據。
2.AVURLAsset中的resourceLoader可以實現這個機制,resourceLoader的delegate就是上述的代理對象。
3.視頻播放器在開始播放之前首先檢測是本地cache中是否有此視頻,如果沒有才通過代理獲得數據,如果有,則直接播放本地cache中的視頻即可。
52.請簡述你理解的面向對象思想。
(網絡簡述)
面向對象思想把整個世界看成由各種對象來組成的. 這些對象具有屬性和行為, OC中稱之為屬性和方法. 從最簡單的整數到復雜的飛機等均可看作對象, 它不僅能表示具體的事物, 還能表示抽象的規則, 計划或事件.
面向對象編程(Object Oriented Programming,OOP,面向對象程序設計)是一種計算是一種計算機編程范式, 它將對象作為問題空間的基本元素, 利用對象和對象之間的相互作用來設計程序.
(課件解釋)
1、對象是接收命令的基本單位,每個對象負責處理數據的某個方面,多個對象分工合作以完成復雜的功能。
2、生活邏輯的映射
53、如何設計一個緩存類?
1、設計一個CacheItem類,用來請求一個web連接,它的一個實例表示一個緩存項。這個CacheItem類,需要一個url創建一個NSURLConnection,去請求web資源。使用CacheItem類主要用來請求web資源。
2、在NSURLConnection開始請求之前,調用CachedDownloadManager類,來搜索和管理本地的緩存文件。將緩存文件的情況保存到一個字典類中。
3、如果這個文件已經被下載,而且沒有過期,則從本地獲取文件的數據。如果文件已經過期,則重新下載。我們通過download:urlMustExpireInSeconds:updateExpiryDateIfInCache方法來實現,
詳情參考http://w11h22j33.iteye.com/blog/1420733
54—談談對藍牙技術的理解
藍牙是一種無線技術標准,可實現固定設備、移動設備和樓宇個人域網之間的短距離數據交換。主從關系
藍牙技術規定每一對設備之間進行藍牙通訊時,必須一個為主角色,另一為從角色,才能進行通信,通信時,必須由主端進行查找,發起配對,建鏈成功后,雙方即可收發數據。
55—iOS8.0有什么新特征
1、支持第三方鍵盤 2、自帶網頁翻譯功能(即在線翻譯) 3、指紋識別功能開放:第三方軟件可以調用 4、Safari瀏覽器可直接添加新的插件。 5、可以把一個網頁上的所有圖片打包分享到Pinterest、 6、支持第三方輸入法:將是否授權輸入法的選擇留給用戶 7、Home Kit智能家居 :可以利用iPhone對家居,如燈光等進行控制 8、3D圖像應用Metal:可以更充分利用CPU和GPU的性能 9、引入全新基於C語言的編程語言Swift:更快、更安全、更好的交互、更現代 10、 Xcode更新 11、相機和照片API也實現開放
56—懶加載
1.懶加載基本
懶加載——也稱為延遲加載,即在需要的時候才加載(效率低,占用內存小)。所謂懶加載,寫的是其get方法.
注意:如果是懶加載的話則一定要注意先判斷是否已經有了,如果沒有那么再去進行實例化
2.使用懶加載的好處:
(1)不必將創建對象的代碼全部寫在viewDidLoad方法中,代碼的可讀性更強
(2)每個控件的getter方法中分別負責各自的實例化處理,代碼彼此之間的獨立性強,松耦合
57— 在ARC下發生內存泄露的解決方案
1,循環參照
A有個屬性參照B,B有個屬性參照A,如果都是strong參照的話,兩個對象都無法釋
解決方案 把其中一個屬性的strong改為assign即可。
2,死循環
如果某個ViewController中有無限循環,也會導致即使ViewController對應的view關掉了,ViewController也不能被釋放。
這種問題常發生於animation處理。
解決辦法 在ViewController關掉的時候,停止這個animation。
-(void)viewWillDisappear:(BOOL)animated {
[self.view.layer removeAllAnimations];
}
3、當一個對象存入到集合中的時候,默認會保存它的強指針,如果最后不對這個集合進行清空操作,一樣會有內存溢出的情況
Person * p = [[Person alloc] init];
NSMutableArray * arr = [[NSMutableArray alloc] init];
[arr addObject:p];
把對象從集合中移除的時候,也會釋放掉這個對象的強指針
[arr removeObject:p];
或者[arr removeAllObjects];
而接下來才是重點:
arr = nil;//如果不進行賦值為nil的操作,一樣存在內存溢出的現象,賦值為nil系統會對其進行清空所有強指針的操作.
p = nil;
解決方案 1、建議你找到泄露的那個對象,將其賦值為nil,因為ARC里面,一旦對象沒有指針指向,就會馬上被釋放。
58 —GCD(異步Block中的self.的處理)
用__weak把self重新引用一下就行了 ,像這樣:
__weak ViewController *weakSelf = self;
59- APNS 推送的實現過程
首先應用發送通知,系統彈出提示框詢問客戶是否允許,當用戶允許后像蘋果服務器(APNS)請求deviceToken,並由蘋果服務器發送給自己的應用,自己的應用將DeviceToken發送給自己的服務器,自己的服務器想要發送網絡推送時將deviceToken以及想要推送的信息發送給蘋果服務器,蘋果服務器將信息發送給應用.
60—添加NSNotificationCenter監聽,其后面的object的意義是什么?
用NSNotificationCenter添加監聽者,其后面的object的意義是:監聽同一條通知的多個觀察者,在通知到達時,他們執行回調的順序是不確定的,所以我們不能去假設操作的執行會按照添加觀察者的順序來執行.
61、iOS的加密方式以及優劣
1,MD5加密是最常用的加密方法之一,是從一段字符串中通過相應特征生成一段32位的數字字母混合碼。MD5主要特點是 不可逆
2,在MIME格式的電子郵件中,base64可以用來將binary的字節序列數據編碼成ASCII字符序列構成的文本。使用時,在傳輸編碼方式中指定base64。使用的字符包括大小寫字母各26個,加上10個數字,和加號“+”,斜杠“/”,一共64個字符,等號“=”用來作為后綴用途。
base64編碼后的數據比原始數據略長,為原來的4/3
RSA非對稱加密算法 非對稱加密算法需要兩個密鑰非對稱密碼體制的特點:算法強度復雜、安全性依賴於算法與密鑰但是由於其算法復雜,而使得加密解密速度沒有對稱加密解密的速度快 對稱密碼體制中只有一種密鑰,並且是非公開的
62、論Socket和http協議的區別
HTTP:超文本傳輸協議,首先它是一個協議,並且是基於TCP/IP協議基礎之上的應用層協議。TCP/IP協議是傳輸層協議,主要解決數據如何在網絡中傳輸。HTTP是基於請求-響應形式並且是短連接,並且是無狀態的協議
Socket:Socket 不屬於協議范疇,而是一個調用接口(API),
Socket是對TCP/IP協議的封裝,通過調用Socket,才能使用TCP/IP協議。Socket 連接是長連接,理論上客戶端和服務器端一旦建立連接將不會主動斷開此連接。Socket連接屬於請求-響應形式,服務端可主動將消息推送給客戶端
63、 kvo/kvc之間的關系
KVC 與 KVO 是 Objective C 的關鍵概念。KVC,即是指 NSKeyValueCoding,一個非正式的 Protocol,提供一種機制來間接訪問對象的屬性。KVO 就是基於 KVC 實現的關鍵技術之一。從最基礎的層次上看,KVC 有兩個方法:一個是設置 key 的值,另一個是獲取 key 的值。比如:
[p valueForKeyPath:@"spouse.name"];
相當於這樣……
[[p valueForKey:@"spouse"] valueForKey:@"name"];
Key-Value Observing (KVO) 建立在 KVC 之上,它能夠觀察一個對象的 KVC key path 值的變化。舉個例子,用代碼觀察一個 person 對象的 address 變化,以下是實現的三個方法:
• watchPersonForChangeOfAddress: 實現觀察
• observeValueForKeyPath:ofObject:change:context: 在被觀察的 key path 的值變化時調用。
• dealloc 停止觀察
它通過 key path 觀察對象的值,當值發生變化的時候會收到通知。
64、數據持久化機制
1.屬性列表
2.對象歸檔
3.數據庫存儲(SQLite3)
4.蘋果公司提供的持久性工具Core Data。
① 屬性列表文件是一種XML文件,Foundation框架中的數組和字典等都可以於屬性列表文件相互轉換。
NSArray類常用讀寫屬性列表文件的方法:+arrayWithContentsOfFile;-initWithContentsOfFile ;-writeToFile:atomically。
NSDictionary類常用讀寫屬性列表文件的方法:+dictionaryWithContentsOfFile;-initWithContentsOfFile;-writeToFile:atomically。
當然也可以通過代碼直接創建plist文件。
②對象歸檔是將對象歸檔以文件的形式保存到磁盤中(也稱為序列化,持久化),使用的時候讀取該文件的保存路徑讀取文件的內容(也稱為接檔,反序列化)。
簡單對象歸檔
使用兩個類:NSKeyedArichiver、NSKeyedUnarchiver
例子:使用兩個類:NSKeyedArichiver、NSKeyedUnarchiver
NSString *homeDirectory = NSHomeDirectory(); //獲取根目錄
NSString homePath = [homeDirectory stringByAppendingPathComponent:@"自定義文件名,如test.archiver"];
NSArray *array = @[@"abc", @"123", @12];
Bool flag = [NSKeyedArichiver archiveRootObject:array toFile:homePath];
if(flag) {
NSLog(@"歸檔成功!");
}
自定義內容歸檔
歸檔:
使用NSData實例作為歸檔的存儲數據
添加歸檔的內容---使用鍵值對
完成歸檔
解歸檔:
從磁盤讀取文件,生成NSData實例
根據NSData實例和初始化解歸檔實例
解歸檔,根據key訪問value
③上述方法都有一個致命的缺點,那就是都無法存儲大批量的數據,有性能的問題。
舉例:使用歸檔。
(1)數據的存取都必須是完整的,要求寫入的時候要一次性寫入,讀取的時候要一次性全部讀取,這涉及到應用的性能問題。
(2)如果有1000條數據,此時要把第1001條數據存入,那么需要把所有的數據取出來,把這條數據加上去之后,再存入。
創建步驟
1、創建一個簡單的View based application
2、選擇項目文件,然后選擇目標,添加libsqlite3.dylib庫到選擇框架
3、通過選擇" File-> New -> File... -> "選擇 Objective C class 創建新文件,單擊下一步
4、"sub class of"為NSObject",類命名為DBManager
5、選擇創建
6、更新DBManager,
④Core Data是蘋果官方推薦使用的數據持久化方式,在使用的過程中,不需要導入數據庫框架,也不需要使用sql語句操作數據庫,完全是按照面向對象的思想,使用實體模型來操作數據庫。在使用的過程中需要注意的是,如果模型發生了變化,可以選擇重新生成實體類文件,但是自動生成的數據庫並不會自動更新,需要考慮重新生成數據庫,並把之前數據庫中數據進行移植。Core Data能夠簡化操作,但是它不支持跨平台使用,如果想實現跨平台,就需要使用SQLite來進行數據持久化。
65、ios中bound 和frame區別
frame指的是:該View在父View坐標系統中的位置和大小。(參照點是父親的坐標系統)
bounds指的是:該View在本身坐標系統中的位置和大小。(參照點是本身坐標系統)
bounds大小改變 frame 也改變
66、服務器連接三次握手
在TCP/IP協議中,TCP協議提供可靠的連接服務,采用三次握手建立一個連接。
第一次握手:建立連接時,客戶端發送連接請求到服務器,並進入SYN_SEND狀態,等待服務器確認;
第二次握手:服務器收到客戶端連接請求,向客戶端發送允許連接應答,此時服務器進入SYN_RECV狀態;
第三次握手:客戶端收到服務器的允許連接應答,向服務器發送確認,客戶端和服務器進入通信狀態,完成三次握手。
(所謂的三次握手就是要有三次連接信息的發送/接收過程。TCP連接的建立需要進行三次連接信息的發送/接收。)
67、 GCD有哪三種隊列和用法
1. The main queue: 與主線程功能相同。實際上,提交至main queue的任務會在主線程中執行。main queue可以調用dispatch_get_main_queue()來獲得。因為main queue是與主線程相關的,所以這是一個串行隊列。
2. Global queues: 全局隊列是並發隊列,並由整個進程共享。進程中存在三個全局隊列:高、中(默認)、低三個優先級隊列。可以調用dispatch_get_global_queue(0,0)函數傳入優先級來訪問隊列。
3.用戶隊列: 用戶隊列 (GCD並不這樣稱呼這種隊列, 但是沒有一個特定的名字來形容這種隊列,所以我們稱其為用戶隊列) 是用函數 dispatch_queue_create(,)1.隊列名稱 2.隊列的類型 並行隊列DISPATCH_QUEUE_CONCURRENT 串行隊列DISPATCH_QUEUE_SERIAL
68.CALayer 和UiView和繪圖的Api的關系
兩者最大的區別是,圖層不會直接渲染到屏幕上,UIView是iOS系統中界面元素的基礎,所有的界面元素都是繼承自它。它本身完全是由CoreAnimation來實現的。它真正的繪圖部分,是由一個CALayer類來管理。UIView本身更像是一個CALayer的管理器。一個UIView上可以有n個CALayer,每個layer顯示一種東西,增強UIView的展現能力。
69、動畫矩陣變換算法
仿射是動畫基礎,不能熟練使用也肯定玩不好動畫特效的 。仿射變換AffineTransform,在iOS中他的實現類是CGAffineTransform和CATransform3D。
仿射變換的矩陣計算
仿射計算中,(以二維坐標為例,坐標點為x,y)我們設我們的坐標點矩陣為
A = [x y 1]
仿射變換基礎矩陣為:
//仿射基礎矩陣
B = [ ]
a b 0
c d 0
tx ty 1
[ ]
根據矩陣計算規則我們知道A x B的結果是一個1行3列的矩陣,設A x B得到的新矩陣C ,那么C的矩陣應該為
C = [ (a*x+c*y+tx) (b*x+d*y+ty) (1) ]
設C為 = [x' y' 1] , 那么可以得到
x' = a*x + c*y + tx
y' = b*x + d*y + ty
這步很關鍵。根據這個公式,那么仿射矩陣就可以分成5種分別對應
• 平移(Translation)
• 縮放(Scale)
• 翻轉(Flip)
• 旋轉(Rotation)
• 剪切(Shear)
平移(Translation)
//向右移動300的仿射效果
let translate = CGAffineTransformMakeTranslation(300, 0)
//使用仿射基礎方法CGAffineTransformMake ( CGFloat a, CGFloat b, CGFloat c, CGFloat d, CGFloat tx, CGFloat ty )
let translate = CGAffineTransformMake(1,0,0,1,300,0)
縮放(Scale)
代碼
//x和y都放大1倍
//let scaleAffine = CGAffineTransformMakeScale(2, 2)
//使用仿射基礎方法CGAffineTransformMake
let scaleAffine = CGAffineTransformMake(2,0,0,2,0,0)
剪切(Shear)
代碼
//使用仿射基礎方法CGAffineTransformMake,設置x和y都為0.5的斜切
//斜切效果只能用CGAffineTransformMake實現,但是通過CATransform3DMakeRotation可以有類似的效果
let shearAffine = CGAffineTransformMake(1,0.5,0.5,1,0,0)
旋轉(Rotation)
//仿射旋轉矩陣
[ ]
cosa sina 0
-sina cosa 0
0 0 1
[ ]
代碼
let rotation = CGAffineTransformMake(CGFloat( cos(M_PI_4) ), CGFloat( sin(M_PI_4) ), -CGFloat( sin(M_PI_4) ), CGFloat( cos(M_PI_4) ), 0, 0)
翻轉(Flip)
/Flip仿射,要是有3D去實現
let flip = CATransform3DMakeRotation(angle, x, y, z)
//示例
let flipX = CATransform3DMakeRotation(CGFloat(M_PI), 1, 0, 0)
let flipY = CATransform3DMakeRotation(CGFloat(M_PI), 0, 1, 0)
let flipZ = CATransform3DMakeRotation(CGFloat(M_PI), 0, 0, 1)
3D仿射變換
3D仿射在iOS中是通過CATransform3D實現的,它有着與CGAffineTrans類似的一組API,但他們有個重要的區別在於 CATransform3D的效果只能加在layer的transform屬性上 ,而CGAffineTransform直接加在View上
3D仿射常用的方法
//位移3D仿射
CATransform3DMakeTranslation
CATransform3DTranslation
//旋轉3D仿射
CATransform3DMakeRotation
CATransform3DRotation
//縮放3D仿射
CATransform3DMakeScale
CATransform3DScale
//疊加3D仿射效果
CATransform3DConcat
//仿射基礎3D方法,可以直接做效果疊加
CGAffineTransformMake (sx,shx,shy,sy,tx,ty)
/*
這個是一個初始化矩陣,帶入矩陣算法計算后的結構會得到
x'=x , y'=y , z'=z
它的作用是清除之前對矩陣設置的仿射效果,或者用來初始化一個原始無效果的仿射矩陣
[ 1 0 0 0 ]
[ 0 1 0 0 ]
[ 0 0 1 0 ]
[ 0 0 0 1 ]
*/
CATransform3DIdentity
//檢查是否有做過仿射3D效果
CATransform3DIsIdentity(transform)
//檢查是否是一個仿射3D效果
CATransform3DIsAffine(transform)
//檢查2個3D仿射效果是否相同
CATransform3DEqualToTransform(transform1,transform2)
//3D仿射效果反轉(反效果,比如原來擴大,就變成縮小)
CATransform3DInvert(transform)
//2D仿射轉換3D仿射
CATransform3DGetAffineTransform(transform)
CATransform3DMakeAffineTransform(transform)