2014年11月26日 星期三

關於ViewController以及autolayout你應該要知道的事

一、生命週期的呼叫順序:

  1. initWithNibName
  2. loadView
  3. viewDidLoad
  4. viewWillAppear
  5. viewWillLayoutSubviews
  6. viewDidLayoutSubviews
  7. viewDidAppear
  8. viewWillDisappear
  9. viewDidDisappear
  10. dealloc
initWithNibName 
若以xib呼叫時,會執行這裡,不需要在這覆寫什麼東西。

loadView 
這裡要非常注意,因為在xcode會自動生成一些code在這裡,目的是連結Interface Builder與你的ViewController Class。
所以一般使用xib或storyboard是不需要去override這個methed,如果真的想不開,請記得先執行[super loadView],不然你肯定找不到你辛苦拉好的view。
如果你沒用xib,就是要在這裡建立你要的self.view。

viewDidLoad
當View被load好之後,會執行這裡,且在生命週期中只會執行一次,所以一些初始值的設定盡量放在這。

viewWillAppear
view被load好之後,就要將它顯示出來,在顯示之前會執行這裡。
這裡在每次顯示前都會被執行,所以可以在此設定一些隨著每次畫面出現,都要變動的值。

viewWillLayoutSubviews
viewDidLayoutSubviews
在viewWillAppear時,還沒有做些auto layout的調整,將會在這裡才實作,
意思是如果你想要抓取UI在auto layout之後的frame,從這裡被執行之後才能抓到。
值得注意的是,這兩個function是只要有畫面的變動時,就會被觸發,被觸發的頻率比viewWillAppear/viewDidAppear來的高很多。

其他的就差不多是類似的意思,例如viewWillDisappear,就是在畫面將消失前會觸發。

二、接下來要介紹的是接到memoryWarming的回收方式:

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];

     if ([self.view window] == nil)
    {
        // 如果view的window為nil,代表self.view已經不在顯示。
        
        //TODO:一、加入code讓你要保留的值存到安全的地方
        //TODO:二、把你設為strong的值,指定為nil

        // 最後讓你的self.view = nil;
        self.view = nil;
    }
}



三、改變self.view大小的流程(auto layout的執行過程)

當view controller的size改變時,他的subview們也會重新調整自己的位置。他們通常使用layout constraints和autoresizing masks,這時view controller會發生下列的步驟:

  1. self.view改變size.
  2. 如果沒使用autolayout,才會以autoresizing masks來調整大小
  3. view controller的 viewWillLayoutSubviews 方法將會被呼叫。
  4. self.view的 layoutSubviews 方法會被呼叫,如果使用auto layout他會執行下列步驟:
    1. view controller 的 updateViewConstraints 方法會被呼叫。
    2. updateViewConstraints會去呼叫各個view的 updateConstraints 方法。
    3. 計算新的layout,並重置views到新的位置。
  5. view controller的 viewDidLayoutSubviews 方法被呼叫。

四、autolayout的最佳執行方式建議

    如果你是開發於iOS 6 and later
    先使用layout constraints來自動設定你的view的位置(iOS 6 and later)
    你可以去覆寫updateViewConstraints方法 來加入一些需求額外客製化的layout constraints,但記得一定要在方法中先加入[super updateViewConstraints];來實作自動產生的UI constrains.

    如果你是用iOS 5.x
    使用autoresizing masks,你要覆寫layoutSubviews來設定一些無法用resizing masks自動達成的位置。

    2014年11月25日 星期二

    iOS 6以後,要如何呼叫客製化的tableView Cell

    分為Cell是「自定義出來的」或是「已經放在storyboard上的」兩種:

    一,自定義出來的:

    先來viewDidLoad中加入這行註冊你要call的cell,
    [self.tableView registerClass:[CustomCell class] forCellReuseIdentifier:@"CustomCell"];
    //如果要用xib,那就使用iOS5之後就有的method
    //- (void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(5_0);

    註冊之後,你就可以在cellForRowAtIndexPath:中直接呼叫UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CustomCell" forIndexPath:indexPath];

    //而不需要如下的傳統寫法
    static NSString *CellIdentifier = @"CustomCell";
    if (cell == nil) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];

    二,從storyboard上抓
    先把你客製化的cell放到你storyboard上的tableView中,然後設定identifier為@"CustomCell"

    接下來,直接在cellForRowAtIndexPath:中呼叫cell即可
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CustomCell" forIndexPath:indexPath];
        
    注意:如果你用storyboard的方式,那不可以呼叫registerClass:[CustomCell class] 方法,否則它會建立一組新的cell,而不會直接取用storyboard上畫好的!!!

    2014年11月21日 星期五

    auto layout的觸發時機

    viewDidLoad      
            \/
    viewWillAppear
            \/
    auto layout
            \/
    viewDidAppear

    2014年11月14日 星期五

    tableView的cell的width會給定一個default值,reuse的時候才會以tableView為主

    //如下NSLog所示,一開始進入cell == nil判斷時,cell的width都會是320,當你下拉tableView再拉回時,reuse的cell才會跟tableView的width一樣大。
    //由此可知,一開始new的cell因為不知道你的tableView的frame,所以會先給定一個default值!你要自行去修改。

     static NSString *CellIdentifier = @"Cell";
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
         
    NSLog(@"%@ cellForRowAtIndexPath cell.frame.size.width 1 =%f", [self class], cell.frame.size.width);

        if (cell == nil) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
            NSLog(@"%@ cellForRowAtIndexPath cell.frame.size.width 2 =%f", [self class], cell.frame.size.width);
            [cell setFrame:CGRectMake(0.f, 0.f, tableView.frame.size.width, tableView.frame.size.height)];
        }
        NSLog(@"%@ cellForRowAtIndexPath cell.frame.size.width 3 =%f", [self class], cell.frame.size.width);

    2014年11月10日 星期一

    抓一個月有幾天

    - (NSInteger)numberOfDaysInMonth:(NSDate *)today
    {
        NSRange range = [[NSCalendar currentCalendar] rangeOfUnit:NSDayCalendarUnit inUnit:NSMonthCalendarUnit forDate:today];
        return range.length;
    }

    }

    2014年11月5日 星期三

    如何用程式切換tabbar到你要的navigationController然後push到你要的頁面

    UITabBarController *tabbarController = self.tabBarController;
        dispatch_async(dispatch_get_main_queue(), ^{
            
            //選取tabbar第三個controller:Family
            [tabbarController setSelectedIndex:2];
            
            UINavigationController *navController = (UINavigationController *)tabbarController.selectedViewController;
            
            //如果已經被push到下一頁的,都拉回到
            [navController popToRootViewControllerAnimated:NO];
            
            for (UIViewController *subViewController in navController.viewControllers) {
                
                if( [subViewController isKindOfClass:[SFFamilyViewController class]] )
                {
                    SFFamilyViewController *familyVC = (SFFamilyViewController *)subViewController;

                    [familyVC performSegueWithIdentifier:@"familyeditpet" sender:nil];
                    
                }
            }

        });

    2014年11月4日 星期二

    改掉Navigation Controller的back button事件

    //在viewDidLoad中加入這兩行,override返回鍵的方法
    self.navigationItem.backBarButtonItem.target = self;
    self.navigationItem.backBarButtonItem.action = @selector(backButtonDidPressed:);
    
    //宣告這個方法來執行你要在back前做的事
    - (void)backButtonDidPressed:(id)aResponder {
        //do your stuff
        //but don't forget to dismiss the viewcontroller
        [self.navigationController popViewControllerAnimated:YES];
    }