Понимание делегирования

Я пытаюсь понять делегирование. Я написал небольшой проект, чтобы попытаться решить эту проблему. Мне также помогал С.О. Я застрял на самой последней его части. Мой проект простой. У нас есть контроллер основного вида с кнопкой «Пуск». Эта кнопка запускает представление контейнера, привязанное к ContainerViewController. Я сделал небольшую анимацию, чтобы контейнер скользил сбоку. У меня есть еще одна кнопка «назад», которая заставляет представление контейнера исчезать с противоположной анимацией. Обратите внимание, я копирую много кода и дорабатываю остальное по мере обучения, поэтому могут быть ненужные строки, пожалуйста, не стесняйтесь комментировать.

ViewController.h

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

@interface ViewController : UIViewController <ContainerViewControllerDelegate>

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

@end

Вот м файл:

#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

Итак, у Container View есть 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
    }

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

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

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


person Paul    schedule 24.01.2016    source источник
comment
Я подозреваю, что вы либо что-то печатаете не так, либо не в том месте. Можете ли вы обновить свой вопрос, указав строку NSString *myReceivedColor = theValue;, которая дает вам ошибку?   -  person Phillip Mills    schedule 24.01.2016
comment
Попробуйте поместить его туда, где у вас сейчас есть // вместо этого вы получаете данные.   -  person Phillip Mills    schedule 24.01.2016
comment
Хорошо, я пробовал это делать. Когда я копирую строку: self.myReceivedValue = theValue; туда, где // здесь вы получаете комментарий к данным, другими словами, внутри метода делегата (правильно?) ошибка исчезает. Но метка не обновляется. Я добавил строку; NSLog(@мое полученное значение: %@, self.myReceivedValue); в конце метода для кнопки «Назад» и журнала: мое полученное значение: (ноль).   -  person Paul    schedule 24.01.2016
comment
Думаю, пришло время попробовать отладчик. Установите точку останова на строке self.delegate passValue... в chosenCol. Посмотрите, каково значение делегата в этот момент. Затем, если все в порядке, войдите в метод делегата и посмотрите на передаваемую переменную. (Я не уверен, почему вы ожидаете, что что-то произойдет в back.)   -  person Phillip Mills    schedule 24.01.2016


Ответы (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.

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

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

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

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

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

person BoombaleOsby    schedule 24.01.2016
comment
Кроме того, имейте в виду, что вы вызываете делегата в ContainerViewController здесь: - (IBAction)chosenCol:(id)sender { [self.delegate passValue:[self.colors objectAtIndex:[self.myPickerView selectedRowInComponent:0]]]; } Не в действии кнопки "Назад" - person BoombaleOsby; 24.01.2016
comment
Привет, я сделал это: self.childView = [self.storyboard instanceiateViewControllerWithIdentifier:@childVC]; self.childView.delegate = сам; но возврат по-прежнему равен нулю. Так расстраивает!! Спасибо за вклад! - person Paul; 24.01.2016
comment
кнопка selectedCol является временной. Поскольку что-то не работало, я поместил его туда, чтобы убедиться, что моя проблема не связана с представлением выбора. Как только делегирование заработает, я удалю кнопку selectedCol. - person Paul; 24.01.2016