从另一个类访问viewController的方法

时间:2011-04-10 11:48:03

标签: iphone objective-c uiviewcontroller uibutton

我一直在尝试使用UIButton操作来调用不同类中的方法(AppViewController)。我首先尝试在UIButton's调用类(caller.m)中创建视图控制器的实例,然后调用该方法,但这会导致 EXC_BAD_ACCESS

我意识到我需要指向视图控制器的同一个实例,现在我正在尝试确保在caller.m.

中正确声明视图控制器实例

我在AppViewController *viewController中声明了AppDelegate,所以我的想法是从caller.m引用相同的实例。

#import "caller.h"
#import "AppDelegate.h"

@implementation caller

- (id)initWithFrame:(CGRect)frame {
...
[btnSplash addTarget:viewController action:@selector(loadSplashView) forControlEvents:UIControlEventTouchUpInside];
....
}

然而,viewController仍显示为未声明。我尝试了一些其他的东西,但知道我可能遗漏了一些基本的东西。

:::: UPDATE ::::

好的,事实证明我需要创建以下内容,以便实际声明目标“viewController”并指向正确的实例:

AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
AppViewController* viewController = appDelegate.viewController;

现在可以正确调用视图控制器类中的方法。

有关此问题的更清晰解释和更一般的版本,请转到此处: Objective-c basics: Object declared in MyAppDelegate not accessible in another class

3 个答案:

答案 0 :(得分:6)

对象有多种方式可以启动操作,与其他对象通信和/或观察他们感兴趣的更改,包括:

  1. UIControl目标/操作绑定
  2. 协议
  3. 键/值观察(KVO)
  4. 通知
  5. 在这种情况下,我不认为通知是你想要的。当发布通知的对象不关心哪些对象正在观察通知并且可以有一个或多个观察者时,通知是最合适的。如果按下按钮,您通常只需要特定对象来处理操作。

    我建议使用协议。您将在iOS框架中看到许多正在使用的协议,基本上任何具有delegate属性的类通常都会定义委托对象需要遵循的协议。协议是两个对象之间的契约,这样定义协议的对象就知道它可以与符合协议的对象进行通信,而不会对其类或目的做出任何其他假设。

    这是一个示例实现。如果有任何错别字/遗漏,请道歉。

    在caller.h中(我假设调用者是一个UIViewController):

    @class Caller
    
    @protocol CallerDelegate
        - (void)userDidSplashFromCaller:(Caller *)caller;
    @end
    
    @interface Caller : UIViewController
        id <CallerDelegate>    delegate;
    @end
    
    @property (nonatomic, assign)    id <CallerDelegate>    delegate;
    
    @end
    

    在caller.m中:

    @implementation Caller
    
    @synthesize delegate;
    
    - (void)viewDidLoad {
        // whatever you need
        // you can also define this in IB
        [btnSplash addTarget:self forAction:@selector(userTouchedSplashButton)];
    }
    
    - (void)dealloc {
        self.delegate = nil;
        [super dealloc];
    }
    
    - (void)userTouchedSplashButton {
        if (delegate && [delegate respondsToSelector:@selector(userDidSplashFromCaller:)]) {
            [delegate userDidSplashFromCaller:self];
        }
    }
    
    在otherViewController.m中

    // this assumes caller is pushed onto a navigationController
    - (void)presentCaller {
        Caller *caller = [[Caller alloc] init];
        caller.delegate = self;
        [self.navigationController pushViewController:caller animated:YES];
        [caller release];
    }
    
    // protocol message from Caller instance
    - (void)userDidSplashFromCaller:(Caller *)caller {
        NSLog(@"otherVC:userDidSplashFromCaller:%@", caller);
    }
    

    [编辑:澄清]

    我在再次查看您的问题和代码后意识到我做了一些在您的代码中可能不正确的假设。您很可能仍应使用协议,但集成我的示例的确切方式取决于您的应用程序。我不知道你的应用程序中有哪个类Caller,但无论它是什么,它都在处理UIButton,因此很可能是视图控制器或视图。

    关于没有正确的appViewController实例的评论让我想知道你是否理解了类和类实例之间的区别。如果我的回答对您没有帮助,请发布更多代码,说明如何创建和展示您的视图控制器以及如何配置按钮,我可以尝试澄清我的答案。

答案 1 :(得分:3)

单击将在AppViewController中捕获并执行的按钮时,您应该发布NSNotification。

所以这应该是: 在发件人类中:

[btnSplash addTarget:self 
              action:@selector(loadSplashView) 
    forControlEvents:UIControlEventTouchUpInside]; 

-(void)loadSplashView:(id)sender 
{ 
[[NSNotificationCenter defaultCenter] postNotificationName:@"notif_name" object:some_sender_object];
}

在目标类中: 注册以获取视图加载时的通知:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(some_function:) name:@"notif_name" object:nil];

定义要在此课程中采取的操作:

-(void) some_function:(NSNotification *)notif {
   //do something
   // to access the object do: [notif object]
}

答案 2 :(得分:0)

应用的各种对象之间的通信是设计级别的决定。虽然iOS提供了在代码时(属性)执行此操作的简洁方法 - 但它是通过硬耦合实现的。

真正的对象间通信在编译时不会绑定对象 - 这只能通过以下设计模式来确保。

观察员&amp;代表是两种最常用的模式,值得您学习when to use which one - see Observer vs Delegate