2013-12-08 72 views
1

我已经阅读过,而且好像代表会在我的应用中真正有用。不幸的是,关于我尝试过的协议的每个教程都失败了 - 代表没有收到消息!如果有人能告诉我我做错了什么,那将会很棒。Objective-C协议不发送消息

我用两个ViewControllers,一个FirstViewController和一个SecondViewController创建了一个非常简单的测试应用程序。我已经在容器视图中设置它们以正确查看效果。 我Main.storyboard看起来是这样的:

Main.storybord

测试程序的目的是改变的时候的一个按钮在FirstViewController按下SecondViewController的背景色。

这里是FirstViewController.h:

#import <UIKit/UIKit.h> 

@protocol FirstViewControllerDelegate 

-(void)colourDidChange:(UIColor *)theColour; 

@end 

@interface FirstViewController : UIViewController{ 

    UIButton *redButton; 
    UIButton *blueButton; 
} 

@property (nonatomic, retain) id <FirstViewControllerDelegate> delegate; 

@property (nonatomic, retain) IBOutlet UIButton *redButton; 
@property (nonatomic, retain) IBOutlet UIButton *blueButton; 

-(IBAction)redPressed; 
-(IBAction)bluePressed; 

我FirstViewController.m:

#import "FirstViewController.h" 

@interface FirstViewController() 

@end 

@implementation FirstViewController 

@synthesize redButton, blueButton; 
@synthesize delegate; 

-(IBAction)redPressed{ 
    [self.delegate colourDidChange:[UIColor redColor]]; 
} 
-(IBAction)bluePressed{ 
    [self.delegate colourDidChange:[UIColor blueColor]]; 
} 

-(void)viewDidLoad 
{ 
    [super viewDidLoad]; 
} 

我想我已经实现的协议和委托的正确调用。

这里是我的SecondViewController.h:

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

@interface SecondViewController : UIViewController <FirstViewControllerDelegate> 

-(void)colourDidChange:(UIColor *)theColour; 

而且我SecondViewController.m:

-(void)colourDidChange:(UIColor *)theColour{ 
    self.view.backgroundColor = theColour; 
} 

-(void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    FirstViewController *firstView = [[FirstViewController alloc]init]; 
    firstView.delegate = self; 
} 

我已经breakpointed该项目,并意识到colourDidChange:在SecondViewController永远不会执行。 如果有人能够指出我做错了什么,是否宣布(或遵守)代表不力,或者不是以正确的方式设置代表,我们将不胜感激。

非常感谢。

+0

你断点在哪里? In-colourDidChange:?或者在 - 被压制/ -bluePressed?这可能有助于确定事情发生的地方,例如如果在行动中,或许代表是零,为什么事情没有进展。我可以看到一些错误:1.委托属性是一个弱财产('弱'或'分配'),而不是保留/强。另外,IBAction的签名应该是 - (IBAction):foo:(id)sender;你的行为缺乏'身份证'的论点。 – hsoi

+0

我突出了两个 - 当调用blue/redPressed时,self.delegate是0x0。从另一个类设置变量从来没有为我工作。 – nanothread59

+0

好的。我的猜测是你可能有2个FirstViewController实例,特别是因为在你的SectionViewController中创建的'firstView'不一定是以一种典型的方式创建的。由于您使用的是故事板,因此您可以尝试将代理作为IBOutlet公开,并将其连接到故事板而不是-viewDidLoad中。 – hsoi

回答

1

你说实话非常接近。集装箱的意见将调用prepareForSegue:方法,所以你应该在这种方法中初始化第二视图控制器的委托:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 
    if ([segue.identifier isEqualToString:@"TypeContainerViewSegueNameHere"]) { 
     SecondViewController *viewController = (SecondViewController *)segue.destinationViewController; 
     viewController.delegate = self; 
    } 
} 

你知道你所得到SecondViewController的情况下,这将是在用这种方式。此外,你不需要重新声明委托方法在SecondViewController.h文件:

-(void)colourDidChange:(UIColor *)theColour; 

最后,在故事板的容器视图SEGUE的标题设置为SecondViewController到任何你喜欢的标题,然后复制粘贴标题到'TypeContainerViewSegueNameHere'写在上面的地方。

编辑1:

一个典型的情况是与此类似:

@protocol ViewControllerDelegate; 

@interface ViewController : UIViewController 

@property (nonatomic, strong) id<ViewControllerDelegate>delegate; 

@end 

@protocol ViewControllerDelegate <NSObject> 

- (void) delegateMethod; 

@end 

... 

@implementation ViewController 

- (void) buttonAction:(id)sender { 
    [self.delegate delegateMethod]; 
} 

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 
    if ([segue.identifier isEqualToString:@"TypeContainerViewSegueNameHere"]) { 
     SecondViewController *viewController = (SecondViewController *)segue.destinationViewController; 
     viewController.delegate = self; 
    } 
} 

@end 

... 

@interface SecondViewController : UIViewController <ViewControllerDelegate> 

@end 

... 

@implementation SecondViewController 

- (void)delegateMethod { 

} 

@end 

这就是说,你可以让你的主视图控制器的FirstViewController的代表,其中有两个视图在屏幕中看到的容器。然后从主视图控制器调用委托方法到第二个视图控制器。虽然我很好奇你为什么将这两个视图控制器作为子视图控制器,而不是在一个视图控制器中放置视图和两个按钮。

编辑2:

下面是一个例子(快速写和未测试)。把它看成是代表一个三角形:

@protocol FirstViewControllerDelegate; 

@interface FirstViewController : UIViewController 

@property (nonatomic, strong) id<FirstViewControllerDelegate>delegate; 

@end 

@protocol FirstViewControllerDelegate <NSObject> 

- (void) firstViewControllerDelegateMethod; 

@end 

... 

@implementation FirstViewController 

- (void) buttonAction:(id)sender { 
    [self.delegate firstViewControllerDelegateMethod]; 
} 

@end 

... 

@protocol MainViewControllerDelegate; 

@interface MainViewController : UIViewController <FirstViewControllerDelegate> 

@end 

@protocol MainViewControllerDelegate <NSObject> 

- (void) mainViewControllerDelegateMethod; 

@end 

... 

@implementation MainViewController 

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 
    if ([segue.identifier isEqualToString:@"TypeContainerViewSegueNameHere"]) { 
     SecondViewController *viewController = (SecondViewController *)segue.destinationViewController; 
     viewController.delegate = self.delegate; 
    } 
    if ([segue.identifier isEqualToString:@"TypeContainerViewSegueNameHere"]) { 
     FirstViewController *viewController = (FirstViewController *)segue.destinationViewController; 
     viewController.delegate = self; 
    } 
} 

- (void)firstViewControllerDelegateMethod { 
    [self.delegate mainViewControllerDelegateMethod]; 
} 

@end 

... 

@interface SecondViewController : UIViewController <MainViewControllerDelegate> 

@end 

... 

@implementation SecondViewController 

- (void)mainViewControllerDelegateMethod { 

} 

@end 

就像我说的,你应该考虑减少你的应用程序这一部分的复杂性,并考虑把你的视图在一个视图控制器。

+0

我把那段代码放在SecondViewController.m中,除了我改变了代码,因为我想让SecondViewController成为FirstViewController的委托,而不是其他方式。但它仍然没有工作。我的普通应用程序不使用容器视图,那么如果没有它们,你将如何做到这一点? – nanothread59

+0

感谢您的编辑,号码1为我工作。例如,如果你正在创建一个iPad应用程序,并希望像UIImagePickerController委托一样从弹出窗口传递数据,你会如何做到这一点? – nanothread59

+0

如果它有效,你可能想选择它作为答案,并发布一个单独的问题,“想从像UIImagePickerController委托这样的弹出式窗口中传递数据”你会得到来自更多人的回复,而不仅仅是我,它是一个有效的问题要有自己的线索。一般的想法是,UIImagePickerControllerDelegate将回调到呈现UIImagePickerController的视图控制器,然后处理回调方法。 – Chris

3

我怀疑有两个FirstViewController的实例,一个是由您的故事板创建的,另一个是在SecondViewControllerviewDidLoad方法中创建的。

FirstViewController创建SecondViewController时,它可以设置委托属性或使用出口连接它们。

注意:代理属性不应该是retain,它们应该是assign(或带ARC的weak)。

+0

感谢您的保留提示!当你说FirstViewController创建SecondViewController时,我不确定你的意思 - 它们都存在于单独的容器视图中。 – nanothread59

+0

那么,创建SecondViewController的人应该设置它的委托属性。取决于你的程序的结构。你的代码显示SecondsViewController正在创建FirstViewController,这没有意义。 – progrmr