タグ別アーカイブ: no-StoryBoard

【UINavigationController】ボタンを押すことで画面遷移する構造の基本構成

画面遷移する際の概念がやっと理解できたので、構成を残しておく。
サンプルは以下の通り。

処理順のイメージ

  1. AppDelegateがWindowを生成
  2. AppDelegateがTopViewControllerを生成してWindowに表示
  3. TopViewControllerがViewに載ったらイベント付きのボタンを2つ生成
  4. ボタンが押されたらViewController1を生成してWindowのViewに掲示。
  5. ViewController1がViewに載ったらイベント付きのボタンを1つ生成
  6. ボタンが押されたらTopViewControllerを生成してViewに乗せる。

気をつけなければ成らないのは以下の点

  • このサンプルではUINavigationControllerを利用しているので、遷移経路が全て保持されており、経路上の画面自体も保持され続ける。
  • よって、メモリオーバー必至。
  • メモリオーバー時用の対処はUIKit詳細リファレンスに載ってるのでそれを参照。

サンプル

AppDelegate.h

#import 

@interface AppDelegate:NSObject {
  UIWindow* window_;
  UIViewController* rootController_;
}

@property (strong, nonatomic) UIWindow *window;

@end

AppDelegate.m

#import "AppDelegate.h"
#import "TopViewController.h"

@implementation AppDelegate
@synthesize window = _window;

- (void)applicationDidFinishLaunching:(UIApplication *)application{
  // window を自分で作成
  CGRect bounds = [[UIScreenmainScreen]bounds];
  window_ = [[UIWindowalloc] initWithFrame:bounds];
  TopViewController* top = [[[TopViewController alloc]init]autorelease];
  rootController_ = [[UINavigationController alloc] initWithRootViewController:top];
  [window_addSubview:rootController_.view];
  [window_makeKeyAndVisible];
}

- (void)dealloc{
  [rootController_release];
  [window_release];
  [superdealloc];
}

@end

TopViewController.h

#import 
@interface TopViewController : UIViewController
@end

TopViewController.m

#import "TopViewController.h"

@implementation TopViewController

- (UIButton*)makeButton:(CGRect)rect text:(NSString*)text tag:(NSInteger)tag{
  UIButton* button = [UIButtonbuttonWithType:UIButtonTypeRoundedRect];
  [button setFrame:rect];
  [button setTag:tag];
  [button setTitle:text forState:UIControlStateNormal];
  [button addTarget:selfaction:@selector(clickButton:) forControlEvents:UIControlEventTouchUpInside];
  return button;
}

- (void)viewDidLoad{
  NSLog(@"top view did load");
  [superinit];
  UIButton* milkButton = [self makeButton:CGRectMake(10, 20, 300, 100) text:@"milk"tag:0];
  [self.viewaddSubview:milkButton];
  UIButton* soltButton = [self makeButton:CGRectMake(10, 120, 300, 100) text:@"solt"tag:1];
  [self.viewaddSubview:soltButton];
  NSLog(@"top view did load end");
}

- (IBAction)clickButton:(UIButton*)sender{
  NSLog(@"click Milk: tag is : %d",sender.tag);
  /*
   画面遷移の処理を行う。
   1:viewControllerを生成する。
   2:その画面に遷移。
   */
  //UIViewControllerを生成
  Class class = NSClassFromString(@"ViewController1");
  id viewController = [[[class alloc] init ]autorelease];
  [self.navigationController pushViewController:viewController animated:YES];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
@end

ViewController1.h

#import 
@interface ViewController1 : UIViewController
@end

ViewController1.m

#import "ViewController1.h"

@implementation ViewController1

- (void)viewDidLoad{
  [super viewDidLoad];

  //Hello,world!ラベルを追加
  //背景は白、文字は黒で。
  UILabel* label = [[[UILabel alloc] initWithFrame:self.view.bounds] autorelease];
  label.text = @"Hello, world";
  label.textAlignment = UITextAlignmentCenter;
  label.backgroundColor = [UIColor whiteColor];
  label.textColor = [UIColor blackColor];
  label.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  [self.view addSubview:label];

  //これをタップしたら画面遷移する
  UIButton* button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
  [button setTitle:@"画面遷移" forState:UIControlStateNormal];
  [button sizeToFit];
  CGPoint newPoint = self.view.center;
  newPoint.y += 50;
  button.center = newPoint;
  button.autoresizingMask =
    UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
  [button addTarget:self
             action:@selector(buttonDidPush:)
   forControlEvents:UIControlEventTouchUpInside];
  [self.viewaddSubview:button];
}

-(id)init{
  if((self = [superinit])){
    self.title=@"Hello";
  }

  returnself;
}


- (void)buttonDidPush:(UIButton*)sender{
  NSLog(@"Pushed!!");
  id TopViewController = [[[TopViewController alloc] init ]autorelease];
  [self.navigationController pushViewController:TopViewController animated:YES];
}

@end

おまけ

ちなみにViewController1のbuttonDidPush:senderメソッドを以下の様に書き換えると、トップに戻る様になるので遷移経路を保持せずにメモリを節約できる。

- (void)buttonDidPush:(UIButton*)sender{
  NSLog(@"Pushed!! tag:%d",sender.tag);
  [self.navigationController popToRootViewControllerAnimated:YES];
//  id viewController = [[[TopViewController alloc] init ]autorelease];
//  [self.navigationController pushViewController:viewController animated:YES];
}

iOSプログラミング逆引きリファレンス108 ~知りたいことがすぐわかるiPhoneプログラミングテクニック~

iPhoneプログラミングUIKit詳解リファレンス

iOSデバッグ&最適化技法 for iPad/iPhone
詳解 Objective-C 2.0 第3版