Понимание делегации

Я пытаюсь понять делегирование. Я написал небольшой проект, чтобы попытаться решить эту проблему. Я также получил помощь от SO, я застрял в самой последней части этого. Мой проект прост. У нас есть контроллер основного вида, который имеет кнопку "Пуск". Эта кнопка запускает представление контейнера, которое подключено к 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

Итак, контейнерное представление имеет представление picker, делегатом которого он является, и это представление выбора имеет только массив из десяти цветов на выбор:

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

Вот изображение того, на что это похоже. Обратите внимание, что "выбранная" кнопка - это только предварительная кнопка, которую я помещаю туда, чтобы убедиться, что все правильно подключено, и что я могу выйти из выбранного цвета, используя кнопку в контейнере. Я хочу передать этот цвет родительскому контроллеру представления. Так что после того, как я отклонил контейнер с его видом сборщика, у меня есть данные о том, какой цвет был выбран. Я получил помощь от кого-то в SO, и он очень хорошо помог мне начать это. Единственное, что я не понял, это то, что происходит, когда я получаю данные в конце m-файла родительского файла:

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

Это новый вопрос, но я действительно нуждаюсь в нем. Как мне на самом деле получить доступ к данным в родительском. Я спросил в разделе комментариев, и ответ был (я изменяю класс, это было первоначально uicolor):

"Нет, вы получите данные внутри метода - (void) passValue:(NSString *) theValue; установите точку останова в этом методе, чтобы быть уверенным, что он работает, вы можете получить к нему доступ следующим образом: NSString *myReceivedColor = theValue;

Я пытался написать слово в слово "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

1 ответ

Решение

Похоже, ваш делегат ноль.

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

Вы создаете два экземпляра childVC (может быть, опечатка копирования / вставки?), Затем устанавливаете делегата на 'controller', но используете 'childView'. Просто измените свойство childView на ContainerViewController и установите self.childView.delegate = self.

(Кстати, это простая ошибка, так много раз, когда вы думаете "почему это не работает??", проверяйте, установлено ли свойство делегата)

РЕДАКТИРОВАТЬ

Свойство возвращаемого значения, которое вы регистрируете, равно nil b/c, вы никогда не устанавливали его. Вы должны реализовать метод делегата, т.е.

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

Также то, что я говорил о действии selectedCol, это то, где вы вызываете своего делегата - ваше действие "назад" не вызывает этот метод.

Другие вопросы по тегам