2

メソッドが別のクラスで呼び出されたときに、別のオブジェクトのプロパティを変更したい。

このオブジェクトのプロパティを変更するコードは、最初のクラスのメソッドにあり、独自のクラスから呼び出すと機能しますが、他のクラスから呼び出すと、メソッド内のオブジェクトは nil を返します。

コードは次のとおりです。

ViewController.h

@interface ViewController : UIViewController {

    UIView *menuView; //the object

}

@property (nonatomic, retain) IBOutlet UIView *menuView;

-(void)closeMenu; //the method

@end

ViewController.m

@implementation ViewController

@synthesize menuView;

-(void)closeMenu{

    [menuView setFrame:CGRectMake(menuView.frame.origin.x, -menuView.frame.size.height, menuView.frame.size.width, menuView.frame.size.height)];

    NSLog(@"%f", menuView.frame.size.height); //returns height when method is called from it's own class. But returns 0 (nil) when called from the other class.

}

SDNestedTableViewController.h (特に重要なことはありませんが、役に立ちますか?)

@interface SDMenuViewController : SDNestedTableViewController{


}

SDNestedTableViewController.m

#import "SDMenuViewController.h"
#import "ViewController.h"

- (void) item:(SDGroupCell *)item subItemDidChange:(SDSelectableCell *)subItem
{

    ViewController *firstViewController = [[[ViewController alloc] init] autorelease];

    SelectableCellState state = subItem.selectableCellState;
    NSIndexPath *indexPath = [item.subTable indexPathForCell:subItem];
    switch (state) {
        case Checked:
            NSLog(@"Changed Sub Item at indexPath:%@ to state \"Checked\"", indexPath);


            [firstViewController closeMenu]; //called from other class


            break;
        case Unchecked:
            NSLog(@"Changed Sub Item at indexPath:%@ to state \"Unchecked\"", indexPath);
            break;
        default:
            break;
    }
}
4

11 に答える 11

4

あなたが投稿したものは次のようになります:

-(void)closeMenu{
    // menuView is never initialized, == nil
    [nil setFrame:CGRectMake(0, -0, 0, 0)];

    NSLog(@"%f", 0); //returns height when method is called from it's own class. But returns 0 (nil) when called from the other class.

}

だからあなたはやっていNSLog(@"%f", 0);ます。

プロパティにアクセスしてビューをロードするviewと、menuView は IB ルールによって初期化されます。viewController ビューのロード/アンロードの詳細については、リファレンス ドキュメントを参照してください。

于 2012-10-23T00:21:05.547 に答える
2

これはあなたを助けるかもしれないと思います。

あなたのAppDelegateクラスでは、クラスのオブジェクトを宣言する必要がありますViewControllerYourAppDelegateクラスのプロパティとして作成します。以下のように。(これにより、クラスがインポートされ、クラスViewControllerの共有オブジェクトが作成されるYourAppDelegateため、をインポートするだけでクラスのメンバーにYourAppDelegateグローバルにアクセスできますYourAppDelegate.h)。

#import "ViewController.h"

#define UIAppDelegate ((YourAppDelegate *)[UIApplication sharedApplication].delegate)

@interface YourAppDelegate : NSObject <UIApplicationDelegate> 
{
     ViewController  *objViewController;
}

@property (nonatomic, retain) ViewController  *objViewController;

@end

ファイルでプロパティを合成しYourAppDelegate.mます。

@implementation YourAppDelegate

@synthesize objViewController;

@end

次に、注意が必要なのは、クラスをロードするときViewControllerに、クラスのオブジェクトをクラスにバックアップする必要があることです。YourAppDelegateViewController

そのためには、次のようYourAppDelegate.hViewController.hクラスとViewController.m実装viewWillAppear:デリゲートで最初に をインポートします。

- (void)viewWillAppear:(BOOL)animated 
{
    [super viewWillAppear:animated];
    UIAppDelegate.objViewController = self;
}

次にSDNestedTableViewController.m

#import "SDMenuViewController.h"
#import "ViewController.h"

- (void) item:(SDGroupCell *)item subItemDidChange:(SDSelectableCell *)subItem
{

    ViewController *firstViewController = (ViewController *)UIAppDelegate.objViewController;

    if(firstViewController && [firstViewController isKindOfClass:[ViewController class]])
    {
            SelectableCellState state = subItem.selectableCellState;
            NSIndexPath *indexPath = [item.subTable indexPathForCell:subItem];
            switch (state) {
              case Checked:
                        NSLog(@"Changed Sub Item at indexPath:%@ to state \"Checked\"", indexPath);


                        [firstViewController closeMenu]; //called from other class


                        break;
              case Unchecked:
                        NSLog(@"Changed Sub Item at indexPath:%@ to state \"Unchecked\"", indexPath);
                        break;
              default:
                        break;
            }
    }
}

この方法を試してください。私はこれが正しい方法だと言っているわけではありませんが、これはうまくいくはずです。これがお役に立てば幸いです。

于 2012-10-29T08:18:53.827 に答える
1

あなたの問題は、viewController を初期化した方法に関連していると思います。

それ以外の

ViewController *firstViewController = [[[ViewController alloc] init] autorelease];

使用する

ViewController *firstViewController = [[[ViewController alloc] initWithNibName:@"yourNibName" bundle:nil] autorelease];

IBOutlet を使用しているため、ペン先があると想定しています。しかし、nib ファイルをロードしていないため、IBOutlet はセットアップされていないと思います。

また、Interface Builder で IBOutlet 接続を再確認し、「self.menuView」を使用します。

于 2012-10-28T02:14:09.807 に答える
1

問題は:

- (void) item:(SDGroupCell *)item subItemDidChange:(SDSelectableCell *)subItem {

    ViewController *firstViewController = [[[ViewController alloc] init] autorelease];

    ...

    [firstViewController closeMenu];


}

そこから呼び出すと、ビューコントローラーのcloseMenu初期化に十分な時間が経過していないため、初期化されません。この時点でもメソッドは呼び出されません。も nib から作成されていないため、.viewviewDidLoadfirstViewControllermenuViewnil

何らかの理由で十分な遅延が発生する可能性がありますmenuViewが、これは iOS で行うべき方法ではありません。

したがって、を表示したくない場合は、次の代わりにmenuViewブール値を and に追加するだけです。firstViewControllercloseMenu

firstViewController.shouldCloseMenu = YES;

次に、ViewControllerinviewDidLoadメソッドで次のようにします。

if (self.shouldCloseMenu ) {
    [self closeMenu];
}

これは最善の方法ではないかもしれませんが、これでどのように動作するかがわかったはずです。

于 2012-10-23T00:53:16.857 に答える
1

編集2:

さて、あなたはあなたのコードを私に送ってくれたので、あなたの問題を解決するのに十分な情報がないとは言えません。

どれどれ。

次のように、ViewController がアプリの rootViewController であることがわかります。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    // Override point for customization after application launch.
    self.viewController = [[[ViewController alloc] initWithNibName:@"ViewController" bundle:nil] autorelease];
    self.window.rootViewController = self.viewController;
    [self.window makeKeyAndVisible];
    return YES;
}

さて、ViewController は SDNestedTableViewController とどのように関連していますか?

ViewController の viewDidLoad にこれがあります。

- (void)viewDidLoad
{
    [super viewDidLoad];

    SDMenuViewController *mvc = [[[SDMenuViewController alloc] initWithNibName:@"SDNestedTableView" bundle:nil] autorelease];
    [self addChildViewController:mvc];
    [mvc didMoveToParentViewController:self];
    [menuView addSubview:mvc.view];

    // Some other stuff with gesture recognizers I'm omitting...

    [self openMenu];

}

よし、SDMenuViewController は ViewController の子のようだ。これで、SDMenuViewController に item:subItemDidChange というメソッドができました。

- (void) item:(SDGroupCell *)item subItemDidChange:(SDSelectableCell *)subItem
{

    ViewController *firstViewController = [[[ViewController alloc] initWithNibName:@"ViewController" bundle:nil] autorelease];

    SelectableCellState state = subItem.selectableCellState;
    NSIndexPath *indexPath = [item.subTable indexPathForCell:subItem];
    switch (state) {
        case Checked:
            NSLog(@"Changed Sub Item at indexPath:%@ to state \"Checked\"", indexPath);

            //close the menuView

            [firstViewController closeMenu];

            break;
        case Unchecked:
            NSLog(@"Changed Sub Item at indexPath:%@ to state \"Unchecked\"", indexPath);
            break;
        default:
            break;
    }
}

では、既存のViewController オブジェクトへの参照が必要ですよね? すぐに別のものを作っているからです。したがって、これを行うことができます:

ViewController *firstViewController = self.parentViewController;

これにより、ViewController のインスタンスである SDMenuViewController の親への参照が取得されます。このプロパティは、呼び出しを行うときに設定されますaddChildViewController:


さて、これは紛らわしいですが:

あなたの投稿では、あなたのitem:subItemDidChange:メソッドは SDNestedTableViewController にあると言っていますが、あなたが私に送ったコードでは、それは SDMenuViewController にあります。

SDNestedTableViewController で、次のメソッドを見つけました。

- (void) mainItem:(SDGroupCell *)item subItemDidChange: (SDSelectableCell *)subItem forTap:(BOOL)tapped
{
    if(delegate != nil && [delegate respondsToSelector:@selector(item:subItemDidChange:)] )
    {
        [delegate performSelector:@selector(item:subItemDidChange:) withObject:item withObject:subItem];
    }
}

したがって、元の投稿と同じコードを使用していないように見えますが、十分に近いものです。


ここで、SDMenuViewController (たまたま ViewController インスタンスの子) だけでなく、アプリ内の任意の場所から ViewController インスタンスへの参照を取得する場合は、@Mathew Varghese の answer を使用する必要あります

この方法を言い換えると、次のようになります。

  1. この行+ (AppDelegate *)instance;を AppDelegate.h ファイルに追加します。
  2. 次のメソッドを AppDelegate.m ファイルに追加します。

そのようです:

+ (AppDelegate *)instance
{
    AppDelegate *dg = [UIApplication sharedApplication].delegate;
    return dg;
}

次に、その参照が必要なオブジェクトで、次のよう#import AppDelegate.hに言いますViewController *vc = AppDelegate.instance.firstViewController;

とにかく、これはマシューが先ほど言ったことの別の言い方です。

于 2012-10-31T21:25:42.433 に答える
0

UIView*menuViewを削除してみてください。//インターフェースファイルのオブジェクト

@interface ViewController : UIViewController {

    // try to remove this line
    UIView *menuView; //the object

}

このメソッドを更新します

-(void)closeMenu{

    [self.menuView setFrame:CGRectMake(self.menuView.frame.origin.x, -self.menuView.frame.size.height, self.menuView.frame.size.width, self.menuView.frame.size.height)];

    NSLog(@"%f", self.menuView.frame.size.height);

}
于 2012-10-31T02:02:54.037 に答える
0
#import "SDMenuViewController.h"
#import "ViewController.h"

- (void) item:(SDGroupCell *)item subItemDidChange:(SDSelectableCell *)subItem
{

// Checked の場合にのみ必要な場合に、なぜこのオブジェクトをここに割り当てるのか:

    ViewController *firstViewController = [[[ViewController alloc] init] autorelease];
    SelectableCellState state = subItem.selectableCellState;
    NSIndexPath *indexPath = [item.subTable indexPathForCell:subItem];
    switch (state) {
        case Checked:
            NSLog(@"Changed Sub Item at indexPath:%@ to state \"Checked\"", indexPath);


            [firstViewController closeMenu]; //called from other class


            break;
        case Unchecked:
            NSLog(@"Changed Sub Item at indexPath:%@ to state \"Unchecked\"", indexPath);
            break;
        default:
            break;
    }
}

に変更します

#import "SDMenuViewController.h"
#import "ViewController.h"

- (void) item:(SDGroupCell *)item subItemDidChange:(SDSelectableCell *)subItem
{

// Checked の場合にのみ必要な場合に、なぜこのオブジェクトをここに割り当てるのか:

    SelectableCellState state = subItem.selectableCellState;
    NSIndexPath *indexPath = [item.subTable indexPathForCell:subItem];
    switch (state) {
        case Checked:
            NSLog(@"Changed Sub Item at indexPath:%@ to state \"Checked\"", indexPath);


            // here no need to put object in autorelease mode.
            ViewController *firstViewController = [[ViewController alloc] init];
            [firstViewController closeMenu]; //called from other class
            [firstViewController release];

            break;
        case Unchecked:
            NSLog(@"Changed Sub Item at indexPath:%@ to state \"Unchecked\"", indexPath);
            break;
        default:
            break;
    }
}
于 2012-10-30T04:51:27.677 に答える
0

alloc-initViewController をalloc-init'ing することと、その View Controller のプロパティを 'ing することには違いがあります。

2番目の例(別のクラスからの呼び出し)について。あなたの現在のコードは、あなたがalloc-init最初にViewControllerであることを示していますが、その後は何もしません。ViewController のinitメソッドをオーバーライドしていないと仮定すると、そのプロパティと iVar はnil(最悪の場合は未定義) になるはずです。alloc-initあなたはあなたの最初にする必要がありますfirstViewController.menuView。すなわち:

firstViewController.menuView = [[UIView alloc] initWithFrame]; // Don't do this.

このアプローチの問題点は、firstViewController のプロパティを別のクラスから設定していることであり、これは一般的にかなり平均的な設計手法です。通常、この必要なセットアップは でviewDidLoad行われますが、まだ firstViewController で何もしていないため、呼び出されることはありません。

対照的に、closeMenu独自のView Controllerから呼び出すと、実際にビューで何かを行っている可能性が高く、viewDidLoad(またはmenuView = [[UIView alloc] init];見つかった場所)が最初に呼び出され、menuViewオブジェクトが初期化されます。

menuView オブジェクトを使って何かをしようとする前に、最初にそれが初期化されていることを確認する必要があります。それを含む View Controller を初期化するだけでは十分ではありません。

于 2012-10-29T07:19:37.917 に答える
0

これを使用することをお勧めします:

if(menuView) {
    [menuView setFrame:CGRectMake(menuView.frame.origin.x, -menuView.frame.size.height, menuView.frame.size.width, menuView.frame.size.height)];
} else {
    NSLog(@"menuView is nil");
}
于 2012-10-31T13:17:21.547 に答える
0

すべてが正しいです。-(void)closeMenuメソッドを次のように変更します...

-(void)closeMenu
{
    menuView=[[UIView alloc]initWithFrame:CGRectMake(50.0,50.0,200.0,200.0)]
    NSLog(@"%f", menuView.frame.size.height); //returns height when method is called from it's own class. But returns 0 (nil) when called from the other class.
}

これを試して、私に知らせてください。

于 2012-10-30T06:57:44.123 に答える
0

次の手順でこの問題を解決することをお勧めします。

  1. firstViewControllerでのインスタンスまたは変数を使用しないでくださいSDMenuViewController

  2. ケース チェック ブロックで、NSNotificationCenter

  3. ViewController同じメッセージ ID を持つメッセージを登録する際に、メソッドをそのハンドラーとして使用しますcloseMenu

私にとっては、メッセージ センターを使用してハンドリングをディスパッチすると、コントローラー間の関係を切り離すことができます。これは、別のコントローラー内のコントローラーのライフサイクルについてあまり気にしないためのより良い方法です。

それが役立つことを願っています。

于 2012-10-23T00:51:27.360 に答える