Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Наилучший мир с ReactiveCocoa

Anna | 2.07.2014 | нет комментариев

Большинство приложений тратят много времени на ожидание событий и их обработку. Они ждут взаимодействия пользователя с интерфейсом. Ждут результата на сетевой запрос. Ждут заключения асинхронных операций. Ожидают метаморфозы зависимого значения. И только потом они реагируют.

Все эти ожидания и реакции дозволено реализовать огромным числом методов. Нам становится сложно рассуждать о них, объединять и создавать в всякий высокоуровневой форме. Но мы можем сделать отменнее.

Именно следственно мы решили сделать общедоступной часть волшебства, стоящей за GitHub for Mac: ReactiveCocoa (RAC). RAC — это framework для компановки и реформирования последовательностей значений.

Что же это на самом деле?

Давайте конкретизируем. ReactiveCocoa предоставляет уйма увлекательных вероятностей:

  1. Вероятность составлять операции над грядущими данными.
  2. Метод уменшения числа состояний и мутабельности.
  3. Декларативный метод определения поведений и взаимосвязей между свойствами.
  4. Унифицированный, высокоуровневый интерфейс для асинхронных операций.
  5. Красивое API, основанное на KVO.

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

Настоящая красота RAC в том, что он может приспосабливаться к разным, Зачастую встречающимся обстановкам.

Хватит разговоров. Давайте посмотрим как это выглядит на самом деле.

Примеры

RAC, применяя KVO, может предоставлять последовательность значений из KVO-совместимых свойств. Скажем, мы можем следить за изменениями свойства username:

[RACObserve(self, username) subscribeNext:^(NSString *newName) {
    NSLog(@"%@", newName);
}];

Это резко, но это не больше чем отменное API над KVO. Подлинно увлекательные вещи происходят, когда мы объединяем последовательности для выражения трудного поведения.

Представим, мы хотим проверить ввел ли пользователь неповторимое имя, но только с первых 3 попыток:

[[[[RACObserve(self, username) 
    distinctUntilChanged] 
    take:3] 
    filter:^(NSString *newUsername) {
        return [newUsername isEqualToString:@"joshaber"];
    }] 
    subscribeNext:^(id _) {
        NSLog(@"Hi me!");
    }];

Мы отслеживаем за изменением username, отсеиваем несущественные метаморфозы, берем только первые три значения, а после этого, если новое значение равно joshaber, мы выводим специальное приветствие.

И что?

Подумайте о том, что нам пришлось бы сделать, Дабы исполнить это без RAC. А именно:

  • Применять KVO, Дабы добавить наблюдателя за username.
  • Добавить качество для запоминания последнего значения, полученного с поддержкой KVO, вследствие чему мы сумеем игнорировать несущественные метаморфозы.
  • Добавить качество для подсчета числа полученных уникальных значений.
  • Увеличивать это качество всякий раз, когда мы получаем неповторимое значение.
  • И наконец перейти к сопоставлению.

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

Что еще?

Мы можем комбинировать последовательности:

[[RACSignal 
    combineLatest:@[RACObserve(self, password), RACObserve(self, passwordConfirmation)] 
    reduce:^id(NSString *currentPassword, NSString *currentConfirmPassword) {
        return [NSNumber numberWithBool:[currentConfirmPassword isEqualToString:currentPassword]];
    }] 
    subscribeNext:^(NSNumber *passwordsMatch) {
        self.createEnabled = [passwordsMatch boolValue];
    }];

Всякий раз, когда свойства password либо passwordConfirmation меняются, мы объеденяем два ихпоследних значения и приводим их к BOOL, Дабы проверить совпадают ли они. После этого мы активируем либо деактивируем кнопку create, применяя полученный итог.

Связи

Мы можем использовать RAC для приобретения сильных связей с условиями и трансформациями:

RAC(self, helpLabel.text) = [[RACObserve(self, help) 
        filter:^(NSString *newHelp) {
            return newHelp != nil;
        }] 
        map:^(NSString *newHelp) {
            return [newHelp uppercaseString];
        }];

Это объединяет текст нашего help label’a к help свойству, если help качество не nil, и позже этого переводит строку в верхний регистр (потому что пользователям нравится, когда на них ОРУТ).

Асинхронность

RAC также достаточно отлично согласуется с асинхронными операциями.

Скажем, мы можем вызвать блок, как только несколько параллельных операций будут исполнены:

[[RACSignal 
    merge:@[ [client fetchUserRepos], [client fetchOrgRepos] ]] 
    subscribeCompleted:^{
        NSLog(@"They're both done!");
    }];

Либо связать асинхронные операции:

[[[[client 
    loginUser] 
    flattenMap:^(id _) {
        return [client loadCachedMessages];
    }]
    flattenMap:^(id _) {
        return [client fetchMessages];
    }]
    subscribeCompleted:^{
        NSLog(@"Fetched all messages.");
    }];

Это авторизирует нас, получает кешированные сообщения, загружает сообщения с сервера и позже выведет “Fetched all messages.”.

Мы так же довольно легко можем перенести работу в фоновую очередь:

[[[[[client 
    fetchUserWithUsername:@"joshaber"] 
    deliverOn:[RACScheduler scheduler]]
    map:^(User *user) {
        // this is on a background queue
        return [[NSImage alloc] initWithContentsOfURL:user.avatarURL];
    }]
    deliverOn:RACScheduler.mainThreadScheduler]
    subscribeNext:^(NSImage *image) {
        // now we're back on the main queue
        self.imageView.image = image;
    }];

Либо совладать с потенциальным условиями перехвата.

Скажем, мы можем обновить качество итогом всякого асинхронного вызова, но только если оно не было изменено до его заключения:

[[[self 
    loadDefaultMessageInBackground]
    takeUntil:[RACObserve(self.message) skip:1]]
    toProperty:@keypath(self.message) onObject:self];

Как это работает?

RAC достаточно примитивен. Он каждый состоит из сигналов.

Подписчики подписаны на сигналы. Сигналы отправляют своим подписчикам nexterror, и completed события. И если это каждого лишь сигналы, отправляющие события, ключевым вопросом становиться: когда же эти события отправляются?

Создание сигналов

Сигналы определяют свое поведение касательно того когда и в связи с чем отправлются события. Мы можем сделать свой личный сигнал, применяя [RACSignal createSignal:]:

RACSignal *helloWorld = [RACSignal createSignal:^(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@"Hello, "];
    [subscriber sendNext:@"world!"];
    [subscriber sendCompleted];
    return nil;
}];

Блок, что мы передаем в [RACSignal createSignal:], вызывается всякий раз, когда сигнал получает нового подписчика. Новейший подписчик подставляется в блок и, таким образом, мы можем отправлять ему события. В примере выше мы сотворили сигнал, тот, что отправляет “Hello, ”, потом “world!”, и позже этого завершается.

Вложенные сигналы

Мы также можем сделать иной сигнал, учрежденный на нашем helloWorld сигнале:

RACSignal *joiner = [RACSignal createSignal:^(id<RACSubscriber> subscriber) {
    NSMutableArray *strings = [NSMutableArray array];
    return [helloWorld subscribeNext:^(NSString *x) {
        [strings addObject:x];
    } error:^(NSError *error) {
        [subscriber sendError:error];
    } completed:^{
        [subscriber sendNext:[strings componentsJoinedByString:@""]];
        [subscriber sendCompleted];
    }];
}];

Сейчас у нас есть сигнал joiner. Когда кто-то подписывается на joiner, он механически подписывается на сигна

 

Источник: programmingmaster.ru

 

Оставить комментарий
БАЗА ЗНАНИЙ
СЛУЧАЙНАЯ СТАТЬЯ
СЛУЧАЙНЫЙ БЛОГ
СЛУЧАЙНЫЙ МОД
СЛУЧАЙНЫЙ СКИН
НОВЫЕ МОДЫ
НОВЫЕ СКИНЫ
НАКОПЛЕННЫЙ ОПЫТ
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB