2014-02-02 1 views
1

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

Это то, что у меня есть, но не совсем понятно. У меня есть два контроллера вида, в первом случае у меня есть кнопка, которая при нажатии на нее в основном переходит к второму контроллеру представления и метке, которая показывает сообщение, отправленное со второго контроллера представления. Во втором контроллере представления у меня есть кнопка и текстовый фильтр, кнопка в основном отправляет все, что находится в текстовом поле, на метку в главном контроллере.

Вот код ...

// FirstVC.h

#import <UIKit/UIKit.h> 
#import "SecondVC.h" 
@interface FirstVC : UIViewController <passNames> 

@property (nonatomic, strong) NSString* firstNameString; 
@property (weak, nonatomic) IBOutlet UILabel *firstNameLabel; 

@end 

//FirstVC.m

#import "FirstVC.h" 

@implementation FirstVC 

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 
{ 
    if ([[segue identifier]isEqualToString:@"secondController"]) 
    { 
     UINavigationController *navController = segue.destinationViewController; 
     SecondVC *vc2 = (SecondVC*)navController.topViewController; 
     [vc2 setDelegate:self]; 
    } 
} 
-(void)viewWillAppear:(BOOL)animated 
{ 
    self.firstNameLabel.text = _firstNameString; 
} 

-(void)setFirstName:(NSString *)firstName 
{ 
    _firstNameString = firstName; 
} 
@end 

//SecondVC.h

#import <UIKit/UIKit.h> 

@protocol passNames <NSObject> 
-(void)setFirstName:(NSString*)firstName; 
@end 

@interface SecondVC : UIViewController 

@property (retain)id <passNames> delegate; 

- (IBAction)send:(UIBarButtonItem *)sender; 

@property (nonatomic, strong) NSString *firstNameString; 
@property (weak, nonatomic) IBOutlet UITextField *firstNameText; 
@end 

//SecondVC.m

#import "SecondVC.h" 
#import "FirstVC.h" 

@interface SecondVC() 

@end 

@implementation SecondVC 

- (IBAction)send:(UIBarButtonItem *)sender 
{ 
    _firstNameString = _firstNameText.text; 
    [[self delegate]setFirstName:_firstNameString]; 
    [self dismissViewControllerAnimated:YES completion:nil]; 
} 
@end 

Может кто-нибудь объяснить, как работает метод prepareForSegue в вышеуказанном коде? Причина этого вопроса заключается в том, что я добавил NSLog и похоже, что этот метод вызывается только при переходе от главного контроллера представления ко второму контроллеру. Почему нужен этот метод, если он не вызывается при переходе от контроллера второго представления к контроллеру главного представления, который в моем случае является тем, что я делаю? Имеет смысл использовать его при передаче данных с главного контроллера представления на второй контроллер, а не на случай, показанный выше.

Может ли кто-нибудь объяснить весь механизм при передаче данных обратно на главный контроллер?

FYI, я действительно разбираюсь в протоколах и делегировании.

Большое спасибо.

ответ

1

Ваша цель состоит в том, чтобы передать обратно данные, как это:

[[self delegate] setFirstName:_firstNameString]; 

Но вы не можете сделать это, если вы не знаете, кто отправить setFirstName: к, и компилятор не пусть вы делаете это, если не гарантируете, что тот, кто отправляет setFirstName:, может принять это сообщение.

Вот что готовится prepareForSegue.FirstVC заявила, что использует протокол passNames, что означает, что он реализует setFirstName:. А теперь вы говорите:

[vc2 setDelegate:self]; 

... где selfявляется экземпляр FirstVC. Это решает обе проблемы сразу. Экземпляр SecondVC (vc2) теперь имеет делегат (экземпляр FirstVC), он является правильным объектом для отправки информации обратно, и, потому что его делегат объявлен как принявший passNames, мы знаем, что SecondVC может фактически отправить setFirstName: этому делегировать.

Теперь к сердцу вашего актуальный вопрос: Причина для этого в prepareForSegue является лишь то, что это единственный момент, когда экземпляр FirstVC и экземпляр SecondVC «встретиться» один другой! Нет другого момента, когда экземпляр FirstVC имеет ссылку на экземпляр SecondVC, чтобы иметь возможность вызвать на нем setDelegate. Если вы не использовали перетекает и раскадровки, то FirstVC бы просто создать экземпляр SecondVC непосредственно - и установил бы себя в качестве делегата, так же, как вы делаете:

SecondVC *vc2 = [SecondVC new]; 
UINavigationController *nav = [ 
    [UINavigationController alloc] initWithRootViewController: vc2]; 
[vc2 setDelegate:self]; 
[self presentViewController: nav animated: YES completion: nil]; 

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

+1

И посмотреть обсуждение в моей книге: http://www.apeth.com/iOSBook/ch10.html#_protocols – matt

+0

На самом деле у меня есть копия вашей книги. Программирование iOS 5. Очень хорошая книга! Большое спасибо. –

+0

Объяснение этого момента (и многих других) в новой редакции (версия iOS 7), к сожалению, гораздо лучше объясняет ...! – matt

3

В вашем случае вы настраиваете свой метод делегата второго контроллера представления на себя в mainViewController в процессе подготовкиForSegue. Это означает, что помимо перехода на SecondViewController вы реализуете механизм обратного вызова в своем основном контроллере представления, так что ваш метод-делегат вызывается, когда значение передается со второго контроллера представления, и этот метод делегата собирает значение в качестве параметра для обрабатывайте его в главном контроллере просмотра. Возможно, вы установили делегат из VC2 как self inn yourForSegue, потому что вы создаете экземпляр VC2 в этом методе для перехода ко второму контроллеру.

Смежные вопросы

 Смежные вопросы