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