Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ФРП в iOS-разработке

Avatar for Sahey Sahey
December 02, 2017

ФРП в iOS-разработке

Знакомство с основами функционального реактивного программирования на примере использования фреймворка ReactiveCocoa.

Avatar for Sahey

Sahey

December 02, 2017
Tweet

Other Decks in Programming

Transcript

  1. Функциональное программирование • У функций нет побочных эффектов (side effects)

    • Нет изменяемого состояния • Результат зависит только от входных параметров f(x,y) = x + y
  2. map let array = [1,2,3,4,5] var doubleArray:[Int] = [] for

    number in array { doubleArray.append(number * 2) } print(doubleArray) //[2, 4, 6, 8, 10] let map = array.map{$0 * 2} print(map) //[2, 4, 6, 8, 10] //swift syntax + map array.map { (i : Int) -> Int in return i * 2 } array.map ({ i in return i * 2}) array.map ({ i in i * 2 }) array.map ({ $0 * 2 }) array.map { $0 * 2 }
  3. filter let array = [1,2,3,4,5] print(array) //[1, 2, 3, 4,

    5] let filtered = array.filter { $0 % 2 == 0} print(filtered) //[2, 4] reduce let reduce = [1,2,3,4,5].reduce(0, {$0 + $1}) print(reduce) //15 flatMap let flatMap = [[1,2,4,5],[6,7,8,9]].flatMap{($0)} print(flatMap) //[1, 2, 4, 5, 6, 7, 8, 9]
  4. chaining let chaining = [1,2,3,4,5].filter{$0 % 2 == 1}.reduce(0, {$0

    + $1}) print(chaining) //9 пример let classes = [ ["Вася", "Петя"], ["Маша", "Аня"], ["Катя", "Толя"] ] print ("В школе классов: \(classes.count)") //В школе классов: 3 let school = classes.flatMap {$0}.joined(separator: ", ") print ("В школе учатся: \(school)") //В школе учатся: Вася, Петя, Маша, Аня, Катя, Толя
  5. Реактивное программирование • Потоки данных • Распространение изменений imperative a

    = 2 b = 2 c = a + b b = 3 print(c) //4 reactive a = 2 b = 2 c = a + b b = 3 print(c) //5 c = a + b print(c) //5
  6. Зачем? • Что, а не как • Меньше кода, больше

    смысла • Программирование с асинхронными потоками
  7. Streams and Sequence RACStream - абстрактный класс, представляющий любой поток

    значений. RACSequence - один из типов стрима, своего рода коллекция. Является pull-driven стримом. NSArray *array = @[@1, @2, @3, @4, @5]; RACSequence *stream = [array rac_sequence]; NSArray *map = [stream map:^NSNumber *(id value) { return @([value integerValue] * 2); }].array;
  8. Signal RACSignal - базовый компонент, представляет собой поток событий, которые

    будут доставлены в будущем. Является push-driven потоком. • нажатия на кнопку • асинхронные сетевые операции • другие UI события
  9. Subscriptions <UITextFieldDelegate> self.textField.delegate = self; - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:

    (NSString *)string { if (self.textField == textField) { NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string]; NSLog(@“новое значение: %@“,newString); return YES; } //много другого кода для других “текстфилдов” } [self.textField.rac_textSignal subscribeNext:^(NSString *x) { NSLog(@“новое значение: %@",x); }];
  10. Deriving State RAC(button, hidden) = [textField.rac_textSignal map:^id(NSString *value) { return

    @(value.length == 0); }]; RACSignal *nonEmptyTextSignal = [textField.rac_textSignal map:^id(NSString *value) { return @(value.length == 0); }]; RAC(button, hidden) = nonEmptyTextSignal; RAC(self.view, backgroundColor) = [nonEmptyTextSignal map:^id(id value) { if ([value boolValue]) { return [UIColor greenColor]; } else { return [UIColor redColor]; } }];
  11. user input stream Ц ЦЕ ЦЕН throttle(200ms) throttled stream ЦЕ

    ЦЕН filter(length > 2) ЦЕН query stream request stream response stream flatMap( )
  12. RAC(viewModel, addressQuery) = [[textSignal throttle:0.2] filter:^BOOL(NSString *value) { return value.length

    > 2; }]; self.autoCompleteCommand = [[RACCommand alloc] initWithEnabled:autoCompleteLoadingSignal signalBlock:^RACSignal *(id input) { //API }]; @weakify(self); [RACObserve(self, addressQuery) subscribeNext:^(id query) { @strongify(self); [self.autoCompleteCommand execute:query]; }]; RAC(self, autoCompletePlaces) = [self.autoCompleteCommand.executionSignals flattenMap:^RACSignal *(RACSignal *value) { return [value filter:^BOOL(id value) { return [value isKindOfClass: [NSArray class]]; }]; }];
  13. RAC(self, cancelButton.hidden) = [textSignal map:^id(NSString *value) { return @(value.length ==

    0); }]; RAC(self, iconView.alpha) = [textSignal map:^id(NSString *value) { return value.length ? @(1) : @(0.2f); }]; @weakify(self); [autoCompleteSignal subscribeNext:^(NSNumber *loading) { @strongify(self); if (loading.boolValue) { [self.indicatorView startAnimating]; } else { [self.indicatorView stopAnimating]; } }];