iOS面试题02-UI篇
生活随笔
收集整理的這篇文章主要介紹了
iOS面试题02-UI篇
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
Size Classes 具體使用
對屏幕進(jìn)行分類 復(fù)制代碼UIView和CALayer是什么關(guān)系?
UIView顯示在屏幕上歸功于CALayer,通過調(diào)用drawRect方法來渲染自身的內(nèi)容,調(diào)節(jié)CALayer屬性可以調(diào)整UIView的外觀,UIView繼承自UIResponder,比起CALayer可以響應(yīng)用戶事件,Xcode6之后可以方便的通過視圖調(diào)試功能查看圖層之間的關(guān)系 UIView是iOS系統(tǒng)中界面元素的基礎(chǔ),所有的界面元素都繼承自它。它內(nèi)部是由Core Animation來實現(xiàn)的,它真正的繪圖部分,是由一個叫CALayer(Core Animation Layer)的類來管理。UIView本身,更像是一個CALayer的管理器,訪問它的跟繪圖和坐標(biāo)有關(guān)的屬性,如frame,bounds等,實際上內(nèi)部都是訪問它所在CALayer的相關(guān)屬性 UIView有個layer屬性,可以返回它的主CALayer實例,UIView有一個layerClass方法,返回主layer所使用的類,UIView的子類,可以通過重載這個方法,來讓UIView使用不同的CALayer來顯示,如: 復(fù)制代碼 - (class) layerClass {// 使某個UIView的子類使用GL來進(jìn)行繪制return ([CAEAGLLayer class]); } 復(fù)制代碼UIView的CALayer類似UIView的子View樹形結(jié)構(gòu),也可以向它的layer上添加子layer,來完成某些特殊的顯示。例如下面的代碼會在目標(biāo)View上敷上一層黑色的透明薄膜。 復(fù)制代碼 grayCover = [[CALayer alloc]init]; grayCover.backgroudColor = [[UIColor blackColor]colorWithAlphaComponent:0.2].CGColor; [self.layer addSubLayer:grayCover]; 復(fù)制代碼補(bǔ)充部分,這部分有深度了,大致了解一下吧,UIView的layer樹形在系統(tǒng)內(nèi)部被系統(tǒng)維護(hù)著三份copy邏輯樹,就是代碼里可以操縱的,例如更改layer的屬性等等就在這一份動畫樹,這是一個中間層,系統(tǒng)正是在這一層上更改屬性,進(jìn)行各種渲染操作顯示樹,這棵樹的內(nèi)容是當(dāng)前正被顯示在屏幕上的內(nèi)容這三棵樹的邏輯結(jié)構(gòu)都是一樣的,區(qū)別只有各自的屬性 復(fù)制代碼loadView的作用?
loadView用來自定義view,只要實現(xiàn)了這個方法,其他通過xib或storyboard創(chuàng)建的view都不會被加載 復(fù)制代碼IBOutlet連出來的視圖屬性為什么可以被設(shè)置成weak?
因為父控件的subViews數(shù)組已經(jīng)對它有一個強(qiáng)引用 復(fù)制代碼IB中User Defined Runtime Attributes如何使用?
User Defined Runtime Attributes是一個不被看重但功能非常強(qiáng)大的的特性,它能夠通過KVC的方式配置一些你在interface builder中不能配置的屬性 當(dāng)你希望在IB中作盡可能多得事情,這個特性能夠幫助你編寫更加輕量級的viewcontroller 復(fù)制代碼沙盒目錄結(jié)構(gòu)是怎樣的?各自用于那些場景?
Application:存放程序源文件,上架前經(jīng)過數(shù)字簽名,上架后不可修改 Documents:常用目錄,iCloud備份目錄,存放數(shù)據(jù) LibraryCaches:存放體積大又不需要備份的數(shù)據(jù)Preference:設(shè)置目錄,iCloud會備份設(shè)置信息 tmp:存放臨時文件,不會被備份,而且這個文件下的數(shù)據(jù)有可能隨時被清除的可能 復(fù)制代碼pushViewController和presentViewController有什么區(qū)別
兩者都是在多個試圖控制器間跳轉(zhuǎn)的函數(shù) presentViewController提供的是一個模態(tài)視圖控制器(modal) pushViewController提供一個棧控制器數(shù)組,push/pop 復(fù)制代碼請簡述UITableView的復(fù)用機(jī)制
每次創(chuàng)建cell的時候通過dequeueReusableCellWithIdentifier:方法創(chuàng)建cell,它先到緩存池中找指定標(biāo)識的cell,如果沒有就直接返回nil 如果沒有找到指定標(biāo)識的cell,那么會通過initWithStyle:reuseIdentifier:創(chuàng)建一個cell 當(dāng)cell離開界面就會被放到緩存池中,以供下次復(fù)用 復(fù)制代碼如何高性能的給 UIImageView 加個圓角?
不好的解決方案使用下面的方式會強(qiáng)制Core Animation提前渲染屏幕的離屏繪制, 而離屏繪制就會給性能帶來負(fù)面影響,會有卡頓的現(xiàn)象出現(xiàn)self.view.layer.cornerRadius = 5;self.view.layer.masksToBounds = YES;正確的解決方案:使用繪圖技術(shù) 復(fù)制代碼 - (UIImage *)circleImage {// NO代表透明UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0);// 獲得上下文CGContextRef ctx = UIGraphicsGetCurrentContext();// 添加一個圓CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);CGContextAddEllipseInRect(ctx, rect);// 裁剪CGContextClip(ctx);// 將圖片畫上去[self drawInRect:rect];UIImage *image = UIGraphicsGetImageFromCurrentImageContext();// 關(guān)閉上下文UIGraphicsEndImageContext();return image; } 復(fù)制代碼還有一種方案:使用了貝塞爾曲線"切割"個這個圖片, 給UIImageView 添加了的圓角,其實也是通過繪圖技術(shù)來實現(xiàn)的 復(fù)制代碼 UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; imageView.center = CGPointMake(200, 300); UIImage *anotherImage = [UIImage imageNamed:@"image"]; UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 1.0); [[UIBezierPath bezierPathWithRoundedRect:imageView.boundscornerRadius:50] addClip]; [anotherImage drawInRect:imageView.bounds]; imageView.image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); [self.view addSubview:imageView]; 復(fù)制代碼使用drawRect有什么影響?
drawRect方法依賴Core Graphics框架來進(jìn)行自定義的繪制 缺點(diǎn):它處理touch事件時每次按鈕被點(diǎn)擊后,都會用setNeddsDisplay進(jìn)行強(qiáng)制重繪;而且不止一次,每次單點(diǎn)事件觸發(fā)兩次執(zhí)行。這樣的話從性能的角度來說,對CPU和內(nèi)存來說都是欠佳的。特別是如果在我們的界面上有多個這樣的UIButton實例,那就會很糟糕了 這個方法的調(diào)用機(jī)制也是非常特別. 當(dāng)你調(diào)用 setNeedsDisplay 方法時, UIKit 將會把當(dāng)前圖層標(biāo)記為dirty,但還是會顯示原來的內(nèi)容,直到下一次的視圖渲染周期,才會將標(biāo)記為 dirty 的圖層重新建立Core Graphics上下文,然后將內(nèi)存中的數(shù)據(jù)恢復(fù)出來, 再使用 CGContextRef 進(jìn)行繪制 復(fù)制代碼描述下SDWebImage里面給UIImageView加載圖片的邏輯
SDWebImage 中為 UIImageView 提供了一個分類UIImageView+WebCache.h, 這個分類中有一個最常用的接口sd_setImageWithURL:placeholderImage:,會在真實圖片出現(xiàn)前會先顯示占位圖片,當(dāng)真實圖片被加載出來后在替換占位圖片 加載圖片的過程大致如下:首先會在 SDWebImageCache 中尋找圖片是否有對應(yīng)的緩存, 它會以url 作為數(shù)據(jù)的索引先在內(nèi)存中尋找是否有對應(yīng)的緩存如果緩存未找到就會利用通過MD5處理過的key來繼續(xù)在磁盤中查詢對應(yīng)的數(shù)據(jù), 如果找到了, 就會把磁盤中的數(shù)據(jù)加載到內(nèi)存中,并將圖片顯示出來如果在內(nèi)存和磁盤緩存中都沒有找到,就會向遠(yuǎn)程服務(wù)器發(fā)送請求,開始下載圖片下載后的圖片會加入緩存中,并寫入磁盤中整個獲取圖片的過程都是在子線程中執(zhí)行,獲取到圖片后回到主線程將圖片顯示出來 復(fù)制代碼設(shè)計個簡單的圖片內(nèi)存緩存器
類似上面SDWebImage實現(xiàn)原理即可 一定要有移除策略:釋放數(shù)據(jù)模型對象 復(fù)制代碼控制器的生命周期
就是問的view的生命周期,下面已經(jīng)按方法執(zhí)行順序進(jìn)行了排序 復(fù)制代碼 // 自定義控制器view,這個方法只有實現(xiàn)了才會執(zhí)行 - (void)loadView {self.view = [[UIView alloc] init];self.view.backgroundColor = [UIColor orangeColor]; } // view是懶加載,只要view加載完畢就調(diào)用這個方法 - (void)viewDidLoad {[super viewDidLoad];NSLog(@"%s",__func__); }// view即將顯示 - (void)viewWillAppear:(BOOL)animated {[super viewWillAppear:animated];NSLog(@"%s",__func__); } // view即將開始布局子控件 - (void)viewWillLayoutSubviews {[super viewWillLayoutSubviews];NSLog(@"%s",__func__); } // view已經(jīng)完成子控件的布局 - (void)viewDidLayoutSubviews {[super viewDidLayoutSubviews];NSLog(@"%s",__func__); } // view已經(jīng)出現(xiàn) - (void)viewDidAppear:(BOOL)animated {[super viewDidAppear:animated];NSLog(@"%s",__func__); } // view即將消失 - (void)viewWillDisappear:(BOOL)animated {[super viewWillDisappear:animated];NSLog(@"%s",__func__); } // view已經(jīng)消失 - (void)viewDidDisappear:(BOOL)animated {[super viewDidDisappear:animated];NSLog(@"%s",__func__); } // 收到內(nèi)存警告 - (void)didReceiveMemoryWarning {[super didReceiveMemoryWarning];NSLog(@"%s",__func__); } // 方法已過期,即將銷毀view - (void)viewWillUnload {} // 方法已過期,已經(jīng)銷毀view - (void)viewDidUnload {} 復(fù)制代碼你是怎么封裝一個view的
可以通過純代碼或者xib的方式來封裝子控件 建立一個跟view相關(guān)的模型,然后將模型數(shù)據(jù)傳給view,通過模型上的數(shù)據(jù)給view的子控件賦值 復(fù)制代碼 /*** 純代碼初始化控件時一定會走這個方法*/ - (instancetype)initWithFrame:(CGRect)frame {if(self = [super initWithFrame:frame]){[self setup];}return self; }/*** 通過xib初始化控件時一定會走這個方法*/ - (id)initWithCoder:(NSCoder *)aDecoder {if(self = [super initWithCoder:aDecoder]){[self setup];}return self; }- (void)setup {// 初始化代碼 } 復(fù)制代碼如何進(jìn)行iOS6、7的適配
通過判斷版本來控制,來執(zhí)行響應(yīng)的代碼 功能適配:保證同一個功能在6、7上都能用 UI適配:保證各自的顯示風(fēng)格 復(fù)制代碼 // iOS版本為7.0以上(包含7.0) #define iOS7 ([[UIDevice currentDevice].systemVersion doubleValue]>=7.0) 復(fù)制代碼如何渲染UILabel的文字?
通過NSAttributedString/NSMutableAttributedString(富文本) 復(fù)制代碼觸摸事件的傳遞
觸摸事件的傳遞是從父控件傳遞到子控件 如果父控件不能接收觸摸事件,那么子控件就不可能接收到觸摸事件 不能接受觸摸事件的四種情況不接收用戶交互,即:userInteractionEnabled = NO隱藏,即:hidden = YES透明,即:alpha <= 0.01未啟用,即:enabled = NO 提示:UIImageView的userInteractionEnabled默認(rèn)就是NO,因此UIImageView以及它的子控件默認(rèn)是不能接收觸摸事件的 如何找到最合適處理事件的控件:首先,判斷自己能否接收觸摸事件可以通過重寫hitTest:withEvent:方法驗證其次,判斷觸摸點(diǎn)是否在自己身上對應(yīng)方法pointInside:withEvent:從后往前(先遍歷最后添加的子控件)遍歷子控件,重復(fù)前面的兩個步驟如果沒有符合條件的子控件,那么就自己處理 復(fù)制代碼事件響應(yīng)者鏈
如果當(dāng)前view是控制器的view,那么就傳遞給控制器 如果控制器不存在,則將其傳遞給它的父控件 在視圖層次結(jié)構(gòu)的最頂層視圖也不能處理接收到的事件或消息,則將事件或消息傳遞給UIWindow對象進(jìn)行處理 如果UIWindow對象也不處理,則將事件或消息傳遞給UIApplication對象 如果UIApplication也不能處理該事件或消息,則將其丟棄 補(bǔ)充:如何判斷上一個響應(yīng)者如果當(dāng)前這個view是控制器的view,那么控制器就是上一個響應(yīng)者如果當(dāng)前這個view不是控制器的view,那么父控件就是上一個響應(yīng)者 復(fù)制代碼觸摸時間由下(UIApplication)往上(到手指點(diǎn)擊的那個view),事件響應(yīng)由上往下傳遞
轉(zhuǎn)載于:https://juejin.im/post/5a6b1c27f265da3e5b330678
總結(jié)
以上是生活随笔為你收集整理的iOS面试题02-UI篇的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 理解node.js中的 Event Lo
- 下一篇: com.alibaba.druid.sq