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

iOS7でUITableViewCell上のボタンをタップしたら落ちた

More than 5 years have passed since last update.

こんなエラーが起きた

大分略していますがこんな感じのコードを書いて、UITableViewCell上のボタンをタップした時の処理を実行してたのですが、

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
  //~ 略 ~
  cell = [[RensouCell alloc]
             initWithStyle:UITableViewCellStyleDefault
           reuseIdentifier:CellIdentifier];

  // ボタンタップ時のイベント感知
  [cell.likeButton addTarget:self
                      action:@selector(onClickLikeButton:)
            forControlEvents:UIControlEventTouchUpInside];
  //~ 略 ~
}

// ボタンタップ時に実行される処理
- (void)onClickLikeButton:(UIButton *)button
{
  // タップされたボタンから、対応するセルを取得する
  RensouCell *cell = (RensouCell *)[button superview];
  //~ 略 ~
  [cell likeRensou];
}

iOS7で実行してみたら、こんなエラーを出して落ちてしまいました。(iOS6以前だと普通に動く)

[UITableViewCellScrollView likeRensou]: unrecognized selector sent to instance 0x9b453e0

「UITableViewCellScrollView に、likeRensou なんてメソッド無いよ!」というエラーなのですが、そもそもUITableViewCellScrolView ってどこから出てきたんだよ…、という感じでした。(;´Д`)

原因

ぐぐったら以下の記事で解説されていました。
参考:iOS7 では UITableViewCell の subviews階層が変更されている | objc-Lovers

なるほど階層が変わったんですね。確かにこれだと、タップされたUIButtonのsuperviewを取得すると、UITableViewCellScrollViewになりますわ…。

追記

twitterで指摘されて気づいたのですが、UITableViewCellにUIButtonを配置する際は、selfにaddSubviewするんじゃなくて、self.contentViewに対してaddSubviewするのが正しいようです…orz
参考:ynumerator_blog: Custome UITableViewCellの[self addSubview]と[self.contentView addView]の違い

正しいやり方でやっていると、UIButtonのsuperviewはUITableViewCellContentになります。この辺のviewの構造については、以下の図が分かりやすいです。
参考:iOS6とiOS7のUITableViewCell構造の違い

解決策

調べていくうちに、今までやっていたsuperviewを使って対応するUITableViewCellを取得するやり方は、元々推奨されていないという事が分かったので、ガラッと方法を変えてUIEventを使うようにしました。これでばっちり!!

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
  //~ 略 ~
  cell = [[RensouCell alloc]
             initWithStyle:UITableViewCellStyleDefault
           reuseIdentifier:CellIdentifier];

  // ボタンタップ時のイベント感知
  [cell.likeButton addTarget:self
                      action:@selector(onClickLikeButton:event:)
            forControlEvents:UIControlEventTouchUpInside];
  //~ 略 ~
}

// ボタンタップ時に実行される処理
- (void)onClickLikeButton:(UIButton *)button event:(UIEvent *)event
{
  // タップされたボタンから、対応するセルを取得する
  NSIndexPath *indexPath = [self indexPathForControlEvent:event];
  RensouCell *cell = (RensouCell *)[self.tableView cellForRowAtIndexPath:indexPath];
  //~ 略 ~
  [cell likeRensou];
}

// UIControlEventからタッチ位置のindexPathを取得する
- (NSIndexPath *)indexPathForControlEvent:(UIEvent *)event {
    UITouch *touch = [[event allTouches] anyObject];
    CGPoint p = [touch locationInView:self.tableView];
    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:p];
    return indexPath;
}

参考:Objective-C:UITableViewCell上に配置したButtonのタップを感知する方法 - Qiita [キータ]

解決策その2

上で挙げたような修正が大変な場合は、オススメは出来ませんが、以下のような修正方法もあるらしいです。一応紹介。

参考:既存アプリのiOS 7対応 | iOS 7エンジニア勉強会

というわけで

無事修正したものを再申請できました!!早く審査通らないかな(´ω`)

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
ユーザーは見つかりませんでした