鏈接:http://www.itdecent.cn/p/5d2163640e26
如何進(jìn)行網(wǎng)絡(luò)消息推送
一種是Apple自己提供的通知服務(wù)(APNS服務(wù)器)、一種是用第三方推送機(jī)制。
首先應(yīng)用發(fā)送通知,系統(tǒng)彈出提示框詢問用戶是否允許,當(dāng)用戶允許后向蘋果服務(wù)器(APNS)請求deviceToken,并由蘋果服務(wù)器發(fā)送給自己的應(yīng)用,自己的應(yīng)用將DeviceToken發(fā)送自己的服務(wù)器,自己服務(wù)器想要發(fā)送網(wǎng)絡(luò)推送時將deviceToken以及想要推送的信息發(fā)送給蘋果服務(wù)器,蘋果服務(wù)器將信息發(fā)送給應(yīng)用。
推送信息內(nèi)容,總?cè)萘坎怀^256個字節(jié);
iOS SDK本身提供的APNS服務(wù)器推送,它可以直接推送給目標(biāo)用戶并根據(jù)您的方式彈出提示。
優(yōu)點(diǎn):不論應(yīng)用是否開啟,都會發(fā)送到手機(jī)端;
缺點(diǎn):消息推送機(jī)制是蘋果服務(wù)端控制,個別時候可能會有延遲,因?yàn)樘O果服務(wù)器也有隊(duì)列來處理所有的消息請求;
第三方推送機(jī)制,普遍使用Socket機(jī)制來實(shí)現(xiàn),幾乎可以達(dá)到即時的發(fā)送到目標(biāo)用戶手機(jī)端,適用于即時通訊類應(yīng)用。
優(yōu)點(diǎn):實(shí)時的,取決于心跳包的節(jié)奏;
缺點(diǎn):iOS系統(tǒng)的限制,應(yīng)用不能長時間的后臺運(yùn)行,所以應(yīng)用關(guān)閉的情況下這種推送機(jī)制不可用。
網(wǎng)絡(luò)七層協(xié)議
應(yīng)用層:
1.用戶接口、應(yīng)用程序;
2.Application典型設(shè)備:網(wǎng)關(guān);
3.典型協(xié)議、標(biāo)準(zhǔn)和應(yīng)用:TELNET、FTP、HTTP
表示層:
1.數(shù)據(jù)表示、壓縮和加密presentation
2.典型設(shè)備:網(wǎng)關(guān)
3.典型協(xié)議、標(biāo)準(zhǔn)和應(yīng)用:ASCLL、PICT、TIFF、JPEG|MPEG
4.表示層相當(dāng)于一個東西的表示,表示的一些協(xié)議,比如圖片、聲音和視頻MPEG。
會話層:
1.會話的建立和結(jié)束;
2.典型設(shè)備:網(wǎng)關(guān);
3.典型協(xié)議、標(biāo)準(zhǔn)和應(yīng)用:RPC、SQL、NFS、X WINDOWS、ASP
傳輸層:
1.主要功能:端到端控制Transport;
2.典型設(shè)備:網(wǎng)關(guān);
3.典型協(xié)議、標(biāo)準(zhǔn)和應(yīng)用:TCP、UDP、SPX
網(wǎng)絡(luò)層:
1.主要功能:路由、尋址Network;
2.典型設(shè)備:路由器;
3.典型協(xié)議、標(biāo)準(zhǔn)和應(yīng)用:IP、IPX、APPLETALK、ICMP;
數(shù)據(jù)鏈路層:
1.主要功能:保證無差錯的疏忽鏈路的data link;
2.典型設(shè)備:交換機(jī)、網(wǎng)橋、網(wǎng)卡;
3.典型協(xié)議、標(biāo)準(zhǔn)和應(yīng)用:802.2、802.3ATM、HDLC、FRAME RELAY;
物理層:
1.主要功能:傳輸比特流Physical;
2.典型設(shè)備:集線器、中繼器
3.典型協(xié)議、標(biāo)準(zhǔn)和應(yīng)用:V.35、EIA/TIA-232.
對NSUserDefaults的理解
NSUserDefaults:系統(tǒng)提供的一種存儲數(shù)據(jù)的方式,主要用于保存少量的數(shù)據(jù),默認(rèn)存儲到library下的Preferences文件夾。
SDWebImage原理
調(diào)用類別的方法:
從內(nèi)存中(字典)找圖片(當(dāng)這個圖片在本次程序加載過),找到直接使用;
從沙盒中找,找到直接使用,緩存到內(nèi)存。
從網(wǎng)絡(luò)上獲取,使用,緩存到內(nèi)存,緩存到沙盒。
OC中是否有二維數(shù)組,如何實(shí)現(xiàn)二維數(shù)組
OC中沒有二維數(shù)組,可通過嵌套數(shù)組實(shí)現(xiàn)二維數(shù)組。
LayoutSubViews在什么時候被調(diào)用?
當(dāng)View本身的frame改變時,會調(diào)用這個方法。
深拷貝和淺拷貝
如果對象有個指針型成員變量指向內(nèi)存中的某個資源,那么如何復(fù)制這個對象呢?你會只是復(fù)制指針的值傳給副本的新對象嗎?指針只是存儲內(nèi)存中資源地址的占位符。在復(fù)制操作中,如果只是將指針復(fù)制給新對象,那么底層的資源實(shí)際上仍然由兩個實(shí)例在共享。
示例圖1
淺復(fù)制:兩個實(shí)例的指針仍指向內(nèi)存中的同一資源,只復(fù)制指針值而不是實(shí)際資源;
深復(fù)制:不僅復(fù)制指針值,還復(fù)制指向指針?biāo)赶虻馁Y源。如下圖:
示例圖2
單例模式理解與使用
單例模式是一種常用設(shè)計(jì)模式,單例模式是一個類在系統(tǒng)中只有一個實(shí)例對象。通過全局的一個入口點(diǎn)對這個實(shí)例對象進(jìn)行訪問;
iOS中單例模式的實(shí)現(xiàn)方式一般分為兩種:非ARC和ARC+GCD。
對沙盒的理解
每個iOS應(yīng)用都被限制在“沙盒”中,沙盒相當(dāng)于一個加了僅主人可見權(quán)限的文件夾,及時在應(yīng)用程序安裝過程中,系統(tǒng)為每個單獨(dú)的應(yīng)用程序生成它的主目錄和一些關(guān)鍵的子目錄。蘋果對沙盒有幾條限制:
1. 應(yīng)用程序在自己的沙盒中運(yùn)作,但是不能訪問任何其他應(yīng)用程序的沙盒;
2. 應(yīng)用之間不能共享數(shù)據(jù),沙盒里的文件不能被復(fù)制到其他
應(yīng)用程序的文件夾中,也不能把其他應(yīng)用文件夾復(fù)制到沙盒中;
3. 蘋果禁止任何讀寫沙盒以外的文件,禁止應(yīng)用程序?qū)?nèi)容寫到沙盒以外的文件夾中;
4. 沙盒目錄里有三個文件夾:Documents——存儲
應(yīng)用程序的數(shù)據(jù)文件,存儲用戶數(shù)據(jù)或其他定期備份的信息;
Library下有兩個文件夾,Caches存儲應(yīng)用程序再次啟動所需的信息,
Preferences包含應(yīng)用程序的偏好設(shè)置文件,不可在這更改偏好設(shè)置;
temp存放臨時文件即應(yīng)用程序再次啟動不需要的文件。
獲取沙盒根目錄的方法,有幾種方法:用NSHomeDirectory獲取。
獲取Document路徑:
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES).
對瀑布流的理解
首先圖片的寬度都是一樣的,1.將圖片等比例壓縮,讓圖片不變形;2.計(jì)算圖片最低應(yīng)該擺放的位置,哪一列低就放在哪;3.進(jìn)行最優(yōu)排列,在ScrollView的基礎(chǔ)上添加兩個tableView,然后將之前所計(jì)算的scrollView的高度通過tableView展示出來。
如何使用兩個TableView產(chǎn)生聯(lián)動:將兩個tableView的滾動事件禁止掉,最外層scrollView滾動時將兩個TableView跟著滾動,并且更改contentOffset,這樣產(chǎn)生效果滾動的兩個tableView。
ViewController 的 loadView,、viewDidLoad,、viewDidUnload 分別是在什么時候調(diào)用的?
viewDidLoad在view從nib文件初始化時調(diào)用,loadView在controller的view為nil時調(diào)用。
此方法在編程實(shí)現(xiàn)view時調(diào)用,view控制器默認(rèn)會注冊memory warning notification,當(dāng)view controller的任何view沒有用的時候,viewDidUnload會被調(diào)用,在這里實(shí)現(xiàn)將retain的view release,如果是retain的IBOutlet view 屬性則不要在這里release,IBOutlet會負(fù)責(zé)release 。
關(guān)鍵字volatile有什么含意?并給出三個不同的例子:
一個定義為volatile的變量是說這變量可能會被意想不到地改變,這樣,編譯器就不會去假設(shè)這個變量的值了。精確地說就是,優(yōu)化器在用到這個變量時必須每次都小心地重新讀取這個變量的值,而不是使用保存在寄存器里的備份。下面是volatile變量的幾個例子:
? 并行設(shè)備的硬件寄存器(如:狀態(tài)寄存器);
?一個中斷服務(wù)子程序中會訪問到的非自動變量(Non-automatic variables);
? 多線程應(yīng)用中被幾個任務(wù)共享的變量。
@synthesize、@dynamic的理解
@synthesize是系統(tǒng)自動生成getter和setter屬性聲明;@synthesize的意思是,除非開發(fā)人員已經(jīng)做了,否則由編譯器生成相應(yīng)的代碼,以滿足屬性聲明;
@dynamic是開發(fā)者自已提供相應(yīng)的屬性聲明,@dynamic意思是由開發(fā)人員提供相應(yīng)的代碼:對于只讀屬性需要提供setter,對于讀寫屬性需要提供 setter 和getter。查閱了一些資料確定@dynamic的意思是告訴編譯器,屬性的獲取與賦值方法由用戶自己實(shí)現(xiàn), 不自動生成。
frame和bounds有什么不同?
frame指的是:該view在父view坐標(biāo)系統(tǒng)中的位置和大小。(參照點(diǎn)是父親的坐標(biāo)系統(tǒng))
bounds指的是:該view在本身坐標(biāo)系統(tǒng)中的位置和大小。(參照點(diǎn)是本身坐標(biāo)系統(tǒng))
view的touch事件有哪些?
?- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
?- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
?- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
自定義實(shí)現(xiàn)UITabbarController的原理
運(yùn)用字典,點(diǎn)擊五個按鈕的一個可以從字典里選擇一個控制器對象,將其View顯示到主控制器視圖上。
iOS中的響應(yīng)者鏈的工作原理
每一個應(yīng)用有一個響應(yīng)者鏈,我們的視圖結(jié)構(gòu)是一個N叉樹(一個視圖可以有多個子視圖,一個子視圖同一時刻只有一個父視圖),而每一個繼承UIResponder的對象都可以在這個N叉樹中扮演一個節(jié)點(diǎn)。
當(dāng)葉節(jié)點(diǎn)成為最高響應(yīng)者的時候,從這個葉節(jié)點(diǎn)開始往其父節(jié)點(diǎn)開始追朔出一條鏈,那么對于這一個葉節(jié)點(diǎn)來講,這一條鏈就是當(dāng)前的響應(yīng)者鏈。響應(yīng)者鏈將系統(tǒng)捕獲到的UIEvent與UITouch從葉節(jié)點(diǎn)開始層層向下分發(fā),期間可以選擇停止分發(fā),也可以選擇繼續(xù)向下分發(fā)。
如需了解更多細(xì)節(jié),請讀這篇文章。
View和View之間傳值方式
對象的property屬性傳值;
方法參數(shù)傳值;
NSUserDefault傳值;
塊傳值。
property屬性的修飾符的作用
getter=getName、setter=setName:設(shè)置setter與getter的方法名;
readwrite、readonly:設(shè)置可供訪問級別;
assign:方法直接賦值,不進(jìn)行任何retain操作,為了解決原類型與環(huán)循引用問題;
retain:其setter方法對參數(shù)進(jìn)行release舊值再retain新值,所有實(shí)現(xiàn)都是這個順序;
copy:其setter方法進(jìn)行copy操作,與retain處理流程一樣,先對舊值release,再copy出新的對象,retainCount為1。這是為了減少對上下文的依賴而引入的機(jī)制。
nonatomic:非原子性訪問,不加同步, 多線程并發(fā)訪問會提高性能。注意,如果不加此屬性,則默認(rèn)是兩個訪問方法都為原子型事務(wù)訪問。
對于Run Loop的理解
RunLoop,是多線程的法寶,即一個線程一次只能執(zhí)行一個任務(wù),執(zhí)行完任務(wù)后就會退出線程。主線程執(zhí)行完即時任務(wù)時會繼續(xù)等待接收事件而不退出。非主線程通常來說就是為了執(zhí)行某一任務(wù)的,執(zhí)行完畢就需要?dú)w還資源,因此默認(rèn)是不運(yùn)行RunLoop的;
每一個線程都有其對應(yīng)的RunLoop,只是默認(rèn)只有主線程的RunLoop是啟動的,其它子線程的RunLoop默認(rèn)是不啟動的,若要啟動則需要手動啟動;
在一個單獨(dú)的線程中,如果需要在處理完某個任務(wù)后不退出,繼續(xù)等待接收事件,則需要啟用RunLoop;
NSRunLoop提供了一個添加NSTimer的方法,可以指定Mode,如果要讓任何情況下都回調(diào),則需要設(shè)置Mode為Common模式;
實(shí)質(zhì)上,對于子線程的runloop默認(rèn)是不存在的,因?yàn)樘O果采用了懶加載的方式。如果我們沒有手動調(diào)用[NSRunLoop currentRunLoop]的話,就不會去查詢是否存在當(dāng)前線程的RunLoop,也就不會去加載,更不會創(chuàng)建。
SQLite中常用的SQL語句
創(chuàng)建表:creat table 表名 (字段名 字段數(shù)據(jù)類型 是否為主鍵, 字段名 字段數(shù)據(jù)類型, 字段名 字段數(shù)據(jù)類型…);
增: insert into 表名 (字段1, 字段2…) values (值1, 值2…);
刪: delete from 表名 where 字段 = 值;
XIB與Storyboards的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
XIB:在編譯前就提供了可視化界面,可以直接拖控件,也可以直接給控件添加約束,更直觀一些,而且類文件中就少了創(chuàng)建控件的代碼,確實(shí)簡化不少,通常每個XIB對應(yīng)一個類。
Storyboard:在編譯前提供了可視化界面,可拖控件,可加約束,在開發(fā)時比較直觀,而且一個storyboard可以有很多的界面,每個界面對應(yīng)一個類文件,通過storybard,可以直觀地看出整個App的結(jié)構(gòu)。
缺點(diǎn):
XIB:需求變動時,需要修改XIB很大,有時候甚至需要重新添加約束,導(dǎo)致開發(fā)周期變長。XIB載入相比純代碼自然要慢一些。對于比較復(fù)雜邏輯控制不同狀態(tài)下顯示不同內(nèi)容時,使用XIB是比較困難的。當(dāng)多人團(tuán)隊(duì)或者多團(tuán)隊(duì)開發(fā)時,如果XIB文件被發(fā)動,極易導(dǎo)致沖突,而且解決沖突相對要困難很多。
Storyboard:需求變動時,需要修改storyboard上對應(yīng)的界面的約束,與XIB一樣可能要重新添加約束,或者添加約束會造成大量的沖突,尤其是多團(tuán)隊(duì)開發(fā)。對于復(fù)雜邏輯控制不同顯示內(nèi)容時,比較困難。當(dāng)多人團(tuán)隊(duì)或者多團(tuán)隊(duì)開發(fā)時,大家會同時修改一個storyboard,導(dǎo)致大量沖突,解決起來相當(dāng)困難。
將字符串“2015-04-10”格式化日期轉(zhuǎn)為NSDate類型
NSString *timeStr = @"2015-04-10";
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"yyyy-MM-dd";
formatter.timeZone = [NSTimeZone defaultTimeZone];
NSDate *date = [formatter dateFromString:timeStr];
// 2015-04-09 16:00:00 +0000
NSLog(@"%@", date);
隊(duì)列和多線程的使用原理
在iOS中隊(duì)列分為以下幾種:
串行隊(duì)列:隊(duì)列中的任務(wù)只會順序執(zhí)行;
dispatch_queue_t q = dispatch_queue_create("...", DISPATCH_QUEUE_SERIAL);
并行隊(duì)列: 隊(duì)列中的任務(wù)通常會并發(fā)執(zhí)行;
dispatch_queue_t q = dispatch_queue_create("......",DISPATCH_QUEUE_CONCURRENT);
全局隊(duì)列:是系統(tǒng)的,直接拿過來(GET)用就可以;與并行隊(duì)列類似;
dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
主隊(duì)列:每一個應(yīng)用程序?qū)?yīng)唯一主隊(duì)列,直接GET即可;在多線程開發(fā)中,使用主隊(duì)列更新UI;
dispatch_queue_t q = dispatch_get_main_queue();
更多細(xì)節(jié)見下圖:
來自簡書
內(nèi)存的使用和優(yōu)化的注意事項(xiàng)
重用問題:如UITableViewCells、UICollectionViewCells、UITableViewHeaderFooterViews設(shè)置正確的reuseIdentifier,充分重用;
盡量把views設(shè)置為不透明:當(dāng)opque為NO的時候,圖層的半透明取決于圖片和其本身合成的圖層為結(jié)果,可提高性能;
不要使用太復(fù)雜的XIB/Storyboard:載入時就會將XIB/storyboard需要的所有資源,包括圖片全部載入內(nèi)存,即使未來很久才會使用。那些相比純代碼寫的延遲加載,性能及內(nèi)存就差了很多;
選擇正確的數(shù)據(jù)結(jié)構(gòu):學(xué)會選擇對業(yè)務(wù)場景最合適的數(shù)組結(jié)構(gòu)是寫出高效代碼的基礎(chǔ)。比如,數(shù)組: 有序的一組值。使用索引來查詢很快,使用值查詢很慢,插入/刪除很慢。字典: 存儲鍵值對,用鍵來查找比較快。集合: 無序的一組值,用值來查找很快,插入/刪除很快。
gzip/zip壓縮:當(dāng)從服務(wù)端下載相關(guān)附件時,可以通過gzip/zip壓縮后再下載,使得內(nèi)存更小,下載速度也更快。
延遲加載:對于不應(yīng)該使用的數(shù)據(jù),使用延遲加載方式。對于不需要馬上顯示的視圖,使用延遲加載方式。比如,網(wǎng)絡(luò)請求失敗時顯示的提示界面,可能一直都不會使用到,因此應(yīng)該使用延遲加載。
數(shù)據(jù)緩存:對于cell的行高要緩存起來,使得reload數(shù)據(jù)時,效率也極高。而對于那些網(wǎng)絡(luò)數(shù)據(jù),不需要每次都請求的,應(yīng)該緩存起來,可以寫入數(shù)據(jù)庫,也可以通過plist文件存儲。
處理內(nèi)存警告:一般在基類統(tǒng)一處理內(nèi)存警告,將相關(guān)不用資源立即釋放掉
重用大開銷對象:一些objects的初始化很慢,比如NSDateFormatter和NSCalendar,但又不可避免地需要使用它們。通常是作為屬性存儲起來,防止反復(fù)創(chuàng)建。
避免反復(fù)處理數(shù)據(jù):許多應(yīng)用需要從服務(wù)器加載功能所需的常為JSON或者XML格式的數(shù)據(jù)。在服務(wù)器端和客戶端使用相同的數(shù)據(jù)結(jié)構(gòu)很重要;
使用Autorelease Pool:在某些循環(huán)創(chuàng)建臨時變量處理數(shù)據(jù)時,自動釋放池以保證能及時釋放內(nèi)存;
正確選擇圖片加載方式:詳情閱讀細(xì)讀UIImage加載方式
UIViewController的完整生命周期
-[ViewController initWithNibName:bundle:];
-[ViewController init];
-[ViewController loadView];
-[ViewController viewDidLoad];
-[ViewController viewWillDisappear:];
-[ViewController viewWillAppear:];
-[ViewController viewDidAppear:];
-[ViewController viewDidDisappear:];
UIImageView添加圓角
最直接的方法就是使用如下屬性設(shè)置:
imgView.layer.cornerRadius = 10;
// 這一行代碼是很消耗性能的
imgView.clipsToBounds = YES;
**這是離屏渲染(off-screen-rendering),消耗性能的**
給UIImage添加生成圓角圖片的擴(kuò)展API:這是on-screen-rendering
- (UIImage *)imageWithCornerRadius:(CGFloat)radius {
CGRect rect = (CGRect){0.f, 0.f, self.size};
UIGraphicsBeginImageContextWithOptions(self.size, NO, UIScreen.mainScreen.scale);
CGContextAddPath(UIGraphicsGetCurrentContext(),
[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radius].CGPath);
CGContextClip(UIGraphicsGetCurrentContext());
[self drawInRect:rect];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}