
iOS SDK(Objective-C)を勉強中なのですが、あるView(TestViewController.view)から別のView(ButtonViewController.view)を表示し、表示したViewにあるボタンを押した時に、生成元のView(TestViewController.view)のラベル(test_label)に文字列を表示したいのですが、色々やってみたものの上手く行かず、どの用に実装するのが正しいのか行き詰まってしまいました。どなたか手助けよろしくお願いします。
//*** TestViewController.h
#import <UIKit/UIKit.h>
#import "ButtonViewController.h"
@interface TestViewController : UIViewController {
IBOutlet UILabel *test_label;
ButtonViewController *buttonViewController;
}
- (IBAction) pushButton:(id)sender;
@end
//*** TestViewController.m
#import "TestViewController.h"
@implementation TestViewController
- (void)viewDidLoad {
[super viewDidLoad];
test_label.text = @"Push Button";
}
//ButtonViewを表示
- (IBAction) pushButton:(id)sender {
buttonViewController = [[ButtonViewController alloc] initWithNibName:@"ButtonView" bundle:nil];
[self.view addSubview:buttonViewController.view];
}
- (void)dealloc {
[buttonViewController release];
[super dealloc];
}
@end
//*** ButtonViewController.h
#import <UIKit/UIKit.h>
@interface ButtonViewController : UIViewController {
}
- (IBAction) pushButtonSub:(id)sender;
@end
//*** ButtonViewController.m
#import "ButtonViewController.h"
@implementation ButtonViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (IBAction) pushButtonSub:(id)sender {
// ??? ← このボタンを押したときにtest_labelへ表示させたい
}
- (void)dealloc {
[super dealloc];
}
@end
No.5ベストアンサー
- 回答日時:
> //*** 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で追加された文法ですが、ドットでつなぐ記述法に批判が出ました。構造体の要素を記述するのと、区別ができない(しにくい)ではないか?というのが、批判の骨子です。じっさい不備な記述だと、コンパイラも区別ができなくて、混乱するので、問題なしとはいえないようです。
この回答への補足
なるほど。リファレンスを見たりしても@Classというのがたまに出てきていたが、何だろう(省略できるのか?!)と正直思っていました。 お恥ずかしいです...
課題の内容については、再起的になるし、複数のインターフェースで、互いのクラス名を使用してインポートした場合、そもそもエラーがでてしまう。しかしヘッダをインポートしない場合、プロパティとして宣言できないと悩んだあげく、UIViewControllerで宣言してしまっていました。
前方宣言を文献で読んでみて、実際にコーディングした所、ビルドでき、想定していた動作を得ることができました。
最初に練習で作ったアプリは、IBでViewをたくさん用意し、hiddenプロパティを変更していたような作りで始めてしまった為、クラス間の操作でとにかくはまってしまいましたが、詳しい理解はまだまだですが、色々親切に教えていただいたおかげで、???だらけだった所に、光が見えてきた気がして、楽しくなってきました。
長々とおつきあいしていただき、
本当にありがとうございました!!!
No.4
- 回答日時:
> - (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];
}
No.3
- 回答日時:
> ただ、調子に乗って別解にいどんだのですが、ViewControllerにselfを代入する仕組みが理解できず、とそのメンバーは違うんじゃない的な事をいわれてしまいました。
> superviewControllerの宣言が違うのではと、TestViewController *superviewControllerともしてみたのですが、これもNGでした。
ButtonViewControllerに、TestViewControllerをimportしていないからではないですか?
なお、「#import "TestViewController.h"」は、ヘッダファイル(ButtonViewController.h)ではなく、実装ファイル(ButtonViewController.m)に宣言してください。なぜそうするかは、課題としてすこしお考えになってください。
この手法は、発展させるとObjective-Cではおなじみの、Delegateをオリジナルで実装することにつながります。重要なトレーニングになります。
No.2
- 回答日時:
回答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などは省略しています。
No.1
- 回答日時:
あなたのお書きになったコードを読み進めてみましたが……
- (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処理する必要はありません。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
インスタンス参照でアクセスで...
-
変数名の付け方
-
生成したインスタンスを削除す...
-
複数の変数を宣言する時、同時...
-
C#のメモリ解放についてご教授...
-
VB6からのExcel起動について
-
C#「オブジェクト参照が必要で...
-
C# インスタンスの破棄
-
インスタンスを同じ名前で作成...
-
サーブレットでレスポンスが返...
-
vb.netでFAXを送信する方法
-
javaのthisについて質問です。e...
-
VB.NET Form1からForm2を開い...
-
フォームの存在をチェックする方法
-
VB.NET Newしたものを変数に代...
-
非staticフィールドを参照でき...
-
リアルタイム波形表示
-
String a = "a"; と String b =...
-
C# クラスのインスタンスについて
-
メソッドの引数としてのthisの意味
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
private static という変数の修飾
-
変数名の付け方
-
複数の変数を宣言する時、同時...
-
インスタンス参照でアクセスで...
-
生成したインスタンスを削除す...
-
オブジェクト参照がオブジェク...
-
C#において、同じインスタンス...
-
C# インスタンスの破棄
-
変数の参照でエラーが出てしま...
-
インスタンスを同じ名前で作成...
-
VB.NET getとsetの概念がわかり...
-
newしないインスタンス?実体化...
-
javaのクラスの作り方、エラー...
-
非staticフィールドを参照でき...
-
「インスタンス」の意味をわか...
-
[Visual C#] 優先される処理に...
-
フォームの存在をチェックする方法
-
大量のデータとインスタンスの...
-
C#「オブジェクト参照が必要で...
-
String a = "a"; と String b =...
おすすめ情報