- ベストアンサー
Obj-Cで生成元のViewへ文字列を表示させたい
- iOS SDK(Objective-C)を勉強中なのですが、あるView(TestViewController.view)から別のView(ButtonViewController.view)を表示し、表示したViewにあるボタンを押した時に、生成元のView(TestViewController.view)のラベル(test_label)に文字列を表示したいのですが、色々やってみたものの上手く行かず、どの用に実装するのが正しいのか行き詰まってしまいました。
- iOS SDKのObjective-Cで、あるViewから別のViewを表示し、ボタンを押すと生成元のViewのラベルに文字列を表示したいですが、うまくいきません。どのように実装すればよいでしょうか。
- iOS SDKのObjective-Cで、あるViewから別のViewを表示し、そのViewのボタンを押したときに、元のViewのラベルに文字列を表示したいです。実装方法を教えてください。
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
> //*** ButtonViewController.h > @interface ButtonViewController : UIViewController { > UIViewController *superviewController; > } > @property (nonatomic, retain) UIViewController *superviewController; > - (IBAction) pushButtonSub:(id)sender; 「UIViewController *superviewController;」ではなく、「TestViewController *superviewController;」としてください。 UIViewControllerにはとうぜん「test_label」というプロパティがありませんから、コンパイラはそれを構造体と認識し、「request for member 'test_label' in something not a structure or union」というエラーメッセージを出します。TestViewControllerなら、test_labelというプロパティがあるので、エラーになりません。 しかし、これだとTestViewController.hをimportしていないので、「その型は理解できない」というエラーが出ます。そしてヘッダファイルで「#import "TestViewController.h”と宣言すると、別の問題が起きます。回答No.3で課題とした問題です。 そこでButtonViewController.hのヘッダファイルには、「@class TestViewController」という前方宣言を記述しておきます。 「前方宣言」は、C言語の用語ではなく、Objective-Cの用語です。お手持ちのObjective-C、iPhone SDKの参考書でお調べください。(説明がないかもしれませんが……) ※プロパティはObjective-C 2.0で追加された文法ですが、ドットでつなぐ記述法に批判が出ました。構造体の要素を記述するのと、区別ができない(しにくい)ではないか?というのが、批判の骨子です。じっさい不備な記述だと、コンパイラも区別ができなくて、混乱するので、問題なしとはいえないようです。
その他の回答 (5)
- harawo
- ベストアンサー率58% (3742/6450)
> 課題の内容については、再起的になるし、 おっしゃるとおり、正解です。
- harawo
- ベストアンサー率58% (3742/6450)
> - (IBAction) pushButtonSub:(id)sender { > superviewController = [[UIViewController alloc] init]; > superviewController.test_label.text = @"Test";//ここでエラーが発生 > } なぜUIViewControllerインスタンスを新たに作って、それをすでにTestViewControllerのインスタンスが代入されているはずの、superviewControllerに代入するのでしょうか? これでは「不可能を可能にする」ではなくて、「可能を不可能にする」ことになっています。
補足
なるほど。ButtonViewControllerクラスを生成する際に、selfを代入しているので、生成する必要はないですね。 superviewControllerの宣言に問題があったりするのでしょうか? 再び、混乱してきました。。。 TestViewControllerクラスでButtonViewControllerインスタンスを生成する際に、buttonViewController.superviewController = self; をすることで、TestViewControllerがインスタンスを持っていることが分かってきたので、ButtonViewControllerクラスのプロパティでsuperviewControllerを宣言しておき、superviewController.test_label.text = @"Test"; で取得できると思ったのですが、いざ実行すると今回も「request for member 'test_label' in something not a structure or union」で怒られてしまいました。 //*** TestViewController.h #import "ButtonViewController.h" @interface TestViewController : UIViewController { IBOutlet UILabel *test_label; } - (IBAction) pushButton:(id)sender; //*** TestViewController.m(viewDidLoad、dealloc 割愛) #import "TestViewController.h" @implementation TestViewController - (IBAction) pushButton:(id)sender { ButtonViewController *buttonViewController = [[ButtonViewController alloc] initWithNibName:@"ButtonView" bundle:nil]; buttonViewController.superviewController = self; [self.view addSubview:buttonViewController.view]; } //*** ButtonViewController.h @interface ButtonViewController : UIViewController { UIViewController *superviewController; } @property (nonatomic, retain) UIViewController *superviewController; - (IBAction) pushButtonSub:(id)sender; //*** ButtonViewController.m(viewDidLoad、dealloc 割愛) #import "ButtonViewController.h" #import "TestViewController.h" @implementation ButtonViewController @synthesize superviewController; - (IBAction) pushButtonSub:(id)sender { superviewController.test_label.text = @"Test"; [self.view removeFromSuperview]; }
- harawo
- ベストアンサー率58% (3742/6450)
> ただ、調子に乗って別解にいどんだのですが、ViewControllerにselfを代入する仕組みが理解できず、とそのメンバーは違うんじゃない的な事をいわれてしまいました。 > superviewControllerの宣言が違うのではと、TestViewController *superviewControllerともしてみたのですが、これもNGでした。 ButtonViewControllerに、TestViewControllerをimportしていないからではないですか? なお、「#import "TestViewController.h"」は、ヘッダファイル(ButtonViewController.h)ではなく、実装ファイル(ButtonViewController.m)に宣言してください。なぜそうするかは、課題としてすこしお考えになってください。 この手法は、発展させるとObjective-Cではおなじみの、Delegateをオリジナルで実装することにつながります。重要なトレーニングになります。
- harawo
- ベストアンサー率58% (3742/6450)
回答No.1の「おまけ」の部分について。とんだ勘違いを書いてしまいました。addSubviewしたあとに、Viewをreleaseするのは、正しいのですが、ViewControllerをReleaseしてはいけません。このふたつを区別せずに、ごっちゃにしていました。間違ったことを書いてしまいました。すみません。
補足
ヒントありがとうございます! 色々試しまくり、何をどう説明すればいいか良く分からず、???のように質問してしまいました。 すみませんでした。 やっぱり、根本的なところが分かっていないというのを痛感しました。 superviewプロパティを利用するヒントを参考に、 propertyでUILabelを指定し、Tagを付け、ButtonViewController側で生成した所、目的の内容を実現できました!本当にありがとうございます! UILabel *superViewLabel = (UILabel *)[[self.view superview] viewWithTag:100]; superViewLabel.text = @"Test"; 本当にありがとうございます! ただ、調子に乗って別解にいどんだのですが、ViewControllerにselfを代入する仕組みが理解できず、とそのメンバーは違うんじゃない的な事をいわれてしまいました。 superviewControllerの宣言が違うのではと、TestViewController *superviewControllerともしてみたのですが、これもNGでした。 根本的なところだとは思うのですが、書籍を読んでもいまひとつ分からず、駄目なところを指摘してもらえるとありがたいです。 //*** TestViewController.h @interface TestViewController : UIViewController { IBOutlet UILabel *test_label; ButtonViewController *buttonViewController; } @property (nonatomic, retain) ButtonViewController *buttonViewController; - (IBAction) pushButton:(id)sender; //*** TestViewController.m @synthesize buttonViewController; - (void)viewDidLoad { [super viewDidLoad]; test_label.tag = 100; test_label.text = @"Push Button"; } - (IBAction) pushButton:(id)sender { buttonViewController = [[ButtonViewController alloc] initWithNibName:@"ButtonView" bundle:nil]; buttonViewController.superviewController = self; [self.view addSubview:buttonViewController.view]; } - (void)dealloc { [buttonViewController release]; [super dealloc]; } //*** ButtonViewController.h @interface ButtonViewController : UIViewController { UIViewController *superviewController; } @property (nonatomic, retain) UIViewController *superviewController; - (IBAction) pushButtonSub:(id)sender; //*** ButtonViewController.m @synthesize superviewController; - (void)viewDidLoad { [super viewDidLoad]; } - (IBAction) pushButtonSub:(id)sender { superviewController = [[UIViewController alloc] init]; superviewController.test_label.text = @"Test"; //ここでエラーが発生 } - (void)dealloc { [superviewController release]; [super dealloc]; } ※import,@endなどは省略しています。
- harawo
- ベストアンサー率58% (3742/6450)
あなたのお書きになったコードを読み進めてみましたが…… - (IBAction) pushButtonSub:(id)sender { // ??? ← このボタンを押したときにtest_labelへ表示させたい } これでは、質問の丸投げ、「ボクの代わりに、コード書いてちょーダイ!」といっているに等しい態度です。 ヒントだけ書いておきます。 TestViewController.viewとButtonViewController.viewは、親ビュー(superview)と子ビュー(subview)の関係にあります。UILabel *test_labelも、TestViewController.viewの子ビューです。プロパティsuperviewとsubviewsでたどっていって、ButtonViewController.viewから、test_labelのインスタンスを取得することができます。 別解としては、ButtonViewControllerのプロパティとして「superviewController」とでもいうようなものを作っておき、TestViewControllerでButtonViewControllerを生成したときに、「buttonViewController.superviewController = self」とすれば、ButtonViewControllerからTestViewControllerを、インスタンスとして取得できます。 おまけ: - (IBAction) pushButton:(id)sender { buttonViewController = [[ButtonViewController alloc] initWithNibName:@"ButtonView" bundle:nil]; [self.view addSubview:buttonViewController.view]; } - (void)dealloc { [buttonViewController release]; [super dealloc]; } ViewをaddSubviewすると、Viewはコピーされます。なので、buttonViewControllerは、addSubviewの直後にreleaseしましょう。 「[[[ButtonViewController alloc] initWithNibName:@"ButtonView" bundle:nil] autorelease]」として、おまかせでreleaseしてもいいでしょう。 なお、removeFromSuperviewで、子ビューを切り離すとき、子ビューはreleaseされます。別にrelease処理する必要はありません。
補足
なるほど。リファレンスを見たりしても@Classというのがたまに出てきていたが、何だろう(省略できるのか?!)と正直思っていました。 お恥ずかしいです... 課題の内容については、再起的になるし、複数のインターフェースで、互いのクラス名を使用してインポートした場合、そもそもエラーがでてしまう。しかしヘッダをインポートしない場合、プロパティとして宣言できないと悩んだあげく、UIViewControllerで宣言してしまっていました。 前方宣言を文献で読んでみて、実際にコーディングした所、ビルドでき、想定していた動作を得ることができました。 最初に練習で作ったアプリは、IBでViewをたくさん用意し、hiddenプロパティを変更していたような作りで始めてしまった為、クラス間の操作でとにかくはまってしまいましたが、詳しい理解はまだまだですが、色々親切に教えていただいたおかげで、???だらけだった所に、光が見えてきた気がして、楽しくなってきました。 長々とおつきあいしていただき、 本当にありがとうございました!!!