読者です 読者をやめる 読者になる 読者になる

@neiraza

2匹の怪獣が寝た後にプログラマーしてる、最近はサイバーエージェントでゼミ長もしてる僕のネタ帳

iPhoneアプリ開発講座を受講する その2

[iPhone][Objective-C]

2日目は「通知」ネタを中心にやった。

1つはObsererで、もう1つはDelegate。
今回はそこの実装の仕方をまとめておく。
事例としてはそこで必要?という感もあるけど、あくまでも実装方法の確認程度ということで。

Observer

監視対象(監視される側) Class A(ScoreManager.m)

addメソッドでscoreが更新されたタイミングで何かしたいなら・・・。

-(void)add
{
    //値が変わる前にメッセージを飛ばす
    [self willChangeValueForKey:@"score"];
    score_ += 10;
    //値が変わった後にメッセージを飛ばす
    [self didChangeValueForKey:@"score"];
}

通知を貰う側 Class B(RootViewController.m)

scoreに変化があったタイミングで、表示を変更する感じ。
Class Aさんに自分自身を渡したるぜ〜。この「@"score"」が合図な。

- (void)viewDidLoad
{
    ......
    [scoreManager_ addObserver:self forKeyPath:@"score" options:0 context:nil];
    ......
}

受け取る人

//Observerでメッセージをうけとる 
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    //文字列の比較はメソッドで
    if ([keyPath isEqualToString:@"score"] == YES){
        NSLog(@"変わった!");
        [scoreLabel_ setText:[NSString stringWithFormat:@"%d", scoreManager_.score]];
    }
}

Delegate

デリゲートを実現するポイントは以下の3つ。

  • プロパティを用意する
  • プロトコルでメソッドを定義する
  • 呼び出し元と呼び出し先の実装

実装してみる。

  • プロパティを用意する
@property(nonatomic,assign) id <ScoreManagerDeleagate> delegate;
  • プロトコルでメソッドを定義する
@protocol ScoreManagerDeleagate <NSObject>
@optional
-(void)scoreManagerDidSubmit:(ScoreManager*)scoreManager;
@end
  • 呼び出し元と呼び出し先の実装

呼び出し元(RootViewController.m)

自身をデリゲートオブジェクトとして登録する

- (void)viewDidLoad
{
    .....
    scoreManager_.delegate = self;
    .....
}

デリゲートメソッドを実装する

-(void)scoreManagerDidSubmit:(ScoreManager *)scoreManager
{
    NSLog(@"submit完了しました");
}

このイベントが開始されると呼び出し先で、上記のメソッドが呼ばれる

-(void)didSubmit
{
    [scoreManager_ submit];
}

呼び出し先(ScoreManager.m)

デリゲートが登録されているか?
デリゲートが叩きたいメソッドを持っているか?
上記を満たしているのあれば、デリゲートメソッドを呼んであげる

-(void)reset
{   
     if(delegate_ != nil){
        if ([delegate_ respondsToSelector:@selector(scoreManagerDelegateReset:)]) {
            //delegateのメソッドを実行
            [delegate_ scoreManagerDelegateReset:self];
        }
    }
}

メモリ解放

Delegate、Observer共にreleaseだけでは足りなく、
登録解除〜って呪文を唱えておかないと、急に呼ばれてアボーンってこともあるので注意

-(void)dealloc
{
    //delegateのrelease時
    scoreManager_.delegate = nil;
    //observerのrelease時はremoveする
    [scoreManager_ removeObserver:self forKeyPath:@"score"];
    [scoreManager_ release];
    [super dealloc];
}

というわけで、通知に関してはこの2点を教えてもらった。