【问题标题】:Understanding delegation理解委派
【发布时间】:2016-04-30 20:03:33
【问题描述】:

我正在尝试理解委托。我写了一个小项目来尝试解决这个问题。我也得到了 S.O. 的帮助。我被困在它的最后一部分。我的项目很简单。我们有一个主视图控制器,它有一个“开始”按钮。此按钮触发一个与 ContainerViewController 挂钩的容器视图。我做了一个小动画让容器从侧面滑动。我有另一个按钮“返回”,它使容器视图随着相反的动画消失。注意,我复制了很多代码,其余的都是我学习中的,所以可能有不必要的行,欢迎评论。

ViewController.h

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

@interface ViewController : UIViewController <ContainerViewControllerDelegate>

- (IBAction)Start:(id)sender;
- (IBAction)back:(id)sender;

@end

这是m文件:

#import "ViewController.h"

@interface ViewController ()

@property UIViewController *childView;
@property NSString *myReceivedValue;
@property ContainerViewController *controller;
@property IBOutlet UILabel *myLabel;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.childView = [self.storyboard instantiateViewControllerWithIdentifier:@"childVC"];
   self.controller = [self.storyboard instantiateViewControllerWithIdentifier:@"childVC"];
    self.controller.delegate = self;

    self.childView = [self.childViewControllers lastObject];
    [self.childView.view removeFromSuperview];
    [self.childView removeFromParentViewController];
    self.childView.view.userInteractionEnabled = NO;

    }

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (IBAction)Start:(id)sender {

    self.childView.view.frame = CGRectMake(0, 84, 320, 210);

    [self.childView didMoveToParentViewController:self];

    CATransition *transition = [CATransition animation];
    transition.duration = 1;
    transition.type = kCATransitionPush;
    transition.subtype = kCATransitionFromLeft;
    [transition setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
    [self.childView.view.layer addAnimation:transition forKey:nil];

    [self.view addSubview:self.childView.view];
    self.childView.view.userInteractionEnabled = YES;

}

- (IBAction)back:(id)sender {

    [self.childView willMoveToParentViewController:nil];

    [UIView animateWithDuration:1
                          delay:0.0
         usingSpringWithDamping:1
          initialSpringVelocity:1
                        options:UIViewAnimationOptionCurveEaseIn
                     animations:^{

                         self.childView.view.frame = CGRectMake(-320, 84, 320, 210);

                     } completion:^(BOOL complete){

                         [self.childView removeFromParentViewController];
                     }];

}

- (void) passValue:(NSString *) theValue
{
  // here is where you receive the data
}
@end

好的,所以容器视图有一个pickerView,它是它的委托,这个pickerView只有一个十种颜色的数组可供选择:

容器视图的h文件:

#import <UIKit/UIKit.h>


@protocol ContainerViewControllerDelegate;

@interface ContainerViewController : UIViewController <UIPickerViewDelegate>

@property NSArray *colors;

@property (weak)id <ContainerViewControllerDelegate> delegate;

@property (weak, nonatomic) IBOutlet UIPickerView *myPickerView;

- (IBAction)chosenCol:(id)sender;

@end

@protocol ContainerViewControllerDelegate <NSObject>

- (void) passValue:(NSString *) theValue;

@end

容器视图的m文件:

#import "ContainerViewController.h"

@interface ContainerViewController ()

@property NSString *selValue;

@end

@implementation ContainerViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.colors = [[NSArray alloc] initWithObjects:@"blue", @"red", @"green", @"purple", @"black", @"white", @"orange", @"yellow", @"pink", @"violet", nil];

    }

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
    return 1;
}

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {

        return 10;
}

- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {

    return self.colors[row];

}

- (IBAction)chosenCol:(id)sender {

    [self.delegate passValue:[self.colors objectAtIndex:[self.myPickerView selectedRowInComponent:0]]];

}
@end

这是它的外观图片。请注意,“选择”按钮只是我放在那里的一个临时按钮,以确保一切正常,并且我可以使用容器中的按钮注销选择的颜色。我想要做的是能够将该颜色传递给父视图控制器。因此,在我使用它的选择器视图关闭容器后,我存储了选择什么颜色的数据。我从 S.O. 的某个人那里得到了帮助。他在帮助我开始这方面做得很好。我唯一不明白的是,当我收到数据时,在父级的 m 文件末尾会发生什么:

  - (void) passValue:(NSString *) theValue
    {
      // here is where you receive the data
    }

这是一个明显的菜鸟问题,但我确实需要把它说清楚。我如何实际访问父级中的数据。我在cmets部分问过,回复是(我在换班,原来是uicolor):

“不,您将在方法内收到数据 - (void) passValue:(NSString *) theValue; 在该方法中放置一个断点以确保它正常工作,您可以像这样访问它: NSString *myReceivedColor =价值;

我试着逐字逐句地写“NSString *myReceivedColor = theValue;”但“theValue”未被识别。

最终,我想要的是将数据传递回父级,这样当我点击“返回”按钮时,在父级中,“您选择”的标签会更新为所选颜色”。

我以前从未接触过代表团,所以我迷路了。一个慈善的灵魂能花时间用非常明显的术语来解释这最后一点吗?非常感谢

更新--------------------------------- --------------------------

所以,我正在查看的是,在“返回”按钮的方法末尾添加,

 - (IBAction)back:(id)sender {

        [self.childView willMoveToParentViewController:nil];

        [UIView animateWithDuration:1
                              delay:0.0
             usingSpringWithDamping:1
              initialSpringVelocity:1
                            options:UIViewAnimationOptionCurveEaseIn
                         animations:^{

                             self.childView.view.frame = CGRectMake(-320, 84, 320, 210);

                         } completion:^(BOOL complete){

                             [self.childView removeFromParentViewController];
                         }];

几行:

        self.myReceivedValue = theValue;

        self.myLabel.text = self.myReceivedValue;
}

为了能够将 myLabel 的文本更新为我在视图容器中选择的颜色。它返回错误:“使用未声明的标识符“theValue”。这对我来说是全新的,所以我只是复制人们在 SO 上所说的话,希望最终能理解。我在这里做错了什么?tx

【问题讨论】:

  • 我怀疑您输入错误或位置错误。你能用NSString *myReceivedColor = theValue; 行更新你的问题吗?
  • 试着把它放在你当前拥有的地方“//这里是你接收数据的地方”。
  • 好的,我试过了。当我复制以下行时:“self.myReceivedValue = theValue;”到“//这里是您接收数据的地方”注释所在的位置,换句话说,在委托方法内部(对吗?)错误消失了。但是标签没有更新。我已添加该行; "NSLog(@"我收到的值是:%@", self.myReceivedValue);"在“返回”按钮的方法结束时,日志是:我收到的值是:(null)。
  • 是时候试试调试器了,我想。在chosenCol 中的self.delegate passValue... 行上设置断点。看看此时的委托值是多少。然后,假设没问题,进入委托方法并查看正在传递的变量。 (我不确定你为什么期望back 会发生事情。)

标签: objective-c delegation childviewcontroller parentviewcontroller


【解决方案1】:

看起来你的代表是零。

self.childView = [self.storyboard instantiateViewControllerWithIdentifier:@"childVC"];
self.controller = [self.storyboard instantiateViewControllerWithIdentifier:@"childVC"];
self.controller.delegate = self;

您创建了两个“childVC”实例(可能是复制/粘贴错字?)然后将委托设置为“控制器”,但您使用“childView”。只需将 childView 属性更改为 ContainerViewController 并设置 self.childView.delegate=self。

(顺便说一句,这是一个简单的错误,很多时候当你在想“为什么这不起作用??”检查委托属性是否已设置)

编辑

您记录的返回值属性是 nil b/c 您从未设置它。您必须实现委托方法,即

-(void) passValue:(nsstring*)theValue
{
self.receivedValue = theValue
}

关于 selectedCol 操作,我所说的也是您调用委托的地方 - 您的“返回”操作不会调用此方法。

【讨论】:

  • 另外,请记住您在这里调用 ContainerViewController 中的委托:- (IBAction)chosenCol:(id)sender { [self.delegate passValue:[self.colors objectAtIndex:[self. myPickerView selectedRowInComponent:0]]]; } 不在后退按钮操作中
  • 嗨,我已经这样做了:self.childView = [self.storyboard instantiateViewControllerWithIdentifier:@"childVC"]; self.childView.delegate = 自我;但返回仍然为空。太令人沮丧了!!感谢您的意见!
  • selectedCol 按钮只是临时的。由于事情不起作用,我把它放在那里以确保我的问题与选择器视图无关。一旦我让代表团开始工作,我将删除 selectedCol 按钮。
猜你喜欢
  • 1970-01-01
  • 2015-05-10
  • 2010-12-14
  • 2010-11-03
  • 1970-01-01
  • 1970-01-01
  • 2013-01-11
  • 2013-12-05
  • 1970-01-01
相关资源
最近更新 更多