Этот вопрос, кажется, очень популярен здесь, на stackoverflow, поэтому я подумал, что постараюсь дать лучший ответ, чтобы помочь людям, начинающим в мире iOS, как я.
Я надеюсь, что этот ответ достаточно ясен для понимания людьми, и я ничего не пропустил.
Передача данных вперед
Передача данных в контроллер представления из другого контроллера представления. Вы бы использовали этот метод, если хотите передать объект / значение из одного контроллера представления в другой контроллер представления, который вы, возможно, помещаете в стек навигации.
Для этого примера у нас будет ViewControllerA
и ViewControllerB
Чтобы передать значение BOOL
из ViewControllerA
в ViewControllerB
, мы сделаем следующее.
в ViewControllerB.h
создайте свойство для BOOL
@property (nonatomic, assign) BOOL isSomethingEnabled;
в ViewControllerA
, вам нужно рассказать ему о ViewControllerB
так используйте
#import "ViewControllerB.h"
Тогда, где вы хотите загрузить вид, например. didSelectRowAtIndex
или еще что-нибудь IBAction
, вам нужно установить свойство в ViewControllerB
, прежде чем помещать его в стек навигации.
ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
viewControllerB.isSomethingEnabled = YES;
[self pushViewController:viewControllerB animated:YES];
Это установит isSomethingEnabled
в ViewControllerB
в BOOL
значение YES
.
Передача данных с использованием сегментов
Если вы используете раскадровки, вы, скорее всего, используете сегменты и вам понадобится эта процедура для передачи данных. Это похоже на приведенное выше, но вместо передачи данных перед тем, как нажать контроллер представления, вы используете метод, называемый
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
. Таким образом, чтобы передать BOOL
из ViewControllerA
в ViewControllerB
, мы бы сделайте следующее:
в ViewControllerB.h
создайте свойство для BOOL
@property (nonatomic, assign) BOOL isSomethingEnabled;
в ViewControllerA
, которое вам нужно расскажите о ViewControllerB
, поэтому используйте
#import "ViewControllerB.h"
Создайте переход от ViewControllerA
до ViewControllerB
на раскадровке и дайте ему идентификатор, в этом примере мы Я назову его "showDetailSegue"
Далее нам нужно добавить метод к ViewControllerA
, который вызывается при выполнении любого перехода, из-за этого нам нужно определить, какой вызов был вызван а затем сделай что-нибудь В нашем примере мы проверим "showDetailSegue"
, и если это будет выполнено, мы передадим наше значение BOOL
в ViewControllerB
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:@"showDetailSegue"]){
ViewControllerB *controller = (ViewControllerB *)segue.destinationViewController;
controller.isSomethingEnabled = YES;
}
}
. Если ваши представления встроены в контроллер навигации, вам нужно изменить метод выше слегка к следующему
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:@"showDetailSegue"]){
UINavigationController *navController = (UINavigationController *)segue.destinationViewController;
ViewControllerB *controller = (ViewControllerB *)navController.topViewController;
controller.isSomethingEnabled = YES;
}
}
Это установит isSomethingEnabled
в ViewControllerB
значение BOOL
YES
.
Передача данных назад
Для передачи данных из ViewControllerB
в ViewControllerA
необходимо использовать Протоколы и делегаты или Блоки , последний может быть использован как слабосвязанный механизм для обратных вызовов.
Для этого мы сделаем ViewControllerA
делегатом ViewControllerB
. Это позволяет ViewControllerB
отправлять сообщение обратно ViewControllerA
, что позволяет нам отправлять данные обратно.
Чтобы ViewControllerA
был делегатом ViewControllerB
, он должен соответствовать протоколу ViewControllerB
, который мы должны указать. Это сообщает ViewControllerA
, какие методы он должен реализовать.
В ViewControllerB.h
ниже #import
, но выше @interface
вы указываете протокол.
@class ViewControllerB;
@protocol ViewControllerBDelegate
- (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item;
@end
затем еще в ViewControllerB.h
вам нужно установить свойство delegate
и синтезировать в ViewControllerB.m
@property (nonatomic, weak) id delegate;
В ViewControllerB
мы вызываем сообщение на delegate
, когда открываем контроллер представления.
NSString *itemToPassBack = @"Pass this value back to ViewControllerA";
[self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];
Вот и все для ViewControllerB
. Теперь в ViewControllerA.h
, скажите ViewControllerA
импортировать ViewControllerB
и соответствовать его протоколу.
#import "ViewControllerB.h"
@interface ViewControllerA : UIViewController
В ViewControllerA.m
реализовать следующий метод из нашего протокола
- (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item
{
NSLog(@"This was returned from ViewControllerB %@",item);
}
Перед тем как отправить viewControllerB
в стек навигации, нам нужно сообщить ViewControllerB
, что ViewControllerA
является его делегатом, в противном случае мы получим ошибку.
ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
viewControllerB.delegate = self
[[self navigationController] pushViewController:viewControllerB animated:YES];
Центр уведомлений NSN Это еще один способ передачи данных.
// add observer in controller(s) where you want to receive data
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDeepLinking:) name:@"handleDeepLinking" object:nil];
-(void) handleDeepLinking:(NSNotification *) notification {
id someObject = notification.object // some custom object that was passed with notification fire.
}
// post notification
id someObject;
[NSNotificationCenter.defaultCenter postNotificationName:@"handleDeepLinking" object:someObject];
Передача данных обратно из одного класса в другой (классом может быть любой контроллер, менеджер сети / сеанса, подкласс UIView или любой другой класс)
Блоки являются анонимными функциями.
Этот пример передает данные от Контроллера B к Контроллеру A
определяют блок
@property void(^selectedVoucherBlock)(NSString *); // in ContollerA.h
добавить обработчик блока (слушатель) , где вам нужно значение (например, вам нужен ваш ответ API в ControllerA или вам нужны данные ContorllerB на A)
// in ContollerA.m
- (void)viewDidLoad {
[super viewDidLoad];
__unsafe_unretained typeof(self) weakSelf = self;
self.selectedVoucherBlock = ^(NSString *voucher) {
weakSelf->someLabel.text = voucher;
};
}
Перейти к контроллеру B
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
ControllerB *vc = [storyboard instantiateViewControllerWithIdentifier:@"ControllerB"];
vc.sourceVC = self;
[self.navigationController pushViewController:vc animated:NO];
пожарный блок
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:
(NSIndexPath *)indexPath {
NSString *voucher = vouchersArray[indexPath.row];
if (sourceVC.selectVoucherBlock) {
sourceVC.selectVoucherBlock(voucher);
}
[self.navigationController popToViewController:sourceVC animated:YES];
}
if( val == 'bar' ) {
throw $break;
}
It's documented at the same page you linked. It's an exception specially handled by the each function. When thrown, it prevents your function from being called on further elements.
Неправильный путь с той страницы, на которую вы перешли
if(val == 'bar')
{
throw $break;
}
?
Вы правы, и Prototype создал объект ( $ break ), который можно выбросить из каждой функции, чтобы включить эту функциональность. Согласно документации Prototype API:
Регулярные циклы могут быть сокращены в JavaScript с помощью операторов break и continue. Однако при использовании функций итератора ваш код выходит за рамки цикла: код цикла происходит за сценой.
Чтобы предоставить вам эквивалентную (хотя и менее оптимальную) функциональность, Prototype предоставляет два глобальных объекта исключения, $ break и $ продолжить. Их использование эквивалентно использованию соответствующего собственного оператора в ванильном цикле. Эти исключения должным образом перехватываются внутри каждого метода.
Также обратите внимание, что объект $ continue устарел,
верны, и Prototype создал объект ( $ break ), который можно выбросить из функции each, чтобы включить эту функциональность. Согласно документации Prototype API:
Обычные циклы могут быть сокращены в JavaScript с помощью операторов break и continue. Однако при использовании функций итератора ваш код выходит за рамки цикла: код цикла происходит за сценой.
Чтобы предоставить вам эквивалентную (хотя и менее оптимальную) функциональность, Prototype предоставляет два глобальных объекта исключения, $ break и $ продолжить. Их использование эквивалентно использованию соответствующего собственного оператора в ванильном цикле. Эти исключения должным образом перехватываются внутри каждого метода.
Также обратите внимание, что объект $ continue устарел, и для имитации оператора continue используйте вместо него обычный оператор return.
Пример кода:
var result = [];
$R(1,10).each(function(n) {
if (0 == n % 2)
return; // this equals continue
if (n > 6)
throw $break;
result.push(n);
});
// result -> [1, 3, 5]
Подробнее о каждой функции можно прочитать здесь: http: //www.prototypejs. org / api / enumerable / each