Help us understand the problem. What is going on with this article?

Blocksとdelegateの基本

More than 5 years have passed since last update.

@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日目でした。ありがとうございます。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした