李洪強iOS經典面試題140-UI

李洪強iOS經典面試題140-UI

 

UI

viewcontroller的一些方法的說明viewDidLoad,viewWillDisappear, viewWillAppear方法的 順序和做用?

viewWillAppear:視圖即將可見時調用。默認狀況下不執行任何操做css

viewDidAppear:視圖已徹底過渡到屏幕上時調用java

viewWillDisappear:視圖被駁回時調用,覆蓋或以其餘方式隱藏。默認狀況下不執行任何操做ios

viewDidDisappear:視圖被駁回後調用,覆蓋或以其餘方式隱藏。默認狀況下不執行任何操做loadView; .這是當他們沒有正在使用nib視圖頁面,子類將會建立本身的自定義視圖層。毫不能直接調用。web

viewDidLoad:在視圖加載後被調用,若是是在代碼中建立的視圖加載器,他將會在loadView方法後被調用,若是是從nib視圖頁面輸出,他將會在視圖設置好後後被調用。面試

「initWithNibName: bundle:」載入nib檔案來初始化「loadView」載入視圖「viewDidLoad」在載入視圖至內存後會呼叫的方法「viewDidUnload」在視圖從內存中釋放後會呼叫的方法 (當內存太低,釋放一些不須要的視圖時調用)算法

「viewWillAppear」當收到視圖在視窗將可見時的通知會呼叫的方法編程

「viewDidAppear」當收到視圖在視窗已可見時的通知會呼叫的方法數組

「viewWillDisappear」當收到視圖將去除、被覆蓋或隱藏於視窗時的通知會呼叫的方法瀏覽器

「viewDidDisappear」當收到視圖已去除、被覆蓋或隱藏於視窗時的通知會呼叫的方法緩存

「didReceiveMemoryWarning」收到系統傳來的內存警告通知後會執行的方法

「shouldAutorotateToInterfaceOrientation」是否支持不一樣方向的旋轉視圖

「willAnimateRotationToInterfaceOrientation」在進行旋轉視圖前的會執行的方法(用於調整旋轉視圖之用)

代碼的執行順序

一、 alloc 建立對象,分配空間

二、init (initWithNibName) 初始化對象,初始化數據

三、loadView 從nib載入視圖 ,一般這一步不須要去幹涉。除非你沒有使用xib文件建立視圖

四、viewDidLoad 載入完成,能夠進行自定義數據以及動態建立其餘控件

五、viewWillAppear 視圖將出如今屏幕以前,立刻這個視圖就會被展示在屏幕上了

六、viewDidAppear 視圖已在屏幕上渲染完成當一個視圖被移除屏幕而且銷燬的時候的執行順序,這個順序差很少和上面的相反

一、viewWillDisappear 視圖將被從屏幕上移除以前執行

二、viewDidDisappear 視圖已經被從屏幕上移除,用戶看不到這個視圖了

三、dealloc 視圖被銷燬,此處須要對你在init和viewDidLoad中建立的對象進行釋放

什麼是key window?

  • 一個窗口當前能接受鍵盤和非觸摸事件時,便被認爲是主窗口。而觸摸事件則被投遞到觸摸發生的窗口,沒有相應座標值的事件被投遞到主窗口。同一時刻只有一個窗口是主窗口。

談一談你是怎麼封裝view的

- 先添加所需子控件 - 再接收模型數據根據模型數據設置子控件數據和位置 - 簡而言之, 本身的事情本身作, 把不須要暴露出去的封裝起來

簡單說一下APP的啓動過程,從main文件開始提及

 程序啓動分爲兩類:1.有storyboard 2.沒有storyboard 有storyboard狀況下: 1.main函數 2.UIApplicationMain * 建立UIApplication對象 * 建立UIApplication的delegate對象 3.根據Info.plist得到Main.storyboard的文件名,加載Main.storyboard(有storyboard) * 建立UIWindow * 建立和設置UIWindow的rootViewController * 顯示窗口 沒有storyboard狀況下: 1.main函數 2.UIApplicationMain * 建立UIApplication對象 * 建立UIApplication的delegate對象 3.delegate對象開始處理(監聽)系統事件(沒有storyboard) * 程序啓動完畢的時候, 就會調用代理的application:didFinishLaunchingWithOptions:方法 * 在application:didFinishLaunchingWithOptions:中建立UIWindow * 建立和設置UIWindow的rootViewController * 顯示窗口

怎麼解決緩存池滿的問題(cell)

iOS中不存在緩存池滿的狀況,由於一般咱們ios中開發,對象都是在須要的時候纔會建立,有種經常使用的說話叫作懶加載,還有在UITableView中通常只會建立剛開始出如今屏幕中的cell,以後都是從緩存池裏取,不會在建立新對象。緩存池裏最多也就一兩個對象,緩存池滿的這種狀況通常在開發java中比較常見,java中通常把最近最少使用的對象先釋放。

UIButton與UITableView的層級結構

  • 繼承結構,屬於內部的子控件結構

  • UIButton爲:UIButton > UIControl > UIView > UIResponder > NSObject

  • UITableView爲:UITableView > UIScrollView > UIView > UIResponder > NSObject

設置scroll view的contensize能在Viewdidload裏設置麼,爲何

  • 通常狀況下能夠設置在viewDidLoad中,但在autolayout下,系統會在viewDidAppear以前根據subview的constraint從新計算scrollview的contentsize。 這就是爲何,在viewdidload裏面手動設置了contentsize沒用。由於在後面,會再從新計算一次,前面手動設置的值會被覆蓋掉。

  • 解決辦法就是:

    • 去除autolayout選項,本身手動設置contentsize

    • 若是要使用autolayout,要麼本身設置完subview的constraint,而後讓系統自動根據constraint計算出contentsize。要麼就在viewDidAppear裏面本身手動設置contentsize。

簡述你對UIView、UIWindow和CALayer的理解

  • UIView: 屬於UIkit.framework框架,負責渲染矩形區域的內容,爲矩形區域添加動畫,響應區域的觸摸事件,佈局和管理一個或多個子視圖

  • UIWindow:屬於UIKit.framework框架,是一種特殊的UIView,一般在一個程序中只會有一個UIWindow,但能夠手動建立多個UIWindow,同時加到程序裏面。UIWindow在程序中主要起到三個做用:

    • 做爲容器,包含app所要顯示的全部視圖

    • 傳遞觸摸消息到程序中view和其餘對象

    • 與UIViewController協同工做,方便完成設備方向旋轉的支持

  • CAlayer:屬於QuartzCore.framework,是用來繪製內容的,對內容進行動畫處理依賴與UIView來進行顯示,不能處理用戶事件。

  • UIView和CALayer是相互依賴的,UIView依賴CALayer提供內容,CALayer依賴UIView的容器顯示繪製內容。

  • (補充)UIViewController:每一個視圖控制器都有一個自帶的視圖,而且負責這個視圖相關的一切事務。方便管理視圖中的子視圖,負責model與view的通訊;檢測設備旋轉以及內存警告;是全部視圖控制類的積累,定義了控制器的基本功能。

frame和bounds有什麼不一樣?(Difference between frame and bounds?)

  • frame指的是:該view在父view座標系統中的位置和大小(參照點是父親的座標系統)

  • bounds指的是:該view在自己座標系統中的位置和大小(參照點是自己座標系統)

關於頁面間傳值的問題?

屬性傳值:A頁面設置屬性 NSString *paramString,在跳轉B頁面的時候初始化paramString。 //A頁面.h文件 @property (nonatomic, copy)NSString *paramString; //A頁面.m文件 NextViewController *nextVC = [[NextViewController alloc] init]; nextVC.paramString = @"參數傳質"; [self presentViewController:nextVC animated:YES completion:nil]; 委託delegate傳值:在B頁面定義delegate,而且設置delegate屬性,在A頁面實現delegate協議 通知notification傳值:在B頁面中發送通知,在A頁面註冊觀察者而且在不用的時候移除觀察者。 //B頁面發送通知 [[NSNotificationCenter defaultCenter] postNotificationName:@"ChangeNameNotification" object:self userInfo:@{@"name":self.nameTextField.text}]; [self dismissViewControllerAnimated:YES completion:nil]; //A頁面註冊觀察者 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(ChangeNameNotification:) name:@"ChangeNameNotification" object:nil]; } //觀察到通知時候的處理方法 -(void)ChangeNameNotification:(NSNotification*)notification{ NSDictionary *nameDictionary = [notification userInfo]; self.nameLabel.text = [nameDictionary objectForKey:@"name"]; } //通知不使用的時候移除觀察者 [[NSNotificationCenter defaultCenter] removeObserver:self]; block傳值:在B頁面定義一個block類型的變量,在B頁面跳轉A的時候調用這個block。在A頁面跳轉到B頁面的時候對B頁面的block賦值。 //B頁面定義block,並設置block類型的變量 typedef void (^ablock)(NSString *str); @property (nonatomic, copy) ablock block; //B頁面跳轉到A頁面調用這個block self.block(self.nameTextField.text); [self dismissViewControllerAnimated:YES completion:nil]; //A頁面跳轉到B頁面的時候對B頁面的block賦值,這樣在B頁面跳轉的時候就會回調這個block函數 [self presentViewController:second animated:YES completion:nil]; second.block = ^(NSString *str){ self.nameLabel.text = str; }; kvo傳值:在A頁面設置B頁面的變量second,而且對這個變量進行觀察 - (void)addObserver:(NSObject * _Nonnull)anObserver forKeyPath:(NSString * _Nonnull)keyPath options:(NSKeyValueObservingOptions)options context:(void * _Nullable)context 並在A頁面實現 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context方法。 在B頁面對變量keyPath進行設置,在A頁面都會觀察的到。 @property (nonatomic, strong) SecondViewController *second; //在A視圖跳轉到B視圖的地方添加以下代碼 self.second = [[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:nil]; [self.second addObserver:self forKeyPath:@"userName" options:NSKeyValueObservingOptionNew context:nil]; [self presentViewController:self.second animated:YES completion:nil]; //實現這個觀察對象的方法 -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context //在B頁面對userName進行設置,在A頁面均可以間聽到 單例模式傳值:經過全局的方式保存 對於通知代理面試常問, 代理和通知分別在什麼狀況下使用? 區別? 各自優勢?

關於視圖的生命週期的問題

  • 首先判斷控制器是否有視圖,若是沒有就調用loadView方法建立:經過storyboard或者代碼;

  • 隨後調用viewDidLoad,能夠進行下一步的初始化操做;只會被調用一次;

  • 在視圖顯示以前調用viewWillAppear;該函數能夠屢次調用;

  • 視圖viewDidAppear

  • 在視圖顯示以前調用viewWillDisappear;該函數能夠屢次調用;如須要);

  • 在佈局變化先後,調用viewWill/DidLayoutSubviews處理相關信息;

  • 視圖生命週期圖


  • image

響應者鏈條? (What is responder chain?)

  • 事件響應鏈。包括點擊事件,畫面刷新事件等。在視圖棧內從上至下,或者從下之上傳播. 能夠說點事件的分發,傳遞以及處理。具體能夠去看下touch事件這塊。

  • 首先解釋響應者鏈的概念

    • UIResponder類,是UIKIT中一個用於處理事件響應的基類。窗口上的全部事件觸發,都由該類響應(即事件處理入口)。因此,窗口上的View及控制器都是派生於該類的,例如UIView、UIViewController等。

    • 調用UIResponder類提供的方法或屬性,咱們就能夠捕捉到窗口上的全部響應事件,並進行處理。

    • 響應者鏈條是由多個響應者對象鏈接起來的鏈條,其中響應者對象是能處理事件的對象,全部的View和ViewController都是響應者對象,利用響應者鏈條能讓多個控件處理同一個觸摸事件.

  • 事件傳遞機制

若是當前view不能處理當前事件,那麼事件將會沿着響應者鏈(Responder Chain)進行傳遞,知道遇到能處理該事件的響應者(Responsder Object)。


image
- 接收事件的initial view若是不能處理該事件而且她不是頂層的View,則事件會往它的父View進行傳遞。 - initial view的父View獲取事件後若是仍不能處理,則繼續往上傳遞,循環這個過程。若是頂層的View仍是不能處理這個事件的話,則會將事件傳遞給它們的ViewController, - 若是ViewController也不能處理,則傳遞給Window(UIWindow),此時Window不能處理的話就將事件傳遞UIApplication,最後若是連Application也不能處理,則廢棄該事件

ViewController的loadView,viewDidLoad,viewDidUnload分別是在何時調用的?在自定義ViewController的時候這幾個函數裏面應該作什麼工做?

  • viewDidLoad在view從nib文件初始化時調用,

  • loadView在controller的view爲nil時調用。

  • 此方法在編程實現view時調用, view控制器默認會註冊memory warning notification,當viewcontroller的任何view沒有用的時候,viewDidUnload會被調用,在這裏實現將retain的view release,若是是retain的IBOutlet view屬性則不要在這裏release,IBOutlet會負責release。

UITableView的重用機制?(或者如何在一個view上顯示多個tableView,tableView要求不一樣的數據源以及不一樣的樣式 (要求自定義cell), 如何組織各個tableView的delegate和dataSource?請說說實現思路?)

  • 查看UITableView頭文件,會找到NSMutableArray visiableCells,和NSMutableArrayreusableTableCells兩個結構。

  • visiableCells內保存當前顯示的cells,reusableTableCells保存可重用的cells。

  • TableView顯示之初,reusableTableCells爲空,那麼
    [tableView dequeueReusableCellWithIdentifier:CellIdentifier]返回nil。

  • 開始的cell都是經過 [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] 來建立,並且cellForRowAtIndexPath只是調用最大顯示cell數的次數。 好比:有100條數據,iPhone一屏最多顯示10個cell。

  • 程序最開始顯示TableView的狀況是:

    • 用[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]建立10次cell,並給cell指定一樣的重用標識(固然,能夠爲不一樣顯示類型的cell指定不一樣的標識)。而且10個cell所有都加入到visiableCells數組,reusableTableCells爲空。

    • 向下拖動tableView,當cell1徹底移出屏幕,而且cell11(它也是alloc出來的,緣由同上)徹底顯示出來的時候。cell11加入到visiableCells,cell1移出visiableCells,cell1加入到reusableTableCells。

    • 接着向下拖動tableView,由於reusableTableCells中已經有值,因此,當須要顯示新的cell, cellForRowAtIndexPath再次被調用的時候,[tableView dequeueReusableCellWithIdentifier:CellIdentifier],返回cell1。 cell1加入到visiableCells,cell1 移出reusableTableCells;cell2移出 visiableCells,cell2加入到reusableTableCells。以後再須要顯示的Cell就可 以正常重用了.

    • 注意:配置Cell的時候必定要注意,對取出的重用的cell作從新賦值,不要遺留老數據。

在一個tableView中須要自定義多種樣式的cell(兩種或三種),一般你如何實現,說說思路便可?

  • 同上!

UITableView的性能優化? 滑動的時候有種卡的感受是爲何?怎麼解決?

  • 在使用第三方應用時,卻常常遇到性能上的問題,廣泛表如今滾動時比較卡,特別是cell中包含圖片的狀況時。
  • 實際上針對性地優化一下就能夠解決tableView滑動的時候卡頓的問題:

    • 使用不透明視圖。不透明的視圖能夠提升渲染的速度。能夠將cell及其子視圖的opaque屬性設爲YES(默認值)。

    • 不要重複建立沒必要要的cell。UITableView只須要一屏幕的UITableViewCell對象便可。所以在cell不可見時,能夠將其緩存起來,而在須要時繼續使用它便可。注意:cell被重用時,須要調用setNeedsDisplayInRect:或setNeedsDisplay方法重繪cell。

    • 減小動畫效果的使用,最好不要使用insertRowsAtIndexPaths:withRowAnimation:方法,而是直接調用reloadData方法。

    • 減小視圖的數目。Cell包含了textLabel、detailTextLabel和imageView等view,而你還能夠自定義一些視圖放在它的contentView裏,建立它會消耗較多資源,而且也影響渲染的性能。

    • cell包含圖片,且數目較多,使用自定義的cell速度會比使用默認的要快。繼承UITableViewCell,重寫drawRect方法:- (void)drawRect:(CGRect)rect { if (image) { [image drawAtPoint:imagePoint]; self.image = nil; } else { [placeHolder drawAtPoint:imagePoint]; } [text drawInRect:textRect withFont:font lineBreakMode:UILineBreakModeTailTruncation]; }
      不過這樣一來,你會發現選中一行後,這個cell就變藍了,其中的內容就被擋住了。最簡單的方法就是將cell的selectionStyle屬性設爲UITableViewCellSelectionStyleNone,這樣就不會被高亮了。

      -不須要與用戶交互時,使用CALayer,將內容繪製到layer上,而後對cell的contentView.layer調用addSublayer:方法。這個例子中,layer並不會顯著影響性能,但若是layer透明,或者有圓角、變形等效果,就會影響到繪製速度了。解決辦法可參見後面的預渲染圖像。

    • 不要作多餘的繪製工做。在實現drawRect:的時候,它的rect參數就是須要繪製的區域,這個區域以外的不須要進行繪製。

    • 預渲染圖像。你會發現即便作到了上述幾點,當新的圖像出現時,仍然會有短暫的停頓現象。解決的辦法就是在圖形上下文中畫,導出成UIImage對象,而後再繪製到屏幕。(頭像圓角,或者其餘變形的時候,用圖形上下文能提升性能。)異步繪製

    • 不要阻塞主線程。tableview在更新數據時,整個界面卡住不動,徹底不響應用戶請求。常見的是網絡請求,等待時間長待數秒。

    • 解決方案:使用多線程,讓子線程去執行這些函數或方法。

    • 注意:當下載線程數超過2時,會顯著影響主線程的性能。因此在不須要響應用戶請求時,下載線程數能夠增長到5,不建議再加了,以加快下載速度。若是用戶正在交互,應把線程數量控制在2個之內。

    • 提早計算並緩存好高度,由於heightforrowatindexpath調用很是頻繁

    • 選擇正確的數據結構:學會選擇對業務場景最合適的數組結構是寫出高效代碼的基礎。好比,數組: 有序的一組值。使用索引來查詢很快,使用值查詢很慢,插入/刪除很慢。字典: 存儲鍵值對,用鍵來查找比較快。集合: 無序的一組值,用值來查找很快,插入/刪除很快。

    • gzip/zip壓縮:當從服務端下載相關附件時,能夠經過gzip/zip壓縮後再下載,使得內存更小,下載速度也更快。

      tableview的cell裏如何嵌套collection view?

思路同網易新聞相似,用自定義的繼承自UITableViewCell的類,在initWithFrame的構造方法中, 初始化自定義的繼承自UICollectionView的類

下拉和上拉的原理?

  • 以tableView的上拉刷新爲例:

    • 爲了進行無縫閱讀, 經過tableView的代理方法, willDisplayCell判斷是不是最後一行,

    • 若是是最後一行, 在顯示最後一行的同時, 判斷當前是否存在上拉刷新

    • 若是當前沒有上拉刷新, 就進行加載數據, 啓動小菊花轉啊轉。

  • 以tableView的下拉刷新爲例:

    • 判斷當前的上拉刷新視圖是否動畫

    • 若是沒有動畫, 就不是上拉刷新

    • 而後下拉刷新加載數據

    • 加載完畢數據關閉刷新

如何實現cell的動態的行高?

  • 若是但願每條數據顯示自身的行高, 必須設置兩個屬性, 1.預估行高, 2.自定義行高

  • 設置預估行高 tableView.estimatedRowHeight = 200

  • 設置定義行高 tableView.rowHeight = UITableViewAutomaticDimension

  • 若是要讓自定義行高有效, 必須讓容器視圖有一個自下而上的約束

談談webView

  • iOS開發中webview和native code的配合上的一些經驗和技巧。

  • webview與運維成本低,更新幾乎不依賴App的版本;但在交互和性能上與跟native code有很大差距。

  • native code與之對應。

  • HTML5確實給web帶入了一個新時代。這個時代是什麼,web app。也就是說,只有脫離native的這個前提,在瀏覽器的環境下,HTML5的意義才能顯現,而咱們討論iOS App的時候,HTML5顯然沒什麼意義。

  • 無論是用webview仍是native code,兩個原則:

    • 用戶體驗不打折

    • 運維成本低

  • 爲何不提開發成本。由於作web開發和iOS開發根本就是兩回事。固然,web開發發展了這麼多年,對於某些功能實現是要比native app快。但多數狀況,同一個功能,對於iOS開發者和web開發者,用各自擅長的方式開發成本都最低,因此說某個功能開發成本低,每每是一個僞命題。

  • 剛剛說了,webview的優點在於更新不依賴版本,那麼在一款App中,只有會頻繁更新的界面考慮webview纔有意義。那麼哪些界面會頻繁更新,這就要因App而異了。

  • 首頁。首頁資源可謂必爭之地,內容一天一換是正常現象,一天幾換也不稀奇。而若是僅僅是內容的更換,非要上個webview就顯得有些激進了。而事實上首頁的變化千奇百怪,逢年過節變個臉,特殊狀況掛個公告,偶爾還要特批強推一把某個業務,等等。此前,我在設計App首頁的時候,把首頁配置設計的很是複雜。App端要處理n種狀況,n各參數,server端要記住n種規則,直到一天,我崩潰了,把首頁徹底換成webview,才豁然開朗。

    • 活動頁。作互聯網都知道,活動,是一個最多見的運營手段。特色是,週期短,功能少,但基本不能複用。這些特色都標識了活動不適合作native,要用webview實現。即便有人告訴你說,個人活動是一個長期活動並且形式不變,也不要相信他。由於在第二期,第三期,第四期他會分別加上一些很是詭異,卻有很合理的小變動,而這些變動是你在那個版本根本沒法實現的。

    • 試水的新功能。這種界面,每每設計不成熟,須要在運行過程當中不斷收集用戶反饋,更新升級,甚至決定去留。因此,只有webview才能hold住如此不穩定的功能。切記在一個功能尚未肯定以前,不要大張旗鼓單位開發native code,要知道,你寫的這些代碼,三天後就要改一遍,並且要發佈上線。

    • 富文本內容。這個不用多說了吧,按照HTML的經常使用標籤作一個webtext可不是小工程。並且富文本的變化太多了,一點沒法匹配,都會致使整個界面巨醜。

    • OK,上邊說了我認爲最該使用webview的4個界面,分別帶有不一樣的特色,但webview的交互是個短板,所以webview在一個App中,只能做爲界面,不容許在界面中出現動做。而一個webview的界面如何跟native code結合起來呢,個人答案是,超連接。在webview上點擊超連接,會調用webview delegate的shouldload方法,自這裏攔截請求,進行處理。因爲webview的連接都是URL,所以我建議,把整個App的界面都用URL管理起來。

    • 長相問題,webview很難長成native的view。方案:長不成也要裝成。在一些狀況下,禁用webview滾動,使用滾動框架(iScroll不錯)去實現。webview上下留出200pixel的空白背景,y從-200開始。不然你們知道,webview上下會有陰影的背景,不藏起來會很醜。等等,還有不少其餘的方法去假裝webview,是要視情景而用。

    • cell中嵌套webview,在oc中調用js獲取web的高度, CGFloat height = [[self.webView stringByEvaluatingJavaScriptFromString:@"document.body.offsetHeight"] floatValue];在經過webViewDidFinishLoad裏面更新行高。

awakeFromNib與viewdidload區別

  • awakefromnib:當.nib文件被加載的時候,會發送一個awakefromnib消息到.nib文件中的每一個對象,每一個對象均可以定義本身的awakefromnib函數來響應這個消息,執行必要操做。也就是說 經過.nib文件建立view對象執行awakefromnib
  • viewdidload:當view對象被加載到內存就會執行viewdidload,無論是經過nib仍是代碼形式,建立對象就會執行viewdidload

layoutSubview什麼時候調用?

  • 初始化init方法時不會觸發
  • 滾動uiscrollview觸發
  • 旋轉屏幕觸發
  • 改變view的值觸發,前提是frame改變了
  • 改變uiview的大小觸發

viewcontroller的didreceivememorywaring在何時調用 默認操做是什麼

  • 應用程序收到來自系統的內存警告時,調用didreceivememorywaring方法
  • 默認作法:控制器上的view再也不窗口上顯示時,調用viewWillUnload,直接銷燬view,並調用viewdidunload

UIWindow和UIView和 CALayer 的聯繫和區別?

  • UIView是視圖的基類,UIViewController是視圖控制器的基類,UIResponder是表示一個能夠在屏幕上響應觸摸事件的對象;
  • UIwindow是UIView的子類,UIWindow的主要做用:一是提供一個區域來顯示UIView,二是將事件(event)的分發給UIView,一個應用基本上只有一個UIWindow.
    圖層不會直接渲染到屏幕上,UIView是iOS系統中界面元素的基礎,全部的界面元素都是繼承自它。它自己徹底是由CoreAnimation來實現的。它真正的繪圖部分,是由一個CALayer類來管理。UIView自己更像是一個CALayer的管理器。一個UIView上能夠有n個CALayer,每一個layer顯示一種東西,加強UIView的展示能力。
  • 均可以顯示屏幕效果
  • 若是須要用戶交互就要用UIVIew,其可接收觸摸事件(繼承UIResponder),而CALayer不能接收觸摸事件
  • 若是沒有用戶交互可選用CALayer,由於其所在庫較小,佔用的資源較少

UIScrollView

  • contentsize 內容視圖的尺寸
  • contentoffset 內容視圖當前位置相對滾動視圖frame的偏移量
  • contentinset 內容視圖相對滾動視圖frame的展現原點

如何實現瀑布流,流水佈局

  • 使用UICollectionView
  • 使用自定義的FlowLayout
  • 須要在layoutAttributesForElementsInRect中設置自定義的佈局(item的frame)
  • 在 prepareLayout中計算佈局
  • 遍歷數據內容,根據索引取出對應的attributes(使用layoutAttributesForCellWithIndexPath),根據九宮格算法設置佈局
  • 細節1: 實時佈局,重寫shouldInvalidateLayoutForBoundsChange(bounds改變從新佈局,scrollview的contentoffset>bounds)
  • 細節2: 計算設置itemsize(保證內容顯示完整,uicollectionview的content size是根據itemize計算的),根據列最大高度/對應列數量求出,最大高度累加獲得
  • 細節3: 追加item到最短列,避免底部良莠不齊.

UIImage有哪幾種加載方式

  • 二進制 imageWithData
  • Bundle imageWithName
  • 本地路徑 imageWithContentOfFile

描述九宮格算法

  • NSInteger col = x;//定義列數
  • NSInteger index = self.shopsView.subviews.count;//獲取下標
  • CGFloat margin = (self.shopsView.frame.size.width - col*viewW) / (col - 1);//定義間隔
  • CGFloat viewX = (index % col ) * (viewW + margin);
  • CGFloat viewY = (index / col ) * (viewH + 10);

實現圖片輪播圖

  • ScrollView只須要設置三個ImageView便可,而且默認顯示中間的ImageView
  • 根據ScrollView的移動狀況,迅速變化三個ImageView中圖片數據
  • ImageView更新完畢後,偷偷把ScrollView拉回到中間的ImageView位置,這樣視覺效果上就實現了無限循環的效果

應用的生命週期

  • -(BOOL)application:(UIApplication )application willFinishLaunchingWithOptions:(NSDictionary )launchOptions 告訴代理進程啓動但還沒進入狀態保存
  • -(BOOL)application:(UIApplication )application didFinishLaunchingWithOptions:(NSDictionary )launchOptions 告訴代理啓動基本完成程序準備開始運行
  • -(void)applicationWillResignActive:(UIApplication *)application 當應用程序將要入非活動狀態執行,在此期間,應用程序不接收消息或事件,好比來電話了
  • -(void)applicationDidBecomeActive:(UIApplication *)application 當應用程序入活動狀態執行,這個恰好跟上面那個方法相反
  • -(void)applicationDidEnterBackground:(UIApplication *)application 當程序被推送到後臺的時候調用。因此要設置後臺繼續運行,則在這個函數裏面設置便可
  • -(void)applicationWillEnterForeground:(UIApplication *)application 當程序從後臺將要從新回到前臺時候調用,這個恰好跟上面的那個方法相反。
  • -(void)applicationWillTerminate:(UIApplication *)application 當程序將要退出是被調用,一般是用來保存數據和一些退出前的清理工做。

load initialize方法的區別

  • +(void)load;
    • 當類對象被引入項目時, runtime 會向每個類對象發送 load 消息
    • load 方法會在每個類甚至分類被引入時僅調用一次,調用的順序:父類優先於子類, 子類優先於分類
    • load 方法不會被類自動繼承
  • +(void)initialize;
    • 也是在第一次使用這個類的時候會調用這個方法

UIScrollView 大概是如何實現的,它是如何捕捉、響應手勢的?

  • 我對UIScrollView的理解是frame就是他的contentSize,bounds就是他的可視範圍,經過改變bounds從而達到讓用戶誤覺得在滾動,如下是一個簡單的UIScrollView實現

  • 第二個問題我的理解是解決手勢衝突,對本身添加的手勢進行捕獲和響應

// 讓UIScrollView遵照UIGestureRecognizerDelegate協議,實現這個方法,在這裏方法裏對添加的手勢進行處理就能夠解決衝突

  • (BOOL)gestureRecognizer:(UIGestureRecognizer )gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer)otherGestureRecognizer

+[UIView animateWithDuration:animations:completion:] 內部大概是如何實現的?

animateWithDuration:這就等於建立一個定時器 animations:這是建立定時器須要實現的SEL completion:是定時器結束之後的一個回調block

何時會發生「隱式動畫」?

  • 當改變CALayer的一個可作動畫的屬性,它並不能馬上在屏幕上體現出來.相反,它是從先前的值平滑過渡到新的值。這一切都是默認的行爲,你不須要作額外的操做,這就是隱式動畫

如何把一張大圖縮小爲1/4大小的縮略圖?

imgData = UIImageJPEGRepresentation(image, 0.6f)

當TableView的Cell改變時,如何讓這些改變以動畫的形式呈現?

[tableView deselectRowAtIndexPath:indexPath animated:TRUE]; // 重點是這2句代碼實現的功能 [tableView beginUpdates]; [tableView endUpdates];

爲何當 Core Animation 完成時,layer 又會恢復到原先的狀態?

  • 由於這些產生的動畫只是假象,並無對layer進行改變.那麼爲何會這樣呢,這裏要講一下圖層樹裏的呈現樹.呈現樹其實是模型圖層的複製,可是它的屬性值表示了當前外觀效果,動畫的過程實際上只是修改了呈現樹,並無對圖層的屬性進行改變,因此在動畫結束之後圖層會恢復到原先狀態

設計一個進度條。

  1. 自定義一個UIView的子類

    //提供一個成員屬性,接收下載進度值 @property (nonatomic, assign) CGFloat progress;
  2. 重寫成員屬性progress的setter

    //每次改變成員屬性progress的值,就會調用它的setter -(void)setProgress:(CGFloat)progress { _progress = progress; //當下載進度改變時,手動調用重繪方法 [self setNeedsDisplay]; }
  3. 重寫

    -(void)drawRect:(CGRect)rect(核心) -(void)drawRect:(CGRect)rect { //設置圓弧的半徑 CGFloat radius = rect.size.width * 0.5; //設置圓弧的圓心 CGPoint center = CGPointMake(radius, radius); //設置圓弧的開始的角度(弧度制) CGFloat startAngle = - M_PI_2; //設置圓弧的終止角度 CGFloat endAngle = - M_PI_2 + 2 * M_PI * self.progress; //使用UIBezierPath類繪製圓弧 UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius - 5 startAngle:startAngle endAngle:endAngle clockwise:YES]; //將繪製的圓弧渲染到圖層上(即顯示出來) [path stroke]; }

如何播放 GIF 圖片,有什麼優化方案麼?

  • UIImageView用來顯示圖片, 使用UIImageView中的動畫數組來實現圖片的動畫效果
  • 用UIWebView來顯示動態圖片
  • 第三方顯示框架
  • 經過UIImageView顯示動畫效果,其實是把動態的圖拆成了一組靜態的圖,放到數組中,播放的時候依次從數組中取出。若是播放的圖片比較少佔得內存比較小或者比較經常使用(好比工具條上一直顯示的動態小圖標),能夠選擇用imageNamed:方式獲取圖片,可是經過這種方式加到內存中,使用結束,不會本身釋放,屢次播放動畫會形成內存溢出問題。所以,對於大圖或常常更換的圖,在取圖片的時候能夠選擇imageWithContentsOfFile:方式獲取圖片,優化內存。

  • 使用UIWebView顯示圖片須要注意顯示圖片的尺寸與UIWebView尺寸的設置,若是隻是爲了顯示動態圖片,能夠禁止UIWebView滾動。在顯示動態圖片的時候,即便是動圖的背景處爲透明,默認顯示出來是白色背景,這個時候須要手動設置UIWebView的透明才能達到顯示動圖背景透明的效果。

有哪幾種方式能夠對圖片進行縮放,使用 CoreGraphics 縮放時有什麼注意事項?

  • UIImageView總體拉伸
  • UIImage局部拉伸
  • UIImage修改大小
  • images.xcassets:多虧了Xcode中Asset Catalog的slice和dice,咱們不須要代碼也能拉伸圖片。首先在Xcode中選中圖片,而後點擊右下角的Show Slicing:
  • 圖形上下文等比例縮放

XIB與Storyboards的優缺點?

- XIB:在編譯前就提供了可視化界面,能夠直接拖控件,也能夠直接給控件添加約束,更直觀一些,並且類文件中就少了建立控件的代碼,確實簡化很多,一般每一個XIB對應一個類。 - Storyboard:在編譯前提供了可視化界面,可拖控件,可加約束,在開發時比較直觀,並且一個storyboard能夠有不少的界面,每一個界面對應一個類文件,經過storybard,能夠直觀地看出整個App的結構。 - XIB:需求變更時,須要修改XIB很大,有時候甚至須要從新添加約束,致使開發週期變長。XIB載入相比純代碼天然要慢一些。對於比較複雜邏輯控制不一樣狀態下顯示不一樣內容時,使用XIB是比較困難的。當多人團隊或者多團隊開發時,若是XIB文件被髮動,極易致使衝突,並且解決衝突相對要困難不少。 - Storyboard:需求變更時,須要修改storyboard上對應的界面的約束,與XIB同樣可能要從新添加約束,或者添加約束會形成大量的衝突,尤爲是多團隊開發。對於複雜邏輯控制不一樣顯示內容時,比較困難。當多人團隊或者多團隊開發時,你們會同時修改一個storyboard,致使大量衝突,解決起來至關困難。

控制器View的加載過程?

當程序訪問了控制器的View屬性時會先判斷控制器的View是否存在,若是存在就直接返回已經存在的View;
若是不存在,就會先調用loadView這個方法;若是控制器的loadView方法實現了,就會按照loadView方法加載自定義的View;
若是控制器的loadView方法沒有實現就會判斷storyboard是否存在;
若是storyboard存在就會按照storyboard加載控制器的View;若是storyboard不存在,就會建立一個空視圖返回。

應用程序的啓動流程?

1.執行Main 2.執行UIApplicationMain函數. 3.建立UIApplication對象,並設置UIApplicationMain對象的代理. UIApplication的第三個參數就是UIApplication的名稱,若是指定爲nil,它會默認爲UIApplication. UIApplication的第四個參數爲UIApplication的代理. 4.開啓一個主運行循環.保證應用程序不退出. 5.加載info.plist.加載配置文件.判斷一下info.plist文件當中有沒有Main storyboard file base name裏面有沒有指定storyboard文件,若是有就去加載info.plist文件,若是沒有,那麼應用程序加載完畢.

事件傳遞與響應的完整過程?

在產生一個事件時,系統會將該事件加入到一個由UIApplication管理的事件隊列中, UIApplication會從事件隊列中取出最前面的事件,將它傳遞給先發送事件給應用程序的主窗口. 主窗口會調用hitTest方法尋找最適合的視圖控件,找到後就會調用視圖控件的touches方法來作具體的事情. 當調用touches方法,它的默認作法, 就會將事件順着響應者鏈條往上傳遞, 傳遞給上一個響應者,接着就會調用上一個響應者的touches方法

下列回調機制的理解不正確的是

A target-action:當兩個對象之間有⽐較緊密的關係時,如視圖控制器與其下的某個視圖。       
B delegate:當某個對象收到多個事件,並要求同一個對象來處理全部事件時。委託機制必須依賴於某個協議定義的⽅法來發送消息。       
C NSNotification:當須要多個對象或兩個無關對象處理同一個事件時。 D Block:適⽤於回調只發⽣生一次的簡單任務。 參考答案:B

給UIImageView添加圓角

  • 最直接的方法就是使用以下屬性設置:
imgView.layer.cornerRadius = 10; // 這一行代碼是很消耗性能的 imgView.clipsToBounds = YES;
  • 好處是使用簡單,操做方便。壞處是離屏渲染(off-screen-rendering)須要消耗性能。對於圖片比較多的視圖上,不建議使用這種方法來設置圓角。一般來講,計算機系統中CPU、GPU、顯示器是協同工做的。CPU計算好顯示內容提交到GPU,GPU渲染完成後將渲染結果放入幀緩衝區。
  • 簡單來講,離屏渲染,致使本該GPU乾的活,結果交給了CPU來幹,而CPU又不擅長GPU乾的活,因而拖慢了UI層的FPS(數據幀率),而且離屏須要建立新的緩衝區和上下文切換,所以消耗較大的性能。
  • 給UIImage添加生成圓角圖片的擴展API:
- (UIImage *)hyb_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; }

而後調用時就直接傳一個圓角來處理:

imgView.image = [[UIImage imageNamed:@"test"] hyb_imageWithCornerRadius:4];

這麼作就是on-screen-rendering了,經過模擬器->debug->Color Off-screen-rendering看到沒有離屏渲染了!(黃色的小圓角沒有顯示了,說明這個不是離屏渲染了)

  • 在畫以前先經過UIBezierPath添加裁剪,可是這種不實用
- (void)drawRect:(CGRect)rect { CGRect bounds = self.bounds; [[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:8.0] addClip]; [self.image drawInRect:bounds]; }
  • 經過mask遮罩實現

一個view已經初始化完畢,view上面添加了n個button(可能使用循環建立),除用view的tag以外,還能夠採用什麼辦法來找到本身想要的button來修改Button的值

這個問題有不少種方式,並且不一樣的使用場景也不同的。好比說:
•    第一種:若是是點擊某個按鈕後,纔會刷新它的值,其它不用修改,那麼不用引用任何按鈕,直接在回調時,就已經將接收響應的按鈕給傳過來了,直接經過它修改便可。
•    第二種:點擊某個按鈕後,全部與之同類型的按鈕都要修改值,那麼能夠經過在建立按鈕時將按鈕存入到數組中,在須要的時候遍歷查找。

使用drawRect有什麼影響?

  • drawRect方法依賴Core Graphics框架來進行自定義的繪製,但這種方法主要的缺點就是它處理touch事件的方式:每次按鈕被點擊後,都會用setNeddsDisplay進行強制重繪;並且不止一次,每次單點事件觸發兩次執行。這樣的話從性能的角度來講,對CPU和內存來講都是欠佳的。特別是若是在咱們的界面上有多個這樣的UIButton實例。

viewWillLayoutSubView你老是知道的。

controller layout觸發的時候,開發者有機會去從新layout本身的各個subview。
橫豎屏切換的時候,系統會響應一些函數,其中 viewWillLayoutSubviews 和 viewDidLayoutSubviews。
- (void)viewWillLayoutSubviews { [self _shouldRotateToOrientation:(UIDeviceOrientation)[UIApplication sharedApplication].statusBarOrientation]; } -(void)_shouldRotateToOrientation:(UIDeviceOrientation)orientation { if (orientation == UIDeviceOrientationPortrait ||orientation == UIDeviceOrientationPortraitUpsideDown) { // 豎屏 } else { // 橫屏 } } 經過上述一個函數就知道橫豎屏切換的接口了。 注意:viewWillLayoutSubviews只能用在ViewController裏面,在view裏面沒有響應。

一個tableView是否能夠關聯兩個不一樣的數據源?

  • 固然是能夠關聯多個不一樣的數據源,可是不能同時使用多個數據源而已。好比,一個列表有兩個篩選功能,一個是篩選城市,一個是篩選時間,那麼這兩個就是兩個數據源了。當篩選城市時,就會使用城市數據源;當篩選時間時,就會使用時間數據源。

如何自動計算cell的高度?

  • 實現原理:經過數據模型的id做爲key,以確保惟一,如何才能保證複用cell時不會出現混亂。在配置完數據後,經過更新約束,獲得最後一個控件的frame,就只能夠判斷cell實際須要的高度,而且緩存下來,下次再獲取時,判斷是否存在,若存在則直接返回。所以,只會計算一遍

UITableView是如何計算內容高度的?爲何初始化時配置數據時,獲取行高的代理方法會調用數據條數次?

  • UITableView是繼承於UIScrollView的,所以也有contentSize。要獲得tableview的contentsize,就須要獲得全部cell的高度,從而計算出總高度,才能獲得contentsize。所以,在reloadData時,就會調用該代理方法數據條數次。

一個tableView是否能夠關聯兩個不一樣的數據源?你會怎麼處理?

答:首先咱們從代碼來看,數據源如何關聯上的,實際上是在數據源關聯的代理方法裏實現的。
所以咱們並不關心如何去關聯他,他怎麼關聯上,方法只是讓我返回根據本身的須要去設置如相關的數據源。
所以,我以爲能夠設置多個數據源啊,可是有個問題是,你這是想幹嗎呢?想讓列表如何顯示,不一樣的數據源分區塊顯示?

給出委託方法的實例,而且說出UITableVIew的Data Source方法

CocoaTouch框架中用到了大量委託,其中UITableViewDelegate就是委託機制的典型應用,是一個典型的使用委託來實現適配器模式,其中UITableViewDelegate協議是目標,tableview是適配器,實現UITableViewDelegate協議,並將自身設置爲talbeview的delegate的對象,是被適配器,通常狀況下該對象是UITableViewController。 UITableVIew的Data Source方法有- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section; - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;

cocoa touch框架

答:iPhone OS 應用程序的基礎 Cocoa Touch 框架重用了許多 Mac 系統的成熟模式,可是它更多地專一於觸摸的接口和優化。

UIKit 爲您提供了在 iPhone OS 上實現圖形,事件驅動程序的基本工具,其創建在和 Mac OS X 中同樣的 Foundation 框架上,包括文件處理,網絡,字符串操做等。

Cocoa Touch 具備和 iPhone 用戶接口一致的特殊設計。有了 UIKit,您可使用 iPhone OS 上的獨特的圖形接口控件,按鈕,以及全屏視圖的功能,您還可使用加速儀和多點觸摸手勢來控制您的應用。

各色俱全的框架 除了UIKit 外,Cocoa Touch 包含了建立世界一流 iPhone 應用程序須要的全部框架,從三維圖形,到專業音效,甚至提供設備訪問 API 以控制攝像頭,或經過 GPS 獲知當前位置。

Cocoa Touch 既包含只須要幾行代碼就能夠完成所有任務的強大的 Objective-C 框架,也在須要時提供基礎的 C 語言 API 來直接訪問系統。這些框架包括:

Core Animation:經過 Core Animation,您就能夠經過一個基於組合獨立圖層的簡單的編程模型來建立豐富的用戶體驗。

Core Audio:Core Audio 是播放,處理和錄製音頻的專業技術,可以輕鬆爲您的應用程序添增強大的音頻功能。

Core Data:提供了一個面向對象的數據管理解決方案,它易於使用和理解,甚至可處理任何應用或大或小的數據模型。

功能列表:框架分類

下面是 Cocoa Touch 中一小部分可用的框架:

音頻和視頻:Core Audio ,OpenAL ,Media Library ,AV Foundation

數據管理 :Core Data ,SQLite

圖形和動畫 :Core Animation ,OpenGL ES ,Quartz 2D

網絡:Bonjour ,WebKit ,BSD Sockets

用戶應用:Address Book ,Core Location ,Map Kit ,Store Kit

xib文件的構成分爲哪3個圖標?都具備什麼功能。

File’s Owner 是全部 nib 文件中的每一個圖標,它表示從磁盤加載 nib 文件的對象;

First Responder 就是用戶當前正在與之交互的對象;

View 顯示用戶界面;完成用戶交互;是 UIView 類或其子類。

簡述應用程序按Home鍵進入後臺時的生命週期,和從後臺回到前臺時的生命週期? 應用程序:

-[AppDelegate application:willFinishLaunchingWithOptions:] -[AppDelegate application:didFinishLaunchingWithOptions:] -[AppDelegate applicationDidBecomeActive:]

退到後臺:

-[AppDelegate applicationWillResignActive:] -[AppDelegate applicationDidEnterBackground:]

回到前臺:

-[AppDelegate applicationWillEnterForeground:] -[AppDelegate applicationDidBecomeActive:]

ViewController之間,
加載頁面:

-[mainViewController viewDidLoad] -[mainViewController viewWillAppear:] -[mainViewController viewWillLayoutSubviews] -[mainViewController viewDidLayoutSubviews] -[mainViewController viewDidAppear:]

退出當前頁面:

-[mainViewController viewWillDisappear:] -[mainViewController viewDidDisappear:]

返回以前頁面:

-[mainViewController viewWillAppear:] -[mainViewController viewWillLayoutSubviews] -[mainViewController viewDidLayoutSubviews] -[mainViewController viewDidAppear:]

是否使用Core Text或者Core Image等?若是使用過,請談談你使用Core Text或者Core Image的體驗。

CoreText
•    隨意修改文本的樣式
•    圖文混排(純C語言) • 國外:Niumb Core Image(濾鏡處理) * 能調節圖片的各類屬性(對比度, 色溫, 色差等)

分析一下使用手機獲取驗證碼註冊帳號的實現邏輯(給了一個示例圖),發送到手機的驗證碼超過60秒鐘後從新發送

  • 定義一個label屬性,賦值爲60秒,再定義一個count 設置一個timer 每次減小一秒 把count-- 再把count的值拼接到label上 當count == 0 的時候 再顯示從新發送

你作iphone開發時候,有哪些傳值方式,view和view之間是如何傳值的?

block, target-action ,代理,屬性

有哪幾種手勢通知方法、寫清楚方法名?

-(void)touchesBegan:(NSSet)touchedwithEvent:(UIEvent)event;

-(void)touchesMoved:(NSSet)touched withEvent:(UIEvent)event;

-(void)touchesEnded:(NSSet)touchedwithEvent:(UIEvent)event;

-(void)touchesCanceled:(NSSet)touchedwithEvent:(UIEvent)event;

文章若有問題,請留言,我將及時更正。

相關文章
相關標籤/搜索