不能让代理人在我的观点之间工作 [英] Cannot get delegate to work between my views

查看:154
本文介绍了不能让代理人在我的观点之间工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要从一个视图中调用一些方法到另一个视图,我似乎无法让它工作。我做错了什么?

I need to call some methods from one view to another, and I can't seem to get it to work. What am I doing wrong?

这是我的 ViewController.h

#import <UIKit/UIKit.h>
#import "mySettings.h"

@protocol ViewControllerDelegate <NSObject>
@required
- (void) getDefaults;
- (void) updateSubTotal: ( float ) value;
@end

@interface ViewController : UIViewController <UIPickerViewDataSource, UIPickerViewDelegate> {
    id <ViewControllerDelegate> delegate;
}

@property (retain) id delegate;
.
. (other declarations)
.
@end

ViewController.m

#import "ViewController.h"
#import "mySettings.h"

@interface ViewController  (  ) 
@property (assign) mySettings *settingsVC;
@end

@implementation ViewController

-  ( void ) viewDidLoad {
    [ super viewDidLoad ] ;
    // Do any additional setup after loading the view, typically from a nib.

    self.userDefaults =  [[NSUserDefaults alloc] initWithSuiteName:@"group.Just-The-Tip"] ;
    [ self getDefaults ] ;

    self.arrPercent = @ [ @"1",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9",@"10",@"11",@"12",@"13",@"14",@"15",@"16",@"17",@"18",@"19",@"20",@"21",@"22",@"23",@"24",@"25",@"26",@"27",@"28",@"29",@"30",@"31",@"32",@"33",@"34",@"35",@"36",@"37",@"38",@"39",@"40",@"41",@"42",@"43",@"44",@"45",@"46",@"47",@"48",@"49",@"50" ] ;
    self.arrPeople = @ [ @"1",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9",@"10",@"11",@"12",@"13",@"14",@"15",@"16",@"17",@"18",@"19",@"20" ] ;

    self.myPicker.dataSource = self;
    self.myPicker.delegate = self;

    if ( self.bRememberLastBill )
    {
        self.subtotal =  [ self.userDefaults floatForKey:@"sub_total" ] ;
        self.strSubTotal =  [ NSString stringWithFormat: @"%.2f", self.subtotal ] ;
        [ self updateSubTotal:-3 ] ;
    }

    // BEGIN ENABLE DONE BUTTON FOR NUMPAD
    UIToolbar * keyboardDoneButtonView = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, 320, 32)];;
    keyboardDoneButtonView.items = [NSArray arrayWithObjects:
                                    [[UIBarButtonItem alloc] initWithTitle:@"Clear" style:UIBarButtonItemStyleDone target:self action:@selector(clearClicked:)],
                                    [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil],
                                    [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:self action:@selector(doneClicked:)], nil
                                    ];
    [keyboardDoneButtonView sizeToFit];
    self.field_SubTotal.inputAccessoryView = keyboardDoneButtonView;
    // END ENABLE DONE BUTTON FOR NUMPAD

    UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 16, 60)];
    self.field_SubTotal.rightView = paddingView;
    self.field_SubTotal.rightViewMode = UITextFieldViewModeAlways;

    self.settingsVC = [[mySettings alloc] init];
    self.settingsVC.delegate = self ;

    [ self animate ] ;
}

-  ( void ) getDefaults
{
    // lots of stuff here
}

-  ( void ) updateSubTotal: ( float ) value
{
    // even more code here
}

mySettings.h

#import <UIKit/UIKit.h>
#import "ViewController.h"

@interface mySettings : UIViewController {

}

@property (nonatomic, assign) id delegate;
.
. (a bunch of declarations)
.
@end

mySettings.m

#import "mySettings.h"
#import "ViewController.h"

@interface mySettings  (  ) 

@end

@implementation mySettings

@synthesize delegate;

-  ( void ) viewDidLoad {
     [ super viewDidLoad ] ;
    // Do any additional setup after loading the view.

    //self.userDefaults =  [ NSUserDefaults standardUserDefaults ] ;
    self.userDefaults =  [[NSUserDefaults alloc] initWithSuiteName:@"group.Just-The-Tip"] ;

    [ self getDefaults ] ;

    self.textDefaultTax.text =  [ NSString stringWithFormat:@"%.3f", self.default_tax ] ;
    self.textDefaultTip.text =  [ NSString stringWithFormat:@"%.f", self.default_tip ] ;

    // BEGIN ENABLE DONE BUTTON FOR NUMPAD
    UIToolbar * keyboardDoneButtonView = [[UIToolbar alloc] init];
    [keyboardDoneButtonView setItems:[NSArray arrayWithObjects:
                                      [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil],
                                      [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:self action:@selector(doneClicked:)],
                                      nil]];
    [keyboardDoneButtonView sizeToFit];
    self.textDefaultTip.inputAccessoryView = keyboardDoneButtonView;
    self.textDefaultTax.inputAccessoryView = keyboardDoneButtonView;
    // END ENABLE DONE BUTTON FOR NUMPAD

    [ self animate ] ;
}

// a few methods later

- (IBAction)up_default_exclude_tax:(id)sender {
    self.bExcludeTax = self.switchExcludeTax.isOn;
    [ self setDefaults ] ;
    [ self.delegate getDefaults ];
    [ self.delegate updateSubTotal:-3 ];
}


推荐答案

坦白说,你几乎感到困惑我 :)。实现委托设计模式和连接视图控制器的方式不是建议/记录的方式。

Frankly, you have almost confused me :). The way you are implementing delegate design pattern and connecting view controllers is not the suggested/documented way of doing it.

让我们一步一步。

步骤1:MySettings(像UITableViewController)实现一些功能,并依赖其委托来实现其他人。

Step 1: MySettings (like UITableViewController) implements some feature and relies on its delegate to implement others.

所以,以下几点远离这里:

So, following points to take away from here:


  1. 协议定义必须为 MySettingsDelegate 而不是 ViewControllerDelegate

  2. 重命名 mySettings MySettingsViewController

  3. MySettingsViewController 不应导入 ViewController 。它必须使用其委托属性与 ViewController 进行交互。

  1. protocol definition must be MySettingsDelegate and not ViewControllerDelegate.
  2. rename mySettings to MySettingsViewController.
  3. MySettingsViewController should not import ViewController. It must use its delegate property to interact with ViewController.

这是我的 MySettingsViewController 看起来像发布这些更改。

This is how my MySettingsViewController would look like post these changes.

MySettingsViewController.h

`

@protocol MySettingsViewControllerDelegate <NSObject>
@required
- (void) getDefaults;
- (void) updateSubTotal: ( float ) value;
@end




@interface MySettingsViewController : UIViewController {

}

@property (nonatomic, assign) id delegate;
.
. (a bunch of declarations)
.
@end`

Step2:您不需要在属性上调用@synthesis更多。另外,在调用委托方法之前,总是做一个零检查的好习惯。请看我的 MySettingsViewController.m 的样子。我还添加了一些NSLog语句来验证控件是否到达。

Step2: You don't need to call @synthesis on properties any more. Also, before calling a method on delegate it is always good practice to do a nil check. Please see how my MySettingsViewController.m would look like. I have also added some NSLog statement for you to verify if controls comes there or not.

MySettingsViewController.m

@implementation MySettingsViewController
-  ( void ) viewDidLoad {
    [ super viewDidLoad ] ;
    // Do any additional setup after loading the view.

    //self.userDefaults =  [ NSUserDefaults standardUserDefaults ] ;
    self.userDefaults =  [[NSUserDefaults alloc] initWithSuiteName:@"group.Just-The-Tip"] ;

    [ self getDefaults ] ;

    self.textDefaultTax.text =  [ NSString stringWithFormat:@"%.3f", self.default_tax ] ;
    self.textDefaultTip.text =  [ NSString stringWithFormat:@"%.f", self.default_tip ] ;

    // BEGIN ENABLE DONE BUTTON FOR NUMPAD
    UIToolbar * keyboardDoneButtonView = [[UIToolbar alloc] init];
    [keyboardDoneButtonView setItems:[NSArray arrayWithObjects:
                                      [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil],
                                      [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:self action:@selector(doneClicked:)],
                                      nil]];
    [keyboardDoneButtonView sizeToFit];
    self.textDefaultTip.inputAccessoryView = keyboardDoneButtonView;
    self.textDefaultTax.inputAccessoryView = keyboardDoneButtonView;
    // END ENABLE DONE BUTTON FOR NUMPAD

    [ self animate ] ;
}

// a few methods later

- (IBAction)up_default_exclude_tax:(id)sender {
    self.bExcludeTax = self.switchExcludeTax.isOn;
    [self setDefaults];

    NSLog(@"Action taken");

    if (self.delegate && [self.delegate respondsToSelector:@selector(getDefaults)]) {
        NSLog(@"Calling getDefaults");
        [self.delegate getDefaults];
    }

    if (self.delegate && [self.delegate respondsToSelector:@selector(updateSubTotal:)]) {
        NSLog(@"Calling updateSubTotal:");
        [self.delegate updateSubTotal:-3];
    }
}

步骤3:现在,我的支持类准备好了,让它使用它。写入ViewController类的时间。不知道为什么你在ViewController的标题中添加了委托,我们在这里也不需要它。这是我的 ViewController.h 将如下所示:

Step 3: Now, that my support class ready, lets use it. Time to write ViewController class. Not sure why you added delegate in header of ViewController as well, we literally do not need it here. This is how my ViewController.h will look like:

ViewController.h / p>

ViewController.h

@interface ViewController : UIViewController <UIPickerViewDataSource, UIPickerViewDelegate, MySettingsViewControllerDelegate> {

}

.
. (other declarations)
.
@end

步骤4:现在是主要部分。请确保您强力参考 MySettingsViewController 。这就是我的 ViewController.m 将如下所示:

Steps 4: Now comes the main part. Please ensure you hold a strong reference to MySettingsViewController. This is how my ViewController.m would look like:

ViewController.m / p>

ViewController.m

@interface ViewController()
@property (nonatomic, strong) MySettingsViewController *settingsVC;
@end
-  ( void ) viewDidLoad {
    [super viewDidLoad ] ;
    // Do any additional setup after loading the view, typically from a nib.

    self.userDefaults =  [[NSUserDefaults alloc] initWithSuiteName:@"group.Just-The-Tip"] ;
    [ self getDefaults ] ;

    self.arrPercent = @ [ @"1",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9",@"10",@"11",@"12",@"13",@"14",@"15",@"16",@"17",@"18",@"19",@"20",@"21",@"22",@"23",@"24",@"25",@"26",@"27",@"28",@"29",@"30",@"31",@"32",@"33",@"34",@"35",@"36",@"37",@"38",@"39",@"40",@"41",@"42",@"43",@"44",@"45",@"46",@"47",@"48",@"49",@"50" ] ;
    self.arrPeople = @ [ @"1",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9",@"10",@"11",@"12",@"13",@"14",@"15",@"16",@"17",@"18",@"19",@"20" ] ;

    self.myPicker.dataSource = self;
    self.myPicker.delegate = self;

    if ( self.bRememberLastBill )
    {
        self.subtotal =  [ self.userDefaults floatForKey:@"sub_total" ] ;
        self.strSubTotal =  [ NSString stringWithFormat: @"%.2f", self.subtotal ] ;
        [ self updateSubTotal:-3 ] ;
    }

    // BEGIN ENABLE DONE BUTTON FOR NUMPAD
    UIToolbar * keyboardDoneButtonView = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, 320, 32)];;
    keyboardDoneButtonView.items = [NSArray arrayWithObjects:
                                    [[UIBarButtonItem alloc] initWithTitle:@"Clear" style:UIBarButtonItemStyleDone target:self action:@selector(clearClicked:)],
                                    [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil],
                                    [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:self action:@selector(doneClicked:)], nil
                                    ];
    [keyboardDoneButtonView sizeToFit];
    self.field_SubTotal.inputAccessoryView = keyboardDoneButtonView;
    // END ENABLE DONE BUTTON FOR NUMPAD

    UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 16, 60)];
    self.field_SubTotal.rightView = paddingView;
    self.field_SubTotal.rightViewMode = UITextFieldViewModeAlways;

    self.settingsVC = [[MySettingsViewController alloc] init];
    self.settingsVC.delegate = self ;

    [ self animate ] ;
}

-  ( void ) getDefaults
{
    // lots of stuff here
}

-  ( void ) updateSubTotal: ( float ) value
{
    // even more code here
}

我相信这样做必须解决你的问题,并且会使委托模式变得清晰。您还需要确保在 MySettingsViewController 处于活动状态并调用其委托时, ViewController 也保留在内存中。

I believe this must solve your issue and would bring clarity to delegate pattern. You also need to ensure that while MySettingsViewController is active and calls its delegate, ViewController also stays in memory.

编辑:如果您正在使用故事板

请确保您正确地设置代理正确的对象。不要实例化你自己的对象。

Please ensure you are setting the delegate correctly on the right object. Do not instantiate your own object.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"SegueRegistrationUserAction"]) {
        [(MySettingsViewController *)segue.destinationViewController setDelegate:self];
    }
}

最终编辑(固定在代码中):

所以,我看了看你的代码,发现了这个问题。这显然是不同的对象问题。您正在使用故事板,并在代码中创建一个 mySettings 对象。当您通过故事板连接时,您应该使用从故事板创建的对象,并避免创建自己的对象。当我在 ViewController.m 中更改以下方法时,它会解决问题。

So, I took a look at your code and found the issue. It was apparently different objects issue. You are using storyboard and also creating a mySettings object in code as well. When you connect via storyboard, you should use the object created from storyboard and avoid creating your own. When I changed the below method in your ViewController.m, it fixed the issue.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    self.settingsVC = (mySettings *)segue.destinationViewController;
    self.settingsVC.delegate = self;
}

这篇关于不能让代理人在我的观点之间工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆