UIViewController

  1. 父類是UIResponder(父類是NSObject)
  2. 概念:凡是繼承自UIViewController的對象,都叫做控制器
  3. 作用:負(fù)責(zé)處理軟件界面的各種事件、負(fù)責(zé)軟件界面的創(chuàng)建和銷毀
  4. 注意:每個UIViewController專門管理一個軟件界面(view),它管理的其他所有控件都是這個view的子控件或“孫控件”
    // UIViewController用view這個強指針指著它負(fù)責(zé)的軟件界面,所以只要控制器不銷毀,軟件界面就不會銷毀
    NSLog(@"%@",viewController.view);
    

控制器的創(chuàng)建

通過storyboard創(chuàng)建控制器

  1. 詳見storyboard中“系統(tǒng)加載指定storyboard的流程”

通過xib創(chuàng)建控制器

  1. 步驟:
    1. 首先創(chuàng)建一個Xib文件
    2. Xib文件需要拖一個View描述控制器的View
    3. 需要把Xib上的View與控制器連線,并設(shè)置Xib的File'owner為控制器
    // 通過xib創(chuàng)建窗口的根控制器:initWithNibName
    // NibName:xib名稱
    ViewController *vc = [[ViewController alloc] initWithNibName:@"VC" bundle:nil];
    self.window.rootViewController = vc;
    
  • xib注意點:
    1> xib里面必須有一個view描述控制器的view,因為控制器的view 屬性必須有值。
    2> xib需要指定描述哪一個控制器,描述UIView不需要,因為xib里面可以描述很多UIView,不能固定死,但是控制器就不一樣了,一個xib就用來描述一個控制器。(設(shè)置file owner為控制器,即設(shè)置custom class)
    3> xib里面可能有很多view,需要拖線指明哪個是控制器的view
  1. 假設(shè)通過Xib創(chuàng)建XXXViewController控制器對象順序
    1. 如果nibName不為空,會去創(chuàng)建對應(yīng)的xib
    2. 如果nibName為nil,首先會去查找XXXViewController.xib,如果有,就會去加載XXXViewController.xib
    3. 如果沒有找到,就會去找XXXView.xib,如果有,也會去加載
    4. 都沒有找到,就會生成一個空的view
    5. init底層就會調(diào)用initWithNibName:bundle:(注意不會通過storyboard的方式加載)
    6. Xcode7之前是先找XXXView后找XXXViewController
  • xib如何快速創(chuàng)建控制器的view:
    1> 定義新的控制器的時候,勾選xib,會自動搞一個xib描述控制器的view.
    2> 會自動生成一個和控制器同名的xib,并且里面設(shè)置好了。

  • xib最后會轉(zhuǎn)成Nib文件,關(guān)于nib的介紹詳見UINib

  • xib和storyboard的區(qū)別 storyboard已經(jīng)指定了控制器的view,不需要我們管,xib需要我們手動設(shè)置view的custom class和owner。

控制器的view

  1. 控制器View的決定權(quán):[viewController setView:view]——>viwDidLoad——>重寫LoadView>storyboard>xib


    控制器view加載.png
  • 控制器的view是懶加載的
    -(UIView *)view
    {
        if (_view == nil) {
            [self loadView];
            [self viewDidLoad];
        }
    
        return _view;
    }
    
  • loadView的時機與重寫loadView的意義
    1. 第一次加載控制器的view時才會調(diào)用loadView
    2. 使用場景:若想自定義控制器的View就可重寫這個方法,例如:控制器的View想展示一張圖片,或者創(chuàng)建UIWebView等;
    3. 注意:一旦重寫了loadView,就不要調(diào)用[super loadView],否則會重復(fù)創(chuàng)建
     - (void)loadView
    {
    // 如果當(dāng)前控制器是窗口的根控制器,它的view可以不設(shè)置尺寸。
    UIImageView *vcView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"1"]];
    self.view = vcView;
    }
    
  1. 可以用isViewLoaded方法判斷一個UIViewController的view是否已經(jīng)被加載

  2. 只要創(chuàng)建了控制器,無論是通過storyboard,還是xib,還是手動,都會自動創(chuàng)建view,如果沒有指定view,創(chuàng)建的是一個空的view

  • 控制器view的透明度
    //alloc init創(chuàng)建空View,默認(rèn)幾乎透明(幾乎透明:alpha > 0.01)
    ViewController *vc = [[ViewController alloc] init];
    vc.view.backgroundColor = [UIColor clearColor];//空view默認(rèn)的顏色
    //vc.view.backgroundColor = [UIColor whiteColor];
    
    // 如果一個View完全透明,可以直接點擊后面的東西,可以完全穿透。(完全透明:alpha <= 0.01);另外要注意顏色與透明度無關(guān)
    vc.view.alpha = 0.02;
    

控制器的生命周期方法

  1. 生命周期方法:即控制器的view什么時候創(chuàng)建,什么時候銷毀,只要以view開頭一般都是控制器view的生命周期


    生命周期方法.png
  1. 具體的生命周期方法:(布局控件方法調(diào)用頻繁,view顯示與消失前都會調(diào)用)
// 控制器的view加載完成時調(diào)用
- (void)viewDidLoad {
    [super viewDidLoad];

    //以后打印控制器的View真實尺寸,一般不再viewDidLoad去打印,因為不準(zhǔn)確(還在加載數(shù)據(jù)),在viewDidAppear中打印
}

// 控制器的view即將顯示時調(diào)用
- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
}

// 控制器的view完全顯示時調(diào)用
// 一般用來調(diào)試控制器view的真實尺寸
- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
}

//  控制器的view即將消失時調(diào)用
- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
}

// 控制器的view完全消失的時候調(diào)用
- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
}

// 控制器的view即將布局子控件的時候調(diào)用
- (void)viewWillLayoutSubviews
{
    [super viewWillLayoutSubviews];
}

// 控制器的view布局子控件的完成時候調(diào)用
- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
}

// ARC中必須要了解
// viewDidLoad -> viewWillAppear -> viewWillLayoutSubviews -> viewDidLayoutSubviews ->  viewDidAppear -> viewWillDisappear -> viewWillLayoutSubviews -> viewDidLayoutSubviews -> viewDidDisappear    //可以看出布局控件方法調(diào)用頻繁


// 非ARC
// Unload:卸載,當(dāng)前view銷毀
//- (void)viewWillUnload
//{
//}

// 當(dāng)前view卸載完成,完全銷毀的時候調(diào)用
- (void)viewDidUnload
{
    self.datas = nil;
}

//  MRC中內(nèi)存機制解釋
//- (void)setDatas:(NSArray *)datas
//{
//    if (datas != _datas) {
//        [_datas release];
//        _datas = [datas retain];
//    }
//}

當(dāng)出現(xiàn)內(nèi)存警告時,控制器的處理流程

  1. didReceiveMemoryWarning,當(dāng)控制器接收內(nèi)存警告的時候調(diào)用
    • 內(nèi)存警告?zhèn)鬟f過程:手機內(nèi)存不足產(chǎn)生事件->通知應(yīng)用程序->調(diào)用應(yīng)用程序代理方法->把事件傳遞給窗口->窗口傳給控制器->調(diào)用控制器內(nèi)存警告的方法。


      內(nèi)存警告處理.png
  • 當(dāng)控制器接收內(nèi)容警告,會銷毀沒有顯示的控制器的view。

  • 調(diào)用viewWillUnload,viewDidUnload,銷毀控制器的view

  • viewDidUnload里面一般清空顯示在view里面的數(shù)據(jù)
    1. 為什么要清空顯示view的數(shù)據(jù):展示數(shù)據(jù)的view都不存在了,這些數(shù)據(jù)也就沒有用處了,因為數(shù)據(jù)主要是用來展示在view上
    2. 清空數(shù)據(jù)建議使用nil,清空數(shù)據(jù),在非arc和arc都通用。arc是不能使用release,而且非arc下,self.datas = nil;做的事情更多。

  • didReceiveMemoryWarning會導(dǎo)致viewDidLoad重新調(diào)用。

    • 當(dāng)收到內(nèi)存警告,導(dǎo)航控制器的子控制器的view有可能被干掉,他如果沒有顯示的話,當(dāng)下次使用這個控制器的時候就會調(diào)用,加載view。

UIViewController管理狀態(tài)欄

    從iOS7開始,系統(tǒng)提供了2種管理狀態(tài)欄的方式
  1. 在iOS7中,默認(rèn)情況下,狀態(tài)欄都是由UIViewController管理的(每一個UIViewController都可以擁有自己不同的狀態(tài)欄),UIViewController實現(xiàn)下列方法就可以輕松管理狀態(tài)欄的可見性和樣式

    // 設(shè)置狀態(tài)欄是否隱藏
    viewController.prefersStatusBarHidden = YES;
    
    // 修狀態(tài)欄樣式
    - (UIStatusBarStyle)preferredStatusBarStyle
    {
        return UIStatusBarStyleLightContent;
    }
    @end
    
  2. 通過UIApplication管理(一個應(yīng)用程序的狀態(tài)欄都由它統(tǒng)一管理)
    1. 需在info.plist中配置


    Snip20151108_152.png
         2. 在Info.plist中做了圖中的配置,可能會出現(xiàn)以下警告信息
    
Snip20151108_153.png
```objc
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];

// 狀態(tài)欄的可見性
// 隱藏狀態(tài)欄
app.statusBarHidden = YES;
// 動畫隱藏狀態(tài)欄
[app setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide]
```

父子控制器

  1. 開發(fā)原則:如果子控件添加到父控件中時,如果子控件是控制器的view,需要將子控件的控制器添加到父控件的控制器。
  • 屏幕控件切換顯示時,某個控件不顯示,一般是將控件從父控件移除,但不會立即移除對應(yīng)的子控制器。
    一來方便下次使用時快速處理時間與顯示視圖;
    二來是子控制器銷毀時,其視圖也會被銷毀,而不會造成內(nèi)存泄露。
  • 開發(fā)中遇到內(nèi)存警告時,沒有顯示的控件,要銷毀其控制器以釋放內(nèi)存。
  • 任何控制器都可以添加子控制器,都可以管理子控制器
  • 父控制器的UINavigationController(導(dǎo)航控制器)UITabBarController(標(biāo)簽控制器),它的子控制器都能拿到,它的底層是:
    1. 判斷下自己是不是導(dǎo)航控制器和標(biāo)簽控制器的子控制器,ChildViewController不是導(dǎo)航控制器和標(biāo)簽控制器子控制器則繼續(xù)判斷
    2. 判斷下父控制器是不是導(dǎo)航控制器和標(biāo)簽控制器的子控制器,是就可以拿到
    3. 繼續(xù)一直判斷,直到?jīng)]有父控制器
  • Modal也是同樣的原理:
    1. 判斷下自己是否被Modal,如果被modal,就把自己dismiss
    2. 如果不是,判斷下自己父控制器是否被modal,如果被modal,就把自己dismiss
    3. 一直判斷,直到?jīng)]有父控制器
// 子控制器(只讀)
@property(nonatomic,readonly) NSArray<__kindof UIViewController *> *childViewControllers NS_AVAILABLE_IOS(5_0);


// 添加子控制器
- (void)addChildViewController:(UIViewController *)childController NS_AVAILABLE_IOS(5_0);

// 移除出父控制器
- (void) removeFromParentViewController

UIViewController常用屬性

// 標(biāo)題
@property(nullable, nonatomic,copy) NSString *title;

// 父控制器
@property(nullable,nonatomic,weak,readonly) UIViewController *parentViewController;

// modal它的控制器
@property(nullable, nonatomic,readonly) UIViewController *presentedViewController  NS_AVAILABLE_IOS(5_0);

// 它modal的控制器
@property(nullable, nonatomic,readonly) UIViewController *presentingViewController NS_AVAILABLE_IOS(5_0);

判斷當(dāng)前ViewController是push還是present的方式顯示的

NSArray *viewcontrollers=self.navigationController.viewControllers;

if (viewcontrollers.count > 1)
{
    if ([viewcontrollers objectAtIndex:viewcontrollers.count - 1] == self)
    {
        //push方式
       [self.navigationController popViewControllerAnimated:YES];
    }
}
else
{
    //present方式
    [self dismissViewControllerAnimated:YES completion:nil];
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,546評論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,570評論 3 418
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,505評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,017評論 1 313
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,786評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,219評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,287評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,438評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,971評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,796評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,995評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,540評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,230評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,918評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,697評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內(nèi)容