2015-05-14 2 views
10

Я читал в ReactiveCocoa v3 в последнее время, и я изо всех сил пытаюсь создать базовые вещи. Я уже прочитал журнал изменений, тесты, несколько вопросов SO и статьи Колина Эберхардта по этому вопросу. Тем не менее, я все еще не вижу примеров базовых привязок.Как сделать базовые привязки в ReactiveCocoa 3 и 4

Предположим, у меня есть приложение, в котором представлено меню дня. Приложение использует RAC3 и шаблон MVVM.

Модель (Меню)

Модель имеет один простой метод для извлечения меню сегодняшних. На данный момент это не делает каких-либо сетевых запросов, это в основном просто создает объект модели. Недвижимость mainCourse - String.

class func fetchTodaysMenu() -> SignalProducer<Menu, NoError> { 
    return SignalProducer { 
     sink, dispoable in 
      let newMenu = Menu() 
      newMenu.mainCourse = "Some meat" 
      sendNext(sink, newMenu) 
      sendCompleted(sink) 
    } 
} 

ViewModel (MenuViewModel)

Модель вид раскрывает различные переменные для String позволяя контроллер представления показать меню. Давайте просто добавим одно свойство для показа основного курса.

var mainCourse = MutableProperty("") 

И мы добавим привязки для этого свойства:

self.mainCourse <~ Menu.fetchTodaysMenu() 
    |> map { menu in 
     return menu.mainCourse! 
    } 

ViewController (MenuViewController)

И последнее, но не в последнюю очередь, я хочу представить это основное блюдо в представлении. Я добавлю для этого UILabel.

var headline = UILabel() 

И, наконец, я хочу, чтобы установить text свойство этого UILabel путем наблюдения с моей точки зрения модели. Что-то как:

self.headline.text <~ viewModel.headline.producer 

Который, к сожалению, не работает.

Вопросы

  1. Метод fetchTodaysMenu() возвращает SignalProducer<Menu, NoError>, но что, если я хочу, чтобы этот метод возвращает SignalProducer<Menu, NSError> вместо? Это сделало бы мою привязку в моей модели представления неудачной, поскольку метод теперь может вернуть ошибку. Как я могу справиться с этим?
  2. Как уже упоминалось, текущая привязка в моем контроллере просмотра не работает. Я играл с созданием MutableProperty, который представляет собой свойство UILabel, но я так и не понял. Я также считаю, что неудобно или многословно создавать дополнительные переменные для каждого свойства, которое я хочу связать. Это не было необходимо в RAC2. Я намеренно также пытался избежать использования DynamicProperty, но, может быть, я не должен? Я просто хочу найти правильный способ сделать RAC(self.headline, text) = RACObserve(self.viewModel, mainCourse);.

Любые другие отзывы/рекомендации о том, как сделать эту базовую установку, высоко оценены.

+5

Возможно, вам будет интересно прочитать эту статью: http://nomothetis.svbtle.com/an-introduction-to-reactivecocoa – mustafa

+0

Действительно я. Спасибо @mustafa! –

ответ

13

Итак, после написания этого вопроса, Колин Эберхардт сделал часть 3 своей серии блога RAC3, в которой содержится интересный и очень важный пример использования MVVM и RAC3. Сообщение можно найти here и исходный код here.

Основываясь на своей работе, я сумел ответить на мои собственные вопросы:

  1. Принимая несколько иной подход, я могу сделать fetchTodaysMenu() возвращающие SignalProducer<Menu, NSError>, как хотелось. Вот как я тогда бы в моей модели представления:

    MenuService.fetchTodaysMenu() 
        |> observeOn(QueueScheduler.mainQueueScheduler) 
        |> start(next: { response in 
         self.mainCourse.put(response.mainCourse!) 
        }, error: { 
         println("Error \($0)") 
        }) 
    
  2. Похоже, нет никаких UIKit привязок еще от RAC3 беты 4. Колин сделал несколько UIKit расширения себя, чтобы помочь ему сделать эти привязки я искал также. Они могут быть найдены here. Добавление их в мой проект, сделанный быть в состоянии делать то, что я хотел:

    self.mainCourse.rac_text <~ self.viewModel.mainCourse 
    

Update 25 мая 2015

После работал намного больше с ReactiveCocoa 3, я бы как ответить 1) еще раз. Используя catch, это можно сделать более декларативным образом. Я в конечном итоге реализация небольшой вспомогательной функции для этого:

public func ignoreError<T: Any, E: ErrorType>(signalProducer: SignalProducer<T, E>) -> SignalProducer<T, NoError> { 
    return signalProducer 
     |> catch { _ in 
      SignalProducer<T, NoError>.empty 
     } 
} 

Функция преобразует любой NSError в NoError делает возможным связать, как я хотел, делая MenuService.fetchTodaysMenu() |> ignoreError.

Я открытый исходный код моего проекта, как это могло бы быть хорошей отправной точкой для других перспективной в ReactiveCocoa 3,0: https://github.com/s0mmer/TodaysReactiveMenu

Update 5 марта 2016

Как было отмечено в комментариях, так как Swift 2 функция ignoreError теперь будет выглядеть так:

public func ignoreError() -> SignalProducer<Value, NoError> { 
    return flatMapError { _ in 
     SignalProducer<Value, NoError>.empty 
    } 
} 

Кроме того, библиотека расширения называетсяТакже был составлен, где добавлено нечто подобное.

+2

С Swift 2 вам нужно использовать 'flatMapError' вместо' catch', чтобы избежать конфликта с 'catch' Swift 2. – user2067021

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