LoginSignup
95

More than 5 years have passed since last update.

Blocksとdelegateの基本

Last updated at Posted at 2012-12-23

@adachi_cです。

今日はBlocksとdelegateのわりと基本的な話をしようと思います。まず、言いたいこと。

  • delegateで書いていたところをBlocksで書くことで、だいたいコードの量が減るのでできるだけdelegateやめましょう。
  • @propertyも減らしましょう。後任の人ができたときに見づらくてもうかなわないのでこれは私からお願いです。あと、dispatch_async+@propertyでカジュアルな書き換え/参照の合わせ技もやめて欲しい感じですね。
  • モデルでシングルトンで書けるところはもうシングルトンでお願いします。UIの更新もBlocksでいいのでは。

とりあえず、このへんのことをスッキリやれるのがBlocksとGCDなんで、その辺のことに2日アドベントカレンダーをいただいて、皆さんに説明できたらいいなと。

たとえば、キーパッドのビューコントローラがあって、AボタンとBボタンがある。で、それを押したら他のビューに通知して、他のビューのUI更新したい。

従来の場合だと、キーパッド側でこのようにプロトコルを書いて

KeypadViewController.h
@protocol KeypadViewDelegate
-(void)aPushedUpdate:(id)sender;
-(void)bPushedUpdate:(id)sender;
@end

@interface KeypadtViewController : UIViewController {
    id  delegate_;
}
@property IBOutlet UIButton *aButton;

-(IBAction)aPushedUpdate:(id)sender;
-(IBAction)bPushedUpdate:(id)sender;

@end

以下のように、他のビューに通知すればいいですね。

KeypadViewController.m

-(IBAction)aPushedUpdate:(id)sender
{
    [delegate aPushedUpdate:sender];
}

で、通知受ける側はdelegate実装する。

GameViewController.h
@interface GameViewController: UIViewController<KeypadViewDelegate>{
    KeypadViewController *keypadViewController;
}
@property IBOutlet UIVIew *view;
-(void)aPushedUpdate:(id)sender;
@end
GameViewController.m

#pragma mark KeyPadViewDelegate
-(void)aPushedUpdate:(id)sender
{
    /*UIの更新処理を書く*/
    [self.view update];
}

まず、これをBlocksでやればdelegate書かなくていいと。
@property定義しないかわりに、Block型変数を定義します。これはcopyだとiOS4.3のバグで落ちますので、assignにしておきます。

KeypadViewController.h

typedef void(^__view_update)();
@interface KeypadtViewController : UIViewController

@property IBOutlet UIButton *aButton;
@property (assign) __view_update *onAPushed;

-(IBAction)aPushedUpdate:(id)sender;
-(IBAction)bPushedUpdate:(id)sender;

@end

KeypadViewController.m
-(IBAction)aPushedUpdate:(id)sender
{
    if(self.onAPushed){
        self.onAPushed();
    }
}

こんな感じで短いです。

で、UI更新したいビューのほうは以下のように、デリゲート実装する必要ない。

GameViewController.h
@interface GameViewController: UIViewController{
    KeypadViewController *keypadViewController;
}
@property IBOutlet UIVIew *view;
@end

init時に更新処理をコピーする。

GameViewController.m
-(id)init{
    self.keypadViewController = [^{
        dispatch_sync(dispatch_get_main_queue(), ^{
            /*UIの更新処理を書く*/
            [self.view update];
        });
    } copy];
}

こんな感じでかなり短いし簡単で見やすいので、デリゲートやめようという話と、あと、これがKeypadViewControllerみたいなViewControllerじゃなくて、モデルの場合、シングルトンにしてしまって、そいつにcopyして、トランザクションするようにすると、解放処理考える必要もないし、アプリが落ちる心配も減ります。それは25日のやつで説明します。

以上、23日目でした。ありがとうございます。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
95