iOS程序運行流程
系統(tǒng)調(diào)用app的main函數(shù)
main函數(shù)調(diào)用UIApplicationMain.
UIApplicationMain創(chuàng)建shared application instance, UIApplication默認的instance.
UIApplicationMain讀取Info.plist找到主nib文件, 加載nib嫩海,把shared application instance 設為nib的owner.
通過nib文件庇楞,創(chuàng)建app的獨立UIWindows object.
通過nib,實例化了程序的AppDelegate object.
app內(nèi)部啟動結束,application:didFinishLaunchingWith- Options: 被設定成 wAppDelegate instance.
AppDelegate向UIWindow instance發(fā)makeKeyAndVisible消息, app界面展示給用戶. app準備好接收用戶的操作指令.
簡述應用程序按Home鍵進入后臺時的生命周期脏里,以及從后臺回到前臺時的生命周期?
應用程序的狀態(tài):
Not running 未運行刻剥,程序沒啟動
Inactive 未激活馋记,程序在前臺運行,不過沒接受到事件肆资,沒有事件處理的狀態(tài)下通常處于這個狀態(tài)矗愧。
Active 激活 程序在前臺并且接收到了事件
Backgound 后臺 程序在后臺而且能執(zhí)行代碼,大多數(shù)程序進入這個狀態(tài)后會在在這個狀態(tài)上停留一會郑原。
Suspended 掛起 程序在后臺不能執(zhí)行代碼唉韭。
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions
//告訴代理進程啟動但還沒進入狀態(tài)保存 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
// 告訴代理啟動基本完成程序準備開始運行 - (void)applicationWillResignActive:(UIApplication *)application
// 當應用程序?qū)⒁敕腔顒訝顟B(tài)執(zhí)行,在此期間犯犁,應用程序不接收消息或事件属愤,比如來電話了 - (void)applicationDidBecomeActive:(UIApplication *)application
// 當應用程序入活動狀態(tài)執(zhí)行,這個剛好跟上面那個方法相反 - (void)applicationDidEnterBackground:(UIApplication *)application
// 當程序被推送到后臺的時候調(diào)用酸役。所以要設置后臺繼續(xù)運行住诸,則在這個函數(shù)里面設置即可 - (void)applicationWillEnterForeground:(UIApplication *)application
//當程序從后臺將要重新回到前臺時候調(diào)用,這個剛好跟上面的那個方法相反涣澡。 - (void)applicationWillTerminate:(UIApplication *)application
//當程序?qū)⒁顺鍪潜徽{(diào)用贱呐,通常是用來保存數(shù)據(jù)和一些退出前的清理工作。這個需要要設置UIApplicationExitsOnSuspend的鍵值入桂。 - (void)applicationDidFinishLaunching:(UIApplication*)application
//當程序載入后執(zhí)行
描述應用程序的啟動順序吼句?
1、程序入口main函數(shù)創(chuàng)建UIApplication實例和UIApplication代理實例
2事格、在UIApplication代理實例中重寫啟動方法惕艳,設置第一ViewController
3搞隐、在第一ViewController中添加控件,實現(xiàn)對應的程序界面远搪。
參考鏈接:http://www.reibang.com/p/bdf3f20848b9
iOS本地數(shù)據(jù)存儲都有哪幾種方式劣纲?iOS如何實現(xiàn)復雜對象的存儲?
NSKeyedArchiver(歸檔)采用歸檔的形式來保存數(shù)據(jù)谁鳍,該數(shù)據(jù)對象需要遵守NSCoding協(xié)議癞季,并且該對象對應的類必須提供encodeWithCoder:和initWithCoder:方法;
NSUserDefaults:用來保存應用程序設置和屬性、用戶保存的數(shù)據(jù)倘潜。用戶再次打開程序或開機后這些數(shù)據(jù)仍然存在绷柒。NSUserDefaults可以存儲的數(shù)據(jù)類型包括:NSData、NSString涮因、NSNumber废睦、NSDate、NSArray养泡、NSDictionary;
Write寫入方式:永久保存在磁盤中;
SQLite(FMDB嗜湃、CoreData) ;
NSCoding + NSKeyedArchiver實現(xiàn)復雜對象的存儲;
堆和棧的區(qū)別?
棧區(qū)(stack)--由編譯器自動分配釋放澜掩,存放函數(shù)的參數(shù)值购披、局部變量的值。
堆區(qū)(heap)--一般由程序員分配釋放肩榕。
全局區(qū)(靜態(tài)區(qū))(static)--全局變量和靜態(tài)變量刚陡。程序結束后由系統(tǒng)釋放。
文字常量區(qū)--常量字符串存放在這里株汉。程序結束后由系統(tǒng)釋放筐乳。
程序代碼區(qū)—存放函數(shù)體的二進制文件。
棧:只要棧的剩余空間大于所申請空間郎逃,系統(tǒng)將為程序提供內(nèi)存,否則將報異常提示棧溢 出挺份。
堆:首先應該知道操作系統(tǒng)有一個記錄空閑內(nèi)存地址的鏈表褒翰,當系統(tǒng)收到程序的申請時,會遍歷該鏈表匀泊,尋找第一個空間大于所申請空間的堆結點优训,然后將該結點從空閑結點鏈表中刪除,并將該結點的空間分配給程序各聘,另外揣非,對于大多數(shù)系統(tǒng),會在這塊內(nèi)存空間中的首地址處記錄本次分配的大小躲因,這樣早敬,代碼中的delete語句才能正確的釋放本內(nèi)存空間忌傻。另外,由于找到的堆結點的大小不一定正好等于申請的大小搞监,系統(tǒng)會自動的將多余的那部分重新放入空閑鏈表中水孩。
iOS類是否可以多繼承?如果沒有琐驴,那可以用其他方法實現(xiàn)嗎俘种?簡述實現(xiàn)過程
不可以,可以通過消息轉(zhuǎn)發(fā)绝淡、delegate和protocol和類別來實現(xiàn)類似多繼承
KVO (Key-value observing)
KVO是觀察者模式的另一實現(xiàn)宙刘。
使用了isa混寫(isa-swizzling)來實現(xiàn)KVO
使用setter方法改變值KVO會生效,使用setValue:forKey即KVC改變值KVO也會生效牢酵,因為KVC會去調(diào)用setter方法
-
(void)setValue:(id)value
{
[self willChangeValueForKey:@"key"];[super setValue:value];
[self didChangeValueForKey:@"key"];
}
那么通過直接賦值成員變量會觸發(fā)KVO嗎悬包?
不會,因為不會調(diào)用setter方法茁帽,需要加上
willChangeValueForKey和didChangeValueForKey方法來手動觸發(fā)才行
KVC(Key-value coding)**
-(id)valueForKey:(NSString *)key;
-(void)setValue:(id)value forKey:(NSString *)key;
復制代碼
KVC就是指iOS的開發(fā)中玉罐,可以允許開發(fā)者通過Key名直接訪問對象的屬性,或者給對象的屬性賦值潘拨。而不需要調(diào)用明確的存取方法吊输。這樣就可以在運行時動態(tài)地訪問和修改對象的屬性。而不是在編譯時確定铁追,這也是iOS開發(fā)中的黑魔法之一季蚂。很多高級的iOS開發(fā)技巧都是基于KVC實現(xiàn)的
當調(diào)用setValue:屬性值 forKey:@”name“的代碼時琅束,扭屁,底層的執(zhí)行機制如下:
- 程序優(yōu)先調(diào)用set<Key>:屬性值方法,代碼通過setter方法完成設置。注意,這里的<key>是指成員變量名,首字母大小寫要符合KVC的命名規(guī)則运授,下同
- 如果沒有找到setName:方法烤惊,KVC機制會檢查+ (BOOL)accessInstanceVariablesDirectly方法有沒有返回YES乔煞,默認該方法會返回YES,如果你重寫了該方法讓其返回NO的話撕氧,那么在這一步KVC會執(zhí)行setValue:forUndefinedKey:方法瘤缩,不過一般開發(fā)者不會這么做。所以KVC機制會搜索該類里面有沒有名為<key>的成員變量伦泥,無論該變量是在類接口處定義剥啤,還是在類實現(xiàn)處定義,也無論用了什么樣的訪問修飾符不脯,只在存在以<key>命名的變量府怯,KVC都可以對該成員變量賦值。
- 如果該類即沒有set<key>:方法防楷,也沒有_<key>成員變量牺丙,KVC機制會搜索_is<Key>的成員變量。
- 和上面一樣复局,如果該類即沒有set<Key>:方法冲簿,也沒有_<key>和_is<Key>成員變量,KVC機制再會繼續(xù)搜索<key>和is<Key>的成員變量亿昏。再給它們賦值峦剔。
- 如果上面列出的方法或者成員變量都不存在,系統(tǒng)將會執(zhí)行該對象的setValue:forUndefinedKey:方法角钩,默認是拋出異常吝沫。
即如果沒有找到Set<Key>方法的話,會按照_key递礼,_iskey惨险,key,iskey的順序搜索成員并進行賦值操作脊髓。
如果開發(fā)者想讓這個類禁用KVC辫愉,那么重寫+ (BOOL)accessInstanceVariablesDirectly方法讓其返回NO即可,這樣的話如果KVC沒有找到set<Key>:屬性名時将硝,會直接用setValue:forUndefinedKey:方法恭朗。
當調(diào)用valueForKey:@”name“的代碼時,KVC對key的搜索方式不同于setValue:屬性值 forKey:@”name“袋哼,其搜索方式如下:
- 首先按get<Key>,<key>,is<Key>的順序方法查找getter方法冀墨,找到的話會直接調(diào)用闸衫。如果是BOOL或者Int等值類型涛贯, 會將其包裝成一個NSNumber對象。
- 如果上面的getter沒有找到蔚出,KVC則會查找countOf<Key>,objectIn<Key>AtIndex或<Key>AtIndexes格式的方法弟翘。如果countOf<Key>方法和另外兩個方法中的一個被找到虫腋,那么就會返回一個可以響應NSArray所有方法的代理集合(它是NSKeyValueArray寡壮,是NSArray的子類)凹联,調(diào)用這個代理集合的方法,或者說給這個代理集合發(fā)送屬于NSArray的方法醉蚁,就會以countOf<Key>,objectIn<Key>AtIndex或<Key>AtIndexes這幾個方法組合的形式調(diào)用睛琳。還有一個可選的get<Key>:range:方法盒蟆。所以你想重新定義KVC的一些功能,你可以添加這些方法师骗,需要注意的是你的方法名要符合KVC的標準命名方法历等,包括方法簽名。
- 如果上面的方法沒有找到辟癌,那么會同時查找countOf<Key>寒屯,enumeratorOf<Key>,memberOf<Key>格式的方法。如果這三個方法都找到黍少,那么就返回一個可以響應NSSet所的方法的代理集合寡夹,和上面一樣,給這個代理集合發(fā)NSSet的消息厂置,就會以countOf<Key>菩掏,enumeratorOf<Key>,memberOf<Key>組合的形式調(diào)用。
- 如果還沒有找到农渊,再檢查類方法+ (BOOL)accessInstanceVariablesDirectly,如果返回YES(默認行為)患蹂,那么和先前的設值一樣,會按_<key>,_is<Key>,<key>,is<Key>的順序搜索成員變量名砸紊,這里不推薦這么做传于,因為這樣直接訪問實例變量破壞了封裝性,使代碼更脆弱醉顽。如果重寫了類方法+ (BOOL)accessInstanceVariablesDirectly返回NO的話沼溜,那么會直接調(diào)用valueForUndefinedKey:方法,默認是拋出異常游添。
iOS用什么方式實現(xiàn)對一個對象的KVO系草?(KVO的本質(zhì)是什么?)
利用RuntimeAPI動態(tài)生成一個子類唆涝,并且讓instance對象的isa指向這個全新的子類
當修改instance對象的屬性時找都,會調(diào)用Foundation的_NSSetXXXValueAndNotify函數(shù)
willChangeValueForKey:
父類原來的setter
didChangeValueForKey:
內(nèi)部會觸發(fā)監(jiān)聽器(Oberser)的監(jiān)聽方法(observeValueForKeyPath:ofObject:change:context:)
屬性關鍵字**
1.讀寫權限:readonly,readwrite(默認)
2.原子性: atomic(默認),nonatomic廊酣。atomic讀寫線程安全能耻,但效率低,而且不是絕對的安全,比如如果修飾的是數(shù)組晓猛,那么對數(shù)組的讀寫是安全的饿幅,但如果是操作數(shù)組進行添加移除其中對象的還,就不保證安全了戒职。
3.引用計數(shù):
- retain/strong
- assign:修飾基本數(shù)據(jù)類型栗恩,修飾對象類型時,不改變其引用計數(shù)洪燥,會產(chǎn)生懸垂指針磕秤,修飾的對象在被釋放后,assign指針仍然指向原對象內(nèi)存地址捧韵,如果使用assign指針繼續(xù)訪問原對象的話亲澡,就可能會導致內(nèi)存泄漏或程序異常
- weak:不改變被修飾對象的引用計數(shù),所指對象在被釋放后纫版,weak指針會自動置為nil
- copy:分為深拷貝和淺拷貝
淺拷貝:對內(nèi)存地址的復制床绪,讓目標對象指針和原對象指向同一片內(nèi)存空間會增加引用計數(shù)
深拷貝:對對象內(nèi)容的復制,開辟新的內(nèi)存空間
image.png
可變對象的copy和mutableCopy都是深拷貝
不可變對象的copy是淺拷貝其弊,mutableCopy是深拷貝
copy方法返回的都是不可變對象
分類癞己、擴展、代理梭伐、通知痹雅、KVO、KVC糊识、屬性
參考鏈接:https://juejin.im/post/6844904039008698381
@property (nonatomic, copy) NSMutableArray * array;這樣寫有什么影響绩社?
因為copy方法返回的都是不可變對象,所以array對象實際上是不可變的赂苗,如果對其進行可變操作如添加移除對象愉耙,則會造成程序crash
frame 和 bounds 的區(qū)別是什么?
frame相對于父視圖,是父視圖坐標系下的位置和大小拌滋。bounds相對于自身,是自身坐標系下的位置和大小朴沿。
frame以父控件的左上角為坐標原點,bounds以自身的左上角為坐標原點
什么時候會發(fā)生「隱式動畫」败砂?
當改變CALayer的一個可做動畫的屬性赌渣,它并不能立刻在屏幕上體現(xiàn)出來.相反,它是從先前的值平滑過渡到新的值昌犹。這一切都是默認的行為坚芜,你不需要做額外的操作,這就是隱式動畫
UIView 和 CALayer 之間的關系?
UIView顯示在屏幕上歸功于CALayer斜姥,通過調(diào)用drawRect方法來渲染自身的內(nèi)容鸿竖,調(diào)節(jié)CALayer屬性可以調(diào)整UIView的外觀路操,UIView繼承自UIResponder,CALayer不可以響應用戶事件
UIView是iOS系統(tǒng)中界面元素的基礎千贯,所有的界面元素都繼承自它。它內(nèi)部是由Core Animation來實現(xiàn)的搞坝,它真正的繪圖部分搔谴,是由一個叫CALayer(Core Animation Layer)的類來管理。UIView本身桩撮,更像是一個CALayer的管理器敦第,訪問它的根繪圖和坐標有關的屬性,如frame店量,bounds等芜果,實際上內(nèi)部都是訪問它所在CALayer的相關屬性
UIView有個layer屬性,可以返回它的主CALayer實例融师,UIView有一個layerClass方法右钾,返回主layer所使用的類,UIView的子類旱爆,可以通過重載這個方法舀射,來讓UIView使用不同的CALayer來顯示
+[UIView animateWithDuration:animations:completion:] 內(nèi)部大概是如何實現(xiàn)的?
animateWithDuration:這就等于創(chuàng)建一個定時器
animations:這是創(chuàng)建定時器需要實現(xiàn)的SEL
completion:是定時器結束以后的一個回調(diào)block
iOS 的沙盒目錄結構是怎樣的怀伦?
Application:存放程序源文件脆烟,上架前經(jīng)過數(shù)字簽名,上架后不可修改
Documents:常用目錄房待,iCloud備份目錄邢羔,存放數(shù)據(jù),這里不能存緩存文件,否則上架不被通過
Library
Caches:存放體積大又不需要備份的數(shù)據(jù),SDWebImage緩存路徑就是這個
Preference:設置目錄,iCloud會備份設置信息
tmp:存放臨時文件桑孩,不會被備份拜鹤,而且這個文件下的數(shù)據(jù)有可能隨時被清除的可能
Push Notification推送 是如何工作的?
推送通知分為兩種,一個是本地推送,一個是遠程推送
本地推送:不需要聯(lián)網(wǎng)也可以推送,是開發(fā)人員在APP內(nèi)設定特定的時間來提醒用戶干什么
從圖中可以很清楚的看出來推送的原理主要分為以下幾步:
1.由App向iOS設備發(fā)送一個注冊通知流椒,用戶需要同意系統(tǒng)發(fā)送推送署惯。
2.iOS向APNs遠程推送服務器發(fā)送App的Bundle Id和設備的UDID。
3.APNs根據(jù)設備的UDID和App的Bundle Id生成deviceToken再發(fā)回給App镣隶。
4.App再將deviceToken發(fā)送給遠程推送服務器(自己的服務器), 由服務器保存在數(shù)據(jù)庫中极谊。
5.當自己的服務器想發(fā)送推送時, 在遠程推送服務器中輸入要發(fā)送的消息并選擇發(fā)給哪些用戶的deviceToken,由遠程推送服務器發(fā)送給APNs安岂。
6.APNs根據(jù)deviceToken發(fā)送給對應的用戶轻猖。
· APNs 服務器就是蘋果專門做遠程推送的服務器。
·deviceToken是由APNs生成的一個專門找到你某個手機上的App的一個標識碼域那。
· deviceToken 可能會變,如果你更改了你項目的bundle Identifier或者APNs服務器更新了可能會變咙边。
是一個與線程相關的機制猜煮。
一個RunLoop就是一個時間處理的循環(huán),用來不停的調(diào)度工作以及處理輸入時間败许。使用runloop的目的是讓你的線程在有工作的時候忙于工作,而沒工作的時候處于休眠狀態(tài)王带。runloop的設計是為了減少cpu無謂的空轉(zhuǎn);
進程與線程的特點與區(qū)別?
1)進程和線程都是由操作系統(tǒng)所體會的程序運行的基本單元市殷,系統(tǒng)利用該基本單元實現(xiàn)系統(tǒng)對應用的并發(fā)性愕撰。
2)進程和線程的主要差別在于它們是不同的操作系統(tǒng)資源管理方式。 進程有獨立的地址空間醋寝,一個進程崩潰后搞挣,在保護模式下不會對其它進程產(chǎn)生影響,而線程只是一個進程中的不同執(zhí)行路徑音羞。線程有自己的堆棧和局部變量囱桨,但線程之間沒有單獨的地址空間,一個線程死掉就等于整個進程死掉嗅绰,所以多進程的程序要比多線程的程序健壯舍肠,但在進程切換時,耗費資源較大窘面,效率要差一些貌夕。但對于一些要求同時進行并且又要共享某些變量的并發(fā)操作,只能用線程民镜,不能用進程啡专。 共享變量可以實現(xiàn)線程調(diào)用另一個線程。
25匹馬制圈,現(xiàn)有5條跑道们童,沒有計時器,要找出最快3匹馬鲸鹦,至少要跑幾場慧库?
至少跑7場,
對25匹馬隨機分成5個組(A,B,C,D,E,F),每組跑一場馋嗜,記錄每一匹馬在當前組中名次(第1名齐板,第2名,第3名)(跑了五場)
從各個組中選取名次為第一名的馬組成一組葛菇,跑一場甘磨,記錄名次(第六場),本組第1名則確定了25匹馬中最快的一匹馬
選取第六場中名次為第1名的所在原來組名次為第2眯停、3名馬济舆,選取第六場中名次為第2名的所在原來組名次第1、2名馬(它自己+第2名)莺债,選取第六場中名次為第3名所在原來組名次第1名的馬(它自己)滋觉,組成一組签夭,跑一場,記錄名次(第七場)椎侠,本場的第1第租、2名就是25匹馬中最快的第2、3名
8瓶液體我纪,其中1瓶有毒藥慎宾,毒藥1小時后至死,請問最快找出毒藥宣羊,需要幾只老鼠?
1只老鼠可以斷定2瓶液體汰蜘,2^3=8仇冯,所以需要3只老鼠即可,
對液體進行編號族操,001苛坚,010,011色难,100泼舱,101,110枷莉,111
給1號老鼠喂編碼個位數(shù)上是1的液體(001娇昙,011,101笤妙,111)冒掌,
給2號老鼠喂編碼十位數(shù)上是1的液體(010,011蹲盘,110股毫,111),
給3號老鼠喂編碼百位數(shù)上是1的液體(100召衔,101铃诬,110,111)苍凛,
1小時后趣席,
如果老鼠全活, 8號液體有毒,
如果全都死醇蝴,7號液體有毒吩坝,
如果1號死,2哑蔫,3活钉寝, 1號液體有毒
如果2號死弧呐, 1,3活嵌纲,2號液體有毒
如果3號死俘枫,1,2活逮走, 4號液體有毒
如果1鸠蚪,2號死,3活师溅, 3號液體有毒
如果1茅信,3號死,2活墓臭, 5號液體有毒
如果2蘸鲸,3號死,1活窿锉, 6號液體有毒
UIButton不響應事件的原因
按鈕添加到了一個沒有開啟用戶交互的父View上酌摇,例如UIImageView,這時候開啟父試圖的交互 view.userInteractionEnabled = YES
按鈕自身被遮擋嗡载,點擊的時候根本就沒有點擊到button窑多,而是他上面一層View,自然就不會響應
按鈕的frame超出了父視圖的frame洼滚,這個是最容易出現(xiàn)的埂息,按鈕的frame必須在父視圖的frame內(nèi)部點擊才有效
注意:超出父視圖不響應,但在父視圖里的會響應遥巴。
webview的優(yōu)化耿芹,webview為什么會加載白屏
webview加載H5頁面過程
初始化 webview -> 請求頁面 -> 下載數(shù)據(jù) -> 解析HTML -> 請求 js/css 資源 -> dom 渲染 -> 解析 JS 執(zhí)行 -> JS 請求數(shù)據(jù) -> 解析渲染 -> 下載渲染圖片
優(yōu)化
前端優(yōu)化
合并資源,減少http請求數(shù)
加快請求速度:預解析DNS挪哄,減少域名數(shù)吧秕,并行加載,CDN 分發(fā)
客戶端優(yōu)化
離線包方案:把一個個功能模塊的所有相關頁面和資源打包下發(fā)
提前初始化 webview迹炼,提供一個全局的webview砸彬。添加webview 池重用池,可以用兩個或多個 webview 重復使用
預加載數(shù)據(jù)
總結:緩存/預加載/并行斯入,緩存一切網(wǎng)絡請求砂碉,盡量在用戶打開之前就加載好所有內(nèi)容,能并行做的事不串行做刻两。
app啟動優(yōu)化
App總啟動時間 = pre-main耗時 + main耗時增蹭,可以通過添加環(huán)境變量:DYLD_PRINT_STATISTICS
啟動流程
pre-main:系統(tǒng)dylib(動態(tài)鏈接庫)和自身App可執(zhí)行文件的加載
main: main方法執(zhí)行之后到AppDelegate類中的didFinishLaunchingWithOptions方法執(zhí)行結束前這段時間,主要是構建第一個界面磅摹,并完成渲染展示
pre-main優(yōu)化
減少類的數(shù)量滋迈,刪除無用代碼(未被調(diào)用的靜態(tài)變量霎奢、類和方法,抽象重復代碼
+load方法中做的事情延遲到+initialize中,或者在+load中做的事情不宜花費過多時間
減少不必要的framework饼灿,或者優(yōu)化已有的framework
main階段優(yōu)化
didFinishLaunchingWithOptions,日志幕侠、統(tǒng)計,某個功能的預加載,第三方SDK初始化碍彭,可以采用懶加載晤硕,或者分階段啟動
首頁啟動渲染的頁面優(yōu)化,對于viewDidLoad以及viewWillAppear方法中盡量去嘗試少做庇忌,晚做舞箍,不做,或者采用異步的方式去做皆疹。不使用xib或者storyboard疏橄,直接使用代碼
談談你對KVC的理解?
KVC|可以通過(key)直接訪問對象的屬性墙基,或者給對象的屬性賦值软族,這樣可以在運行時動態(tài)的訪問或修改對象的屬性當調(diào)用setValue:屬性值forKey: @"name"的代碼時刷喜,残制,底層的執(zhí)行機制如下∶
1、程序優(yōu)先調(diào)用set key>:屬性值方法掖疮,代碼通過(setter方法|完成設置初茶。注意,這里的<key是指成員變量名浊闪,首字母大小寫要符合(KVC)的命名規(guī)則恼布,下同
2、如果沒有找到setName:|方法搁宾,KVC機制會檢查(+(BOOL)accessInstancelariablesDirectly方法有沒有返回VYES 折汞,默認該方法會返回(VEs ,如果你重寫了該方法讓其返回NO的話,那么在這一步(KC 會執(zhí)行(setValue: forUndefinedKey:)方法盖腿,不過一般開發(fā)者不會這么做爽待。所以KVC機制會搜索該類里面有沒有名為<kep)的成員變量,無論該變量是在類接口處定義翩腐,還是在類實現(xiàn)處定義鸟款,也無論用了什么樣的訪問修飾符,只在存在以<key命名的變量茂卦,KVC都可以對該成員變量賦值何什。
3、如果該類即沒有set<key>:方法等龙,也沒有(_<key>成員變量处渣,KVC機制會搜索(_is<Key>)的成員變量伶贰。
4、和上面一樣霍比,如果該類即沒有set:方法幕袱,也沒有_和_is成員變量,KVC機制再會繼續(xù)搜索和is的成員變量悠瞬。再給它們賦值们豌。
談談對性能優(yōu)化的看法,如何做浅妆?
從用戶體驗出發(fā):
1望迎、程序logging不要太長、
2凌外、相同數(shù)據(jù)不做重復獲取辩尊、
3、昂貴資源要重用(cell康辑、sqlite摄欲、date),
4疮薇、良好的編程習慣和程序設計:選擇正確的集合對象和算法來進行編程胸墙、選擇適合的數(shù)據(jù)存儲格式(plist、SQLite)按咒、優(yōu)化SQLite查詢語句
5迟隅、數(shù)據(jù)資源方面的優(yōu)化(緩存和異步加載)
解決方案:
? 能夠發(fā)現(xiàn)問題
? 利用log或工具分析問題原因
? 假設問題原因
? 改進代碼和設計
oc中可修改和不可以修改類型?
答:可修改不可修改的集合類励七,這個我個人簡單理解就是可動態(tài)添加修改和不可動態(tài)添加修改
一樣智袭。比如NSArray和NSMutableArray,前者在初始化后的內(nèi)存控件就是固定不可變的掠抬,后者可
以添加等吼野,可以動態(tài)申請新的內(nèi)存空間
說說響應鏈
當事件發(fā)生的時候,響應鏈首先被發(fā)送給第一個響應者(往往是事件發(fā)生的視圖两波,也就是用戶觸摸屏幕的地方)瞳步。事件將沿著響應者鏈一直向下傳遞,直到被接受并作出處理雨女。一般來說谚攒,第一響應這是個視圖對象或者其子類,當其被觸摸后事件就交由它處理氛堕,如果他不處理馏臭,時間就會被傳遞給視圖控制器對象;
UIViewController(如果存在),然后是它的父視圖對象(superview),以此類推知道頂層視圖括儒。接下來會沿著頂層視圖(top view)到窗口(UIwindow 對象) 再到程序的(UIApplication對象)绕沈,如果整個過程都沒有響應這個事件,則該事件被丟棄帮寻,一般情況下乍狐,在響應鏈中只要有對象處理事件,事件就會被傳遞 ;
典型的響應路線圖如: First Responser --> The Window -->The Applicationn --> App Delegate
熟悉哪些設計模式固逗?
MVC 模式浅蚪、單例模式、MVVM 模式烫罩、代理模式惜傲、工廠模式,觀察者模式
1.mvc 模式:model 保存應用模型和處理數(shù)據(jù)邏輯贝攒、view 負責 model 數(shù)據(jù)和交互控件的顯示盗誊、
controller 負責 model 和 View 之間的通訊
2.單例模式:用一個靜態(tài)方法返回這個類的對象。這個對象是全局唯一的隘弊。整個項目里面只開
辟一塊內(nèi)層哈踱,比如登錄之后獲取的用戶數(shù)據(jù)存儲、NSNotificationcenter梨熙、NSUserdefaults,
sharedApplication开镣。
缺點:這塊內(nèi)層直到項目推出時才能釋放。
優(yōu)勢:使用簡單串结,延時求值哑子,易于跨模塊, 便于資源共享控制舅列,方便傳值和修改單例的屬性
談談你對MVC的理解肌割?為什么要用MVC?
MVC是Model-VIew-Controller帐要,就是模型-視圖-控制器, MVC把軟件系統(tǒng)分為三個部分:Model把敞,View,Controller榨惠。
Cocoa中所有的控件奋早、窗口等都繼承自 UIView,對應MVC中的 V赠橙。UIView及其子類主要負責UI的實現(xiàn)耽装,而UIView所產(chǎn)生的事件都可以采用委托的方式,交給UIViewController實現(xiàn)期揪。對于不同的 UIView掉奄,都有相應的UIViewController 對應MVC中的C。比如在iPhone OS上常用的UITableView凤薛,它所對應的Controller就是UITableViewController姓建。至于MVC中的M诞仓,那需要根據(jù)用 戶自己的需求來實現(xiàn)了。
MVC可以幫助確保幫助實現(xiàn)程序最大程度的可重用性速兔。各MVC元素彼此獨立運作墅拭,通過分開這些元素,可以構建可維護涣狗,可獨立更新的程序組建谍婉。
簡述NotificationCenter、KVC镀钓、KVO屡萤、Delegate?并說明它們之間的區(qū)別掸宛?
Notification:觀察者模式死陆,controller向defaultNotificationCenter添加自己的 notification,其他類注冊這個notification就可以收到通知唧瘾,這些類可以在收到通知時做自己的操作(多觀察者默認隨機順序發(fā)通知給 觀察者們措译,而且每個觀察者都要等當前的某個觀察者的操作做完才能輪到他來操作,可以用NotificationQueue的方式安排觀察者的反應順序饰序,也 可以在添加觀察者中設定反映時間领虹,取消觀察需要在viewDidUnload 跟dealloc中都要注銷);
KVC鍵值編碼,可以直接通過字符串的名字(key)來間接訪問屬性的機制求豫,而不是通過調(diào)用getter和setter方法訪問;
KVO:觀測指定對象的屬性塌衰,當指定對象的屬性更改之后會通知相應的觀察者;
delegate:一對一,delegate遵循某個協(xié)議并實現(xiàn)協(xié)議聲明的方法;
怎么用 copy 關鍵字蝠嘉?
NSString最疆、NSArray、NSDictionary 等等經(jīng)常使用 copy 關鍵字蚤告,是因為他們有對應的可變類型:
NSMutableString努酸、NSMutableArray、NSMutableDictionary杜恰;
block 也經(jīng)常使用 copy 關鍵字获诈,具體原因見官方文檔:Objects Use Properties to Keep Track
of Blocks:
MRC 中,方法內(nèi)部的 block 是在棧區(qū)的,使用 copy 可以把它放到堆區(qū).在 ARC 中寫不寫都行:對于 block 使用 copy 還是 strong 效果是一樣的,但寫上 copy 也無傷大雅心褐,還能時刻?醒我們:編譯器自動對 block 進行了 copy操作舔涎。如果不寫 copy ,該類的調(diào)用者有可能會忘記或者根本不知道“編譯器會自動對 block進行了 copy 操作”逗爹,他們有可能會在調(diào)用之前自行拷貝屬性值亡嫌。這種操作多余而低效。
copy 此特質(zhì)所表達的所屬關系與 strong 類似。然而設置方法并不保留新值昼伴,而是將其“拷 貝” (copy)匾旭。 當屬性類型為 NSString 時,經(jīng)常用此特質(zhì)來保護其封裝性圃郊,因為傳遞給設置方法的新值有可能指向一個 NSMutableString 類的實例价涝。這個類是 NSString 的子類,表示一種可修改其值的字符串持舆,此時若是不拷貝字符串色瘩,那么設置完屬性之后,字符串的值就可能會在對象不知情的情況下遭人更改逸寓。所以居兆,這時就要拷貝一份“不可變” (immutable)的字符串,確保對象中的字符串值不會無意間變動竹伸。
談談你對多線程開發(fā)的理解泥栖?
好處:
1.使多線程可以把占據(jù)時間長的程序中的任務放到后臺去處理
2.用戶界面可以更加吸引力,這樣比如用戶點擊了一個按鈕去觸發(fā)某些事件的處理勋篓,
可以彈出一個進度條來顯示處理的進度
3.程序的運行速度可能加快
缺點:
1.如果有大量的線程,會影響性能,因為操作系統(tǒng)需要在它們之間切換吧享。
2.更多的線程需要更多的內(nèi)存空間。
ios中有幾種實現(xiàn)多線程的方法譬嚣?
多線程參考鏈接:http://www.reibang.com/p/f28a50f72bb1
1.NSThread
2.NSOperationQueue
3.GCD Thread
是這三種范式里面相對輕量級的钢颂,但也是使用起來最負責的,你需要自己管理thread的生命周期拜银,線程之間的同步殊鞭。線程共享同一應用程序的部分內(nèi)存空間, 它們擁有對數(shù)據(jù)相同的訪問權限尼桶。你得協(xié)調(diào)多個線程對同一數(shù)據(jù)的訪問操灿,一般做法是在訪問之前加鎖,這會導致一定的性能開銷疯汁。在 iOS 中我們可以使用多種形式的 thread: Cocoa threads: 使用NSThread 或直接從 NSObject 的類方法 performSelectorInBackground:withObject: 來創(chuàng)建一個線程牲尺。如果你選擇thread來實現(xiàn)多線程卵酪,那么 NSThread 就是官方推薦優(yōu)先選用的方式幌蚊。
Cocoa operations是基于 Obective-C實現(xiàn)的,類 NSOperation 以面向?qū)ο蟮姆绞椒庋b了用戶需要執(zhí)行的操作溃卡,我們只要聚焦于我們需要做的事情溢豆,而不必太操心線程的管理,同步等事情瘸羡,因為NSOperation已經(jīng)為我 們封裝了這些事情漩仙。 NSOperation 是一個抽象基類,我們必須使用它的子類悠轩。iOS 提供了兩種默認實現(xiàn):NSInvocationOperation 和 NSBlockOperation青灼。
Grand Central Dispatch (GCD): iOS4 才開始支持,它提供了一些新的特性田巴,以及運行庫來支持多核并行編程麸折,它的關注點更高:如何在多個 cpu 上提升效率锡凝。
具體實施
這三種編程方式從上到下,抽象度層次是從低到高的垢啼,抽象度越高的使用越簡單窜锯,也是Apple最推薦使用的。
三種方式的優(yōu)缺點介紹:
1)NSThread:
優(yōu)點:NSThread 比其他兩個輕量級
缺點:需要自己管理線程的生命周期芭析,線程同步锚扎。線程同步對數(shù)據(jù)的加鎖會有一定的系統(tǒng)開銷
NSThread實現(xiàn)的技術有下面三種:
一般使用cocoa thread 技術。
(一)NSThread的使用*
NSThread 有兩種直接創(chuàng)建方式:
- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument
- (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument
參數(shù)的意義:
selector :線程執(zhí)行的方法馁启,這個selector只能有一個參數(shù)驾孔,而且不能有返回值。
target :selector消息發(fā)送的對象
argument:傳輸給target的唯一參數(shù)惯疙,也可以是nil
第一種方式會直接創(chuàng)建線程并且開始運行線程助币,第二種方式是先創(chuàng)建線程對象,然后再運行線程操作螟碎,在運行線程操作前可以設置線程的優(yōu)先級等線程信息
不顯式創(chuàng)建線程的方法:
用NSObject的類方法 performSelectorInBackground:withObject: 創(chuàng)建一個線程:
[Obj performSelectorInBackground:@selector(doSomething) withObject:nil];
參考鏈接:http://www.reibang.com/p/686dbf4bbb52
(二) NSOperation
優(yōu)點:不需要關心線程管理眉菱,數(shù)據(jù)同步的事情,可以把精力放在自己需要執(zhí)行的操作上掉分。
Cocoa operation 相關的類是 NSOperation 俭缓,NSOperationQueue。
NSOperation是個抽象類酥郭,使用它必須用它的子類华坦,可以實現(xiàn)它或者使用它定義好的兩個子類:NSInvocationOperation 和 NSBlockOperation。
創(chuàng)建NSOperation子類的對象不从,把對象添加到NSOperationQueue隊列里執(zhí)行惜姐。
NSOperation 實現(xiàn)多線程的使用步驟分為三步:
創(chuàng)建操作:先將需要執(zhí)行的操作封裝到一個 NSOperation 對象中。
創(chuàng)建隊列:創(chuàng)建 NSOperationQueue 對象椿息。
將操作加入到隊列中:將 NSOperation 對象添加到 NSOperationQueue 對象中歹袁。
之后呢,系統(tǒng)就會自動將 NSOperationQueue 中的 NSOperation 取出來寝优,在新線程中執(zhí)行操作条舔。
NSOperationQueue 控制串行執(zhí)行、并發(fā)執(zhí)行
之前我們說過乏矾,NSOperationQueue 創(chuàng)建的自定義隊列同時具有串行孟抗、并發(fā)功能迁杨,上邊我們演示了并發(fā)功能,那么他的串行功能是如何實現(xiàn)的凄硼?
這里有個關鍵屬性 maxConcurrentOperationCount铅协,叫做最大并發(fā)操作數(shù)。用來控制一個特定隊列中可以有多少個操作同時參與并發(fā)執(zhí)行摊沉。
注意:這里 maxConcurrentOperationCount 控制的不是并發(fā)線程的數(shù)量警医,而是一個隊列中同時能并發(fā)執(zhí)行的最大操作數(shù)。而且一個操作也并非只能在一個線程中運行坯钦。
最大并發(fā)操作數(shù):maxConcurrentOperationCount
maxConcurrentOperationCount 默認情況下為-1预皇,表示不進行限制,可進行并發(fā)執(zhí)行婉刀。
maxConcurrentOperationCount 為1時吟温,隊列為串行隊列。只能串行執(zhí)行突颊。
maxConcurrentOperationCount 大于1時鲁豪,隊列為并發(fā)隊列。操作并發(fā)執(zhí)行律秃,當然這個值不應超過系統(tǒng)限制爬橡,即使自己設置一個很大的值,系統(tǒng)也會自動調(diào)整為 min{自己設定的值棒动,系統(tǒng)設定的默認最大值}糙申。
參考鏈接:http://www.reibang.com/p/4b1d77054b35
(三)GCD
Grand Central Dispatch (GCD)是Apple開發(fā)的一個多核編程的解決方法。在iOS4.0開始之后才能使用船惨。GCD是一個替代諸如NSThread, NSOperationQueue, NSInvocationOperation等技術的很高效和強大的技術」衤悖現(xiàn)在的iOS系統(tǒng)都升級到7了,所以不用擔心該技術不能使用粱锐。
使用 GCD 有很多好處啊疙挺,具體如下:
- GCD 可用于多核的并行運算;
- GCD 會自動利用更多的 CPU 內(nèi)核(比如雙核怜浅、四核)铐然;
- GCD 會自動管理線程的生命周期(創(chuàng)建線程、調(diào)度任務恶座、銷毀線程)搀暑;
- 程序員只需要告訴 GCD 想要執(zhí)行什么任務,不需要編寫任何線程管理代碼奥裸。
GCD 擁有以上這么多的好處险掀,而且在多線程中處于舉足輕重的地位。那么我們就很有必要系統(tǒng)地學習一下 GCD 的使用方法湾宙。
2. GCD 任務和隊列
學習 GCD 之前樟氢,先來了解 GCD 中兩個核心概念:『任務』 和 『隊列』。
任務:就是執(zhí)行操作的意思侠鳄,換句話說就是你在線程中執(zhí)行的那段代碼埠啃。在 GCD 中是放在 block 中的。執(zhí)行任務有兩種方式:『同步執(zhí)行』 和 『異步執(zhí)行』伟恶。兩者的主要區(qū)別是:是否等待隊列的任務執(zhí)行結束碴开,以及是否具備開啟新線程的能力。
-
同步執(zhí)行(sync):
- 同步添加任務到指定的隊列中博秫,在添加的任務執(zhí)行結束之前潦牛,會一直等待,直到隊列里面的任務完成之后再繼續(xù)執(zhí)行挡育。
- 只能在當前線程中執(zhí)行任務巴碗,不具備開啟新線程的能力。
-
異步執(zhí)行(async):
- 異步添加任務到指定的隊列中即寒,它不會做任何等待橡淆,可以繼續(xù)執(zhí)行任務。
- 可以在新的線程中執(zhí)行任務母赵,具備開啟新線程的能力逸爵。
舉個簡單例子:你要打電話給小明和小白。
『同步執(zhí)行』 就是:你打電話給小明的時候凹嘲,不能同時打給小白师倔。只有等到給小明打完了,才能打給小白(等待任務執(zhí)行結束)周蹭。而且只能用當前的電話(不具備開啟新線程的能力)溯革。
『異步執(zhí)行』 就是:你打電話給小明的時候,不用等著和小明通話結束(不用等待任務執(zhí)行結束)谷醉,還能同時給小白打電話致稀。而且除了當前電話,你還可以使用其他一個或多個電話(具備開啟新線程的能力)俱尼。
注意:異步執(zhí)行(async)雖然具有開啟新線程的能力抖单,但是并不一定開啟新線程。這跟任務所指定的隊列類型有關(下面會講)遇八。
隊列(Dispatch Queue):這里的隊列指執(zhí)行任務的等待隊列矛绘,即用來存放任務的隊列。隊列是一種特殊的線性表刃永,采用 FIFO(先進先出)的原則货矮,即新任務總是被插入到隊列的末尾,而讀取任務的時候總是從隊列的頭部開始讀取斯够。每讀取一個任務囚玫,則從隊列中釋放一個任務喧锦。隊列的結構可參考下圖:
在 GCD 中有兩種隊列:『串行隊列』 和 『并發(fā)隊列』。兩者都符合 FIFO(先進先出)的原則抓督。兩者的主要區(qū)別是:執(zhí)行順序不同燃少,以及開啟線程數(shù)不同。
-
串行隊列(Serial Dispatch Queue):
- 每次只有一個任務被執(zhí)行铃在。讓任務一個接著一個地執(zhí)行阵具。(只開啟一個線程,一個任務執(zhí)行完畢后定铜,再執(zhí)行下一個任務)
-
并發(fā)隊列(Concurrent Dispatch Queue):
- 可以讓多個任務并發(fā)(同時)執(zhí)行阳液。(可以開啟多個線程,并且同時執(zhí)行任務)
注意:并發(fā)隊列 的并發(fā)功能只有在異步(dispatch_async)方法下才有效揣炕。
參考鏈接:http://www.reibang.com/p/2d57c72016c6
ViewController生命周期
按照執(zhí)?順序排列:
- initWithCoder:通過nib?件初始化時觸發(fā)帘皿。
- awakeFromNib:nib文件被加載的時候,會發(fā)生一個awakeFromNib的消息到nib文件中的每個對象祝沸。
- loadView:開始加載視圖控制器?帶的view矮烹。
- viewDidLoad:視圖控制器的view被加載完成。
- viewWillAppear:視圖控制器的view將要顯示在window上罩锐。
- updateViewConstraints:視圖控制器的view開始更新AutoLayout約束奉狈。
- viewWillLayoutSubviews:視圖控制器的view將要更新內(nèi)容視圖的位置。
- viewDidLayoutSubviews:視圖控制器的view已經(jīng)更新視圖的位置涩惑。
- viewDidAppear:視圖控制器的view已經(jīng)展示到window上仁期。
- viewWillDisappear:視圖控制器的view將要從window上消失。
- viewDidDisappear:視圖控制器的view已經(jīng)從window上消失竭恬。
struct跛蛋、Class的區(qū)別
class可以繼承,struct不可以
class是引用類型痊硕,struct是值類型
struct在function里修改property時需要mutating關鍵字修飾
NSArray與NSSet的區(qū)別赊级?
NSArray內(nèi)存中存儲地址連續(xù),而NSSet不連續(xù)
NSSet效率高岔绸,內(nèi)部使用hash查找理逊;NSArray查找需要遍歷
NSSet通過anyObject訪問元素,NSArray通過下標訪問
NSHashTable與NSMapTable盒揉?
NSHashTable是NSSet的通用版本晋被,對元素弱引用,可變類型刚盈;可以在訪問成員時copy
NSMapTable是NSDictionary的通用版本羡洛,對元素弱引用,可變類型藕漱;可以在訪問成員時copy
(注:NSHashTable與NSSet的區(qū)別:NSHashTable可以通過option設置元素弱引用/copyin欲侮,只有可變類型崭闲。但是添加對象的時候NSHashTable耗費時間是NSSet的兩倍。
NSMapTable與NSDictionary的區(qū)別:同上)
屬性關鍵字assign锈麸、retain镀脂、weak牺蹄、copy
assign:用于基本數(shù)據(jù)類型和結構體忘伞。如果修飾對象的話,當銷毀時沙兰,屬性值不會自動置nil氓奈,可能造成野指針。
weak:對象引用計數(shù)為0時鼎天,屬性值也會自動置nil
retain:強引用類型舀奶,ARC下相當于strong,但block不能用retain修飾斋射,因為等同于assign不安全育勺。
strong:強引用類型,修飾block時相當于copy罗岖。