重要なお知らせ

「教えて! goo」は2025年9月17日(水)をもちまして、サービスを終了いたします。詳細はこちら>

【GOLF me!】初月無料お試し

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

A 回答 (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で追加された文法ですが、ドットでつなぐ記述法に批判が出ました。構造体の要素を記述するのと、区別ができない(しにくい)ではないか?というのが、批判の骨子です。じっさい不備な記述だと、コンパイラも区別ができなくて、混乱するので、問題なしとはいえないようです。

この回答への補足

なるほど。リファレンスを見たりしても@Classというのがたまに出てきていたが、何だろう(省略できるのか?!)と正直思っていました。 お恥ずかしいです...

課題の内容については、再起的になるし、複数のインターフェースで、互いのクラス名を使用してインポートした場合、そもそもエラーがでてしまう。しかしヘッダをインポートしない場合、プロパティとして宣言できないと悩んだあげく、UIViewControllerで宣言してしまっていました。

前方宣言を文献で読んでみて、実際にコーディングした所、ビルドでき、想定していた動作を得ることができました。

最初に練習で作ったアプリは、IBでViewをたくさん用意し、hiddenプロパティを変更していたような作りで始めてしまった為、クラス間の操作でとにかくはまってしまいましたが、詳しい理解はまだまだですが、色々親切に教えていただいたおかげで、???だらけだった所に、光が見えてきた気がして、楽しくなってきました。

長々とおつきあいしていただき、
本当にありがとうございました!!!

補足日時:2011/02/25 19:20
    • good
    • 0

> 課題の内容については、再起的になるし、



おっしゃるとおり、正解です。
    • good
    • 0

> - (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];
}

補足日時:2011/02/25 13:36
    • good
    • 0

> ただ、調子に乗って別解にいどんだのですが、ViewControllerにselfを代入する仕組みが理解できず、とそのメンバーは違うんじゃない的な事をいわれてしまいました。


> superviewControllerの宣言が違うのではと、TestViewController *superviewControllerともしてみたのですが、これもNGでした。

ButtonViewControllerに、TestViewControllerをimportしていないからではないですか?
なお、「#import "TestViewController.h"」は、ヘッダファイル(ButtonViewController.h)ではなく、実装ファイル(ButtonViewController.m)に宣言してください。なぜそうするかは、課題としてすこしお考えになってください。

この手法は、発展させるとObjective-Cではおなじみの、Delegateをオリジナルで実装することにつながります。重要なトレーニングになります。
    • good
    • 0

回答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などは省略しています。

補足日時:2011/02/24 21:00
    • good
    • 0

あなたのお書きになったコードを読み進めてみましたが……



- (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処理する必要はありません。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!