みんなの「教えて(疑問・質問)」にみんなで「答える」Q&Aコミュニティ

こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

ボタンのtagの番号を値渡しする方法について

今、xcodeでiphoneやipad用のアプリを作っています。
VIewController(VC)に30個くらいのボタンを置き、そのボタンのタグ番号に合わせて、SecondVIewContorller(SVC)で、画像がでてきて、それをタップしたら、次の画像へ移動するというようにしたいのですが、VCのボタンのタグ番号をSVCに送ろうとするところでひっかかっています。もし何かご助言が頂けたら誠に幸いです。よろしくお願いします。
以下、自分なりにつくったコードです。

<VCの実装>
- (IBAction)pushBtn:(UIButton *)sender {
[self performSegueWithIdentifier:@"mySegue" sender:self];}

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{

if([segue.identifier isEqualToString:@"mySegue"]){
secondViewController*viewcon=segue.destinationViewController;
viewcon.Number=[NSString stringWithFormat:@"%d",[sender tag]];
}

これをSVCに送ってタグ番号をつけたいのですが、
以下の上から五行目のところの書き方のところでエラーがでてますが、他の書き方が
わかりません。
<SVCの実装>
- (void)viewDidLoad
{
[super viewDidLoad];

UIImage*imageDate=[UIImage imageNamed:@"%d,png",_Number];

CGRect rect=CGRectMake(0,0 ,200,200);
UIImageView*imageView=[[UIImageView alloc]initWithFrame:rect];

imageView.image=imageDate;
imageView.contentMode=UIViewContentModeScaleAspectFit;
imageView.center=self.view.center;

[self.view addSubview:imageView];}

xcodeのバージョンは、5,0です。

重ね重ねよろしくお願いします。

投稿日時 - 2013-11-17 19:17:47

QNo.8351255

困ってます

質問者が選んだベストアンサー

No.1,4です。

> 最後の[sender tag]を書くと、シュミレーターは成功とでるのですが、すぐにエラーがでます。

コンソールメッセージを見せてもらってすぐわかりました。

「[ViewController tag]: unrecognized selector」
というメッセージは、
「ViewControllerのtagメソッドは認識できないセレクタです」
と言っています。

tagメソッドは、UIViewクラスのメソッドです。
UIView派生クラスではなく、誤ってUIViewController派生クラスの
ViewController(VC)クラスオブジェクトを使ったから
このようなエラーが出たのだと考えられます。
そこで、なぜ誤ってViewControllerが使われたのかを
調べます。

まず、このtagメソッドの直接の呼び出し箇所を見ると、
senderオブジェクトがtagを呼び出しています。このsenderは、
prepareForSegueのパラメータで引き継がれたもので、
もともとperformSegueWithIdentifierのsenderパラメータに
指定したものが引き継がれます。

そのperformSegueWithIdentifierのコードを見ると
[self performSegueWithIdentifier:@"mySegue" sender:self];
となっていて、senderにはselfが指定されています。

このselfは、自分自身(VCクラス)ですので、冒頭のエラーメッセージ通り、
VCクラスにtagメソッドはないというエラーになります。

ここは、タグ番号を付けたUIButtonオブジェクトを指定する必要があります。
つまり、
[self performSegueWithIdentifier:@"mySegue" sender:self];
ではなく、

[self performSegueWithIdentifier:@"mySegue" sender:sender];
とする必要があります。



それと、申し訳ありませんが、No.1の回答で訂正があります。
NSStringの文字列をstringWithFormatの書式に埋め込む場合
「%s」を指定すると書いてしまいましたが、正しくは「%@」です。
_NumberがNSStringクラスのオブジェクトなら
[NSString stringWithFormat:@"%s.png",_Number];
ではなく、
[NSString stringWithFormat:@"%@.png",_Number];
が正しいです。
ただ、もともとNo.1でアドバイスした通り、このコーディングではなく
VC側で
[NSString stringWithFormat:@"%d.png",[sender tag]];
とするのがわかりやすいと思います。

投稿日時 - 2013-11-28 22:55:28

お礼

何度もご丁寧にお答え下さいまして本当に!本当に!ありがとうございました。
おかげさまで出来るようになりました。
教えて頂いたsender:senderが鍵でした!
大変な時間をかけただけに、本当、一言では申し尽くせないほど、感謝しております。
重ね重ね御礼を申し上げます。
ありがとうございます!

投稿日時 - 2013-11-29 05:15:26

このQ&Aは役に立ちましたか?

1人が「このQ&Aが役に立った」と投票しています

回答(7)

前のでも、よくないところがあったので、再び。これが、最後です。

 ポイント
UIKitの部品には、tagというpropertyがあるのですが、これは、いつのXcodeのバージョンからか、デフォルトでは、IB画面で、みえなくなっています。すくなくとも、 Xcode5やXcode4.6では、みえない。

 で、どうするかというと、その部品を選択した状態で、Attribute Inspectorで、下のほうにある、View のところへキャレットをもっていくと、右にShowというのが、出てくるので、ここで、Showをおすと、tagの設定ができるようになります。

 すなわち、Buttonを30個配置する。それぞれのtagを、1-30 で、せっとする。

 30個のButtonで、同じ、IBAction doButtonActionへ、いくようにする
doButtonActionで、

[self peformSegueWithIdentifier:@"toSecondView" sender:self]

とする。

prepareSegueFor... をViewController内にかいて、そこで、
 segue のdestinationViewController.whoCalledMe = sender.tag

で、tagをわたす。

 それで、いけるはずです。User Defined Run Time attributeをつかわなくてもいけます。

投稿日時 - 2013-11-27 20:40:02

お礼

何度もお時間かけてご指導して頂きまして、誠に感謝致します。ありがとうございます。
自分なりに色々やっているのですが、結局、最後の[sender tag]を書くと、シュミレーターは成功とでるのですが、すぐにエラーがでます。エラー内容をみるとtag番号について認識できないのではと解釈しています。NSLogを使い色々試したのですが、-(IBAaction)の中ではタグの認識はでるのですが、-(void)prepareForSegue)のところにtag番号をのせると、認識しません。もし、何かご指導頂けることがありましたら、お手数かけますが是非ともよろしくお願いします。

以下、エラーの内容です。

2013-11-28 19:05:11.638 test91.11[1992:a0b] -[ViewController tag]: unrecognized selector sent to instance 0xa129fa0
2013-11-28 19:05:11.641 test91.11[1992:a0b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ViewController tag]: unrecognized selector sent to instance 0xa129fa0'
*** First throw call stack:

投稿日時 - 2013-11-28 19:42:03

#2,#3ですが。
まだ、あやまちがあったので、修正

Buttonから、segueで、Second View Controllerに飛ぶ方式は、Buttonを複数選択で、ひとつのsegueを出す方法は出来ないようです。

Buttonを複数選択して、ViewController.hに、IBActionを生成する方法はできます。

したがって、かいつまんでいうと、

a ViewController -> SecondViewCOntroller で、segueをつくる。
b ViewController.h に、IBAction で、doButton を生成
c doButtonのなかで、[self performSegueWithIdentifier ...]
d ViewController.m に、
  prepareForSegue を、ていぎして、その中で、値をSecondViewControllerにわたす。


これで、いけます

投稿日時 - 2013-11-21 17:54:56

ANo.4

No.1です。

> 最後の行のviewCon._imageFileName=[NSString stringWithFormat:@"%d.png",[sender tag]];
> がどうもうまくいっていないよう(動かすと成功になり、ボタンを押すとエラーがでるのですが、コードを書いている時点では何もでない状態)で、色々やっているのですが何が欠けているのかわかない状態です。もし宜しければ、ご助言を頂けたら幸いです。


「ボタンを押すとエラーがでる」というのが、
どこにどんなエラーメッセージが出ているのか
もう少し詳しく説明すると、助言できると思いますよ。

それと、気になるのは
viewCon._imageFileName=[NSString stringWithFormat:@"%d.png",[sender tag]];

「viewCon._imageFileName」ですが、これ正しいですか?

普通、SVCのヘッダに
@property (strong, nonatomic) NSString *imageFileName;
と書いたら、
VC側からアクセスするときは「viewCon.imageFileName」でアクセスし、
SVC側からアクセスするときは、「self.imageFileName」か、
または暗黙的に宣言されている「_imageFileName」でアクセスする
形になるはずですけど。

投稿日時 - 2013-11-21 14:11:44

お礼

お礼の連絡が遅くなりまして申し訳ありません。ずっと試行錯誤でトライしていました。
propertyのimageFIleNameのご指摘ありがとうございました。その点は改善できるようになりました。

tagのところでまだつまづいていまして、結局、最後の[sender tag]を書くと、シュミレーターは成功とでるのですが、すぐにエラーがでます。エラー内容をみるとtag番号について認識できないのではと分析しています。NSLogを使い色々試したのですが、-(IBAaction)の中ではタグの認識はできてるのですが、-(void)prepareForSegue)のところで[sender tag]をいれると認識しません。
基本的な何かが欠けているのかもわかりませんが、もし、ご教授頂けることがありましたら、大変お手数をかけて申し訳ありませんが、よろしくお願い致します。

以下がエラー内容です。

return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));

とでてきて、コンソールのところには、

2013-11-28 19:05:11.638 test91.11[1992:a0b] -[ViewController tag]: unrecognized selector sent to instance 0xa129fa0
2013-11-28 19:05:11.641 test91.11[1992:a0b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ViewController tag]: unrecognized selector sent to instance 0xa129fa0'
*** First throw call stack:
と出てきます。

投稿日時 - 2013-11-28 19:40:48

ということで、自分でもやってみましたが。

いくつか、間違っていることがありました。まず、segueを作るのは、最後です。segueを作ってから、Buttonを修正すると、buttonとsegueのコネクションが外れてしまいます。

 次に、User Defined Run Time Attribute で、アクセス出来るのは、バニラのUIButtonでは、決まったものしかできないようです。そこで、こうします

1 ViewControllerにbuttonを30個配置します。
2 User Defined Runtime Attribute は、

keypath=tag type=Number

を使い、値は、0..29で、各ボタンにわりあてます

3 IB画面で、30個のbuttonをセレクトした状態で、control+ドラッグで、SecondViewControllerへsegueをつくります。segue の名前は、toSecondView とでもします

4 ViewController.m のprepareForSegueのなかでの値の引き出しは

 sv.whoCalledMe= [[sender valueForKeyPath:@"tag"] intValue];

で、いけます。

投稿日時 - 2013-11-21 10:35:32

1 Xcode5.xで、single view application でproject 生成。この状態で、白っぽてのView/View Controllerが設置される。
2 IB画面右下から、View Controllerをひきずって、右に並べる。
3 同じく、IB画面右下から、Buttonをひきずって、左側のView Controller のView内に配置する。
4 IB画面で、配置したButtonの上にキャレットを持って行き、controlを押しながらマウス移動して、右のView Controllerの Viewを結ぶ。この時、Segueのタイプはなににするか、きかれるが、modalにする。
  この状態で、ボタンを押すと、即、右のView Controllerが呼ばれるsegueが出来ている。
5 IB画面で、左のView Controller/View内のButtonをセレクトし、メニューのCopyを選択。
6 メニューのPasteを29回やって、同じButtonを、左のViewController /View内に配置。位置をAppにあうよう整列する。この時点で、30個のButtonすべてが、右にある、View Controller(名無し)をよぶsegueを持っている。
7 IB画面の左のView内のButtonを選択して、右のペーンをIdentity Inspectorにして、User Defined Runtime Attrinbute に値を設定する。たとえば、keypath=buttonID, Type=Number, Value=0

同じように30個のbuttonすべてに、値を設定するが、valueは、0..29で、つける。
8 たった、ひとつある、segueを選択して、右側のペーンをAttribute Inspectorにして、名前を、toSecondViewとでもする。
9 file -> New -> ios Object-C Class で、UIViewControllerのサブクラスとして、SecondViewControllerをつくる
10 右側のViewControllerのクラスを、SecondViewControllerにする
11 SecondViewController.h に、@property (assign) int whoCalledMe; を追加する。
12 ViewController.m に

-(void) prepareForSegue:(UIStoryboardSegue *) segue sender:(id)sender {

// sender から、定義したボタンのattribute の値をひきとり、destination view controllerに値を渡す処理

}

を追加する。この時、senderは、Buttonであって、Button にアクセスできれば、先のUser Defined Runtime Attributeにもアクセスできる。

13 SecondViewController.m のviewDidLoadの中で、
  self.whoCalledMe を使った switch分で、イメージをロードする処理を書く。

投稿日時 - 2013-11-19 16:08:25

補足

凄く丁寧にご回答して頂いて誠にありがとうございます。恐縮しています。
教えて頂いた通りにやっていますが、

12 ViewController.m に
-(void) prepareForSegue:(UIStoryboardSegue *) segue sender:(id)sender {
// sender から、定義したボタンのattribute の値をひきとり、destination view controllerに値を渡す処理

のところを
SecondViewController*viewCon=segue.detstinationVIewController;
viewCon.whoCalledMe=
という感じにしているのですが、
attributeのkeypathのvalueの値の入れ方などを色々調べているのですがわかりません。
もし宜しければ、何かご助言を頂けたら幸いです。

投稿日時 - 2013-11-20 21:49:14

ANo.1

> UIImage*imageDate=[UIImage imageNamed:@"%d,png",_Number];

のところでコンパイラエラーが出ているということですね?

3点誤りがあります。
1.「UIImage imageNamed」につけられるパラメータは、文字列1個だけです。
先にstringWithFormatでファイル名文字列を作ってから、それをimageNamedに
指定する必要があります。
2.宣言部が示されていないので推測ですが、おそらく_Numberは、NSStringクラスなのだと思います。
だとすると、「%d」じゃなくて「%s」です。
3.単純パンチミスだと思いますがファイル名の拡張子区切りは
「,」じゃなくて「.」です。

以上より、
UIImage*imageDate=[UIImage imageNamed:[NSString stringWithFormat:@"%s.png",_Number]];
とすればいいと思います。

ただ、ここでファイル名を組み立てるのではなく、呼び出し元でtagをstringWithFormatで
文字列に変換しているところでファイル名まで組み立てた方がすっきりしてわかりやすいか
もしれません。
(その場合、変数名は、NumberじゃなくてimageFileNameとかにすべきです)

今回はちゃんとソースが示されてどのようなエラーが起きているか説明されているので
すぐわかりました。

投稿日時 - 2013-11-19 11:02:57

お礼

今回と前回と、ご丁寧に助言を頂き本当にありがとうございました。
今回、最後のほうに教えて頂いたimageFIleNameをSVC(h)でNSStringの変数で宣言してから、VCのほうでファイルを組み立てるようにというのをしているのですが、
VC(m)で

- (IBAction)pushBtn:(UIButton *)sender {
[self performSegueWithIdentifier:@"mySegue" sender:self];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:@"mySegue"]){
SecondViewController*viewCon=segue.destinationViewController;
viewCon._imageFileName=[NSString stringWithFormat:@"%d.png",[sender tag]];
}

の最後の行のviewCon._imageFileName=[NSString stringWithFormat:@"%d.png",[sender tag]];
がどうもうまくいっていないよう(動かすと成功になり、ボタンを押すとエラーがでるのですが、コードを書いている時点では何もでない状態)で、色々やっているのですが何が欠けているのかわかない状態です。もし宜しければ、ご助言を頂けたら幸いです。何度も本当にすみません。

投稿日時 - 2013-11-21 01:23:11

あなたにオススメの質問