ストップウォッチを作ろう(4) - Cocoaプログラミング

ストップウォッチクラスをそのまま使い回して、iPhoneアプリケーションに仕上げます。

てくっち

前回作ったMac OS Xアプリで、Stopwatchクラスを使っていましたが、

てくっち

これをそのまま再利用して、iPhoneアプリを作ってみましょう。

てくっち

Xcodeを起動し、⌘-shift-N(新規プロジェクト...)から、iPhone OSのView-Based Applicationを選んでください。

てくっち

てくっち

プロジェクト名は、LogWatch-iPhoneにしましょう。

てくっち

てくっち

Finder上で、前回作ったプロジェクトのフォルダ(LogWatch)の中の2つのファイル、Stopwatch.hとStopwatch.mを、

てくっち

てくっち

このように、Xcode上のClassesフォルダへドラッグ&ドロップしてください。すると、

てくっち

てくっち

こんなシートが出るのでターゲット(LogWatch-iPhone)を確認して、追加。

てくっち

てくっち

Finderで確認すると、このように

てくっち

てくっち

2つのファイルがコピーされました。

てくっち

そしてオブジェクトの関係図を書いてみます。

てくっち

てくっち

黒で書いたところはこのプロジェクト(View-Based Application)が最初に用意してくれた部分で、

てくっち

赤で書いたところが、今回自前で設置する部分です。

てくっち

NIBファイル(拡張子が.xib)は2つ用意されてあって、そのうちLogWatch_iPhoneViewController.xibのほうを編集します。

てくっち

そのファイルをダブルクリックしてインターフェースビルダーを起動させ、

てくっち

テキストビュー(UITextView)、ラベル(UILabel)、ボタン2つ(UIButton)、それからUIActivityIndicatorViewを次のように配置しましょう。

てくっち

てくっち

GUIが見えてくると俄然もりあがってきますねー。

てくっち

てくっち

Activity Indicator View (UIActivityIndicatorView)の設定で、Hide When Stoppedをオンにします。

てくっち

さてXcodeにもどって、ビューコントローラーのヘッダファイル(LogWatch_iPhoneViewController.h)を、次のようにします。

てくっち

#import <UIKit/UIKit.h>
@class Stopwatch;

@interface LogWatch_iPhoneViewController : UIViewController {
  IBOutlet UILabel *timeDisplay;
  IBOutlet UIButton *startStopButton, *resetButton;
  IBOutlet UIActivityIndicatorView *busyIndicator;
  IBOutlet UITextView *logView;
  Stopwatch *watch;
  NSTimer *timer;
  NSMutableArray *log;
}
- (IBAction)pushStartStop:(id)sender;
- (IBAction)pushReset:(id)sender;
- (void)updateUI:(NSTimer *)t;
@end

てくっち

さっき示したオブジェクトの関係図のどこに対応するか、確認してみてください。

てくっち

そしてビューコントローラーの実装ファイル(LogWatch_iPhoneViewController.m)を以下のように。

てくっち

#import "LogWatch_iPhoneViewController.h"
#import "Stopwatch.h"

@implementation LogWatch_iPhoneViewController

- (void)updateUI:(NSTimer *)t
{
  NSTimeInterval second = watch.second;
  NSString *s = [[NSString alloc] initWithFormat:@"%.2f", second];
  timeDisplay.text = s;
  [s release];
}

- (IBAction)pushStartStop:(id)sender
{
  [watch startStop];  
  if (watch.isBusy) {
    // START
    timer = [NSTimer scheduledTimerWithTimeInterval:0.01 
                         target:self 
                         selector:@selector(updateUI:) 
                         userInfo:nil 
                        repeats:YES];
    [timer retain];
    [startStopButton setTitle:@"STOP" forState:UIControlStateNormal];
    
    resetButton.userInteractionEnabled = NO;
    resetButton.alpha = 0.5;
    
    [busyIndicator startAnimating];
  }
  else {
    // STOP
    [timer invalidate];
    [timer release];
    [startStopButton setTitle:@"START" forState:UIControlStateNormal];
    
    resetButton.userInteractionEnabled = YES;
    resetButton.alpha = 1.0;
    
    [busyIndicator stopAnimating];
    
    // Log
    [log addObject:timeDisplay.text];
    NSString *s = [log componentsJoinedByString:@"\n"];
    logView.text = s;
    NSRange logEnd;
    logEnd.location = [s length] - 1;
    [logView scrollRangeToVisible:logEnd];
  }
}

- (IBAction)pushReset:(id)sender
{
  if (watch.isBusy)
    return;
  
  [watch reset];
  [self updateUI:nil];
}

- (void)viewDidLoad {
    [super viewDidLoad];
  watch = [[Stopwatch alloc] init];
  log = [[NSMutableArray alloc] init];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning]; 
}

- (void)dealloc {
  [watch release];
  [log release];
    [super dealloc];
}
@end

てくっち

前回作ったAppControllerと似たところが多いです。

てくっち

最後にインターフェースビルダーでビューコントローラーと各オブジェクトを接続します。

てくっち

今編集中のnibファイルのFile's Ownerは

てくっち

ビューコントローラーがおさまっています。

てくっち

ビューコントローラーのアウトレットとアクションを、接続していってください。

てくっち

てくっち

全部つなぐと、このようになります。

てくっち

説明なしでやっちゃってる部分がたくさんあるのですが・・・

てくっち

とても解説しきれません・・・申し訳ない・・・

てくっち

今回の目玉は、Mac OS Xアプリ上で設計したオリジナルのクラスを、

てくっち

まったく変更することなしに、iPhoneアプリで使い回す例でございました。

てくっち

将来、アプリケーション開発で時間を計測する必要が生じたときに、

てくっち

Stopwatchクラスをさくっと利用すれば、ぐっと効率があがってハッピーになるかもしれません。

てくっち