お?いけるくさい?

iPhoneアプリエンジニアのたまごです。いっちょまえエンジニア目指してちいさな発見や学んだことを覚え書きしていきます!Objective-C/iOS/開発

子クラスに作ったUIButtonに親クラスメソッドを実行させたいとき!

TableViewとカスタムセルってやつは。ほんとにもう。

セルの再利用だとかクラス化だとか、わからないことがたくさんあるけど、

最近やっと引数の扱いに慣れてきた!∩(´∀`)∩←

 

色々教えていただいて書きたいことがたくさんあったのに、

なかなか時間がとれず;

 

そんなこんなで今回は

カスタムセルを使ったUITableViewを作り、

そのセル上にあるボタンを押すと

親クラスのUIViewControllerのメソッドが呼ばれる

という実装を覚え書き。

 

まず登場人物は2人。

①TableViewをのっけたUIViewController

②UIButtonをのっけたカスタムセル

 

セルの読み込みは今回は詳しくはハショりますが、

cellForRowAtIndexPathメソッド内に書きます。

 

で!まず基本として、

カスタムせるを作るときはnibファイルを使わないようにする

何度も読むので、nibファイルを使うと重くなります。

コードで書きましょう♪ヽ(´ω)ノ

 

例えばセル上でボタンがこんな感じで作られたとしますね。

        _dlBtn = [UIButtonbuttonWithType:UIButtonTypeCustom];

        _dlBtn.frame = CGRectMake( 185, 53, 130, 20);

        [_dlBtnsetBackgroundColor:[UIColorredColor]];

        [_dlBtnsetTitleColor:[UIColorwhiteColor] forState:UIControlStateNormal]; 

        [_dlBtnsetTitleColor:[UIColorredColor] forState:UIControlStateHighlighted];

        _dlBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;

        _dlBtn.titleLabel.font = [UIFontsystemFontOfSize:15];

        /*[_dlBtn addTarget:self

                   action:@selector(dlBtnPushed:)

         forControlEvents:UIControlEventTouchUpInside];*/

        [self addSubview:_dlBtn]; 

なぜalloc initしてないのかは、私も疑問ですがスルーします。

通常ボタンにメソッドを呼ばせたいときは、

コメントアウトしているところで呼びます。

 

しかーし!

別のクラスのメソッドをボタンで実行したいときは、

ここで呼んでしまうと呼べないのです。

 

そこで!メソッドを実行するためにいくつかステップを踏んで回り道をします。

順序としては

1、ボタンをセットするためのメソッド(A)を子クラスに作成。

  さっきコメントアウトしたやつを移植して、

  親クラスをターゲットに設定できるように引数を持たせます。

  親クラスがこのメソッドを呼べるように、プロパティも設定します。

【子クラス.m】

-(void)btnPushed:(id)mainView{

    

    [_dlBtn addTarget:mainView

               action:@selector(goStore:)

     forControlEvents:UIControlEventTouchUpInside];

}

【子クラス.h】

-(void)btnPushed:(id)mainView;

 

2、親クラスで子クラスのインスタンスを作成後、子クラスのメソッド(A)を呼ぶ。

【親クラス.m】

// セルの内容(必須2)

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString* CellIdentifier = @"MusicCell";

   MusicCell* musicCell = [_musicTableView dequeueReusableCellWithIdentifier:CellIdentifier];

   // if (musicCell == nil) {

        musicCell = [[[MusicCellalloc] initWithStyle:UITableViewCellStyleSubtitlereuseIdentifier:CellIdentifier] autorelease];//毎回つくる

//    } else {

//        [musicCell reloadInputViews];

//    }

    [selfcreateNoSeletionCell:musicCell];

    

〜(中略)〜    

 

    [musicCell btnPushed:self];

    return musicCell;

}

引数には自分selfを設定します。

すると、さっきの1のメソッドのターゲットにselfが渡って自分が実行できるのです。

 

3、呼ばれた子クラスのメソッド(A)が、

  親クラスにあるボタン毎に設定されているメソッド(B)(C)(D)...へとばす。

【子クラス.m】

-(void)btnPushed:(id)mainView{

    

    [_dlBtn addTarget:mainView

               action:@selector(goStore:)

     forControlEvents:UIControlEventTouchUpInside];

 

}

さあ、ここで_dlBtnの飛ばし先@selectorは、goStoreというメソッド!

goStoreは親クラスに書いてあります。

Targetが親クラスになっているので

こちらはプロパティに宣言しなくても実行されます。

 

4、親クラスにあるメソッド(B)が実行される!

【親クラス.m】

-(void)goStore:(id)sender{

    NSLog(@"AppStore");

}

まだgoStoreの中身が無いですが、

とりあえずこんな感じ。

ちなみに3、の行程で(goStore:)と書きましたが、

この:の後ろには何も書かないと、自身(つまり_dlBtn)が設定されます。

よくNSTimerとかでもあるよね。この書き方。

さらにさらに、ボタンのメソッドに関しては、

クラスをまたがずに実行されるときでも、

これ(sender)より多くの引数を持たせることができません。※注意!

だから例えば他にも引き渡したい数があるときは、

別のメソッドを使って実行されるように頭を使う必要があります。

 

*おまけ*

この(id)senderの部分をUIButton*に特定してしまうと、

ボタンのtagプロパティが使えるようになります!

タグで見分けたいときとかは、これを使うとすごく便利になります。

実装方法は2つあるのですが、

①そのまま引数をUIButtonにしちゃう

-(void)goStore:(UIButton*)sender{

    sender.tag = ■

    NSLog(@"AppStore");

}

②id型で受け取ったあとに、UIButton型でキャストしてボタンをつくる

-(void)goStore:(id)sender{

    UIButton* btn = (UIButton*)sender;

    btn.tag = ■

    NSLog(@"AppStore");

}

これでタグがとれます!

引数わかったらちょっと楽しくなってきた。