ReactiveCocoa - 具有一般错误处理的信号生成器序列

时间:2017-06-05 10:30:14

标签: swift swift3 reactive-programming reactive-cocoa reactive-swift

我对使用Swift 3的ReactiveCocoa(v5)有疑问。在我的项目中,我有不同的服务。例如api或用于保存或从磁盘获取内容。那些服务正在返回SignalProducer。我现在有类似于一系列调用彼此依赖的不同服务。这里的顺序是:

  1. 致电服务获取密钥
  2. 使用密钥
  3. 调用服务api
  4. 从api获取数据(返回多个模型)
  5. 使用first-model-service保存第一个模型
  6. 使用第二模型服务保存第二个模型
  7. 在我的序列中,我还必须将第二次服务调用中的数据传递给模型保存。

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/activity_post"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/white"
        android:orientation="vertical">
    
        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:fillViewport="true"> 
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical"
                tools:ignore="NestedWeights">
    
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="0dp"
                    android:layout_weight="0.05"
                    android:orientation="horizontal"
                    tools:ignore="NestedWeights">
    
                    <TextView
                        android:id="@+id/etSearch"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_gravity="center"
                        android:layout_weight="0.9"
                        android:background="@drawable/bg"
                        android:gravity="center"
                        android:maxLines="1"
                        android:padding="@dimen/value_3"
                        android:text="@string/search_text"
                        android:textColor="@color/black"
                        android:textSize="@dimen/font_14"
                        tools:ignore="NestedWeights" />
    
                    <FrameLayout
                        android:id="@+id/imgChat"
                        android:layout_width="0dp"
                        android:layout_height="@dimen/value_30"
                        android:layout_gravity="center"
                        android:layout_margin="@dimen/value_5"
                        android:layout_weight="0.1"
                        android:background="@drawable/tab_bg_selector"
                        tools:ignore="NestedWeights">
    
                        <TextView
                            android:id="@+id/msgCount"
                            android:layout_width="wrap_content"
                            android:layout_height="@dimen/value_20"
                            android:layout_gravity="center"
                            android:background="@drawable/round"
                            android:gravity="center"
                            android:textColor="@android:color/white"
                            android:textSize="@dimen/font_14" />
    
                        <ImageView
                            android:id="@+id/imgMsg"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:src="@drawable/chatt"
                            android:visibility="gone" />
                    </FrameLayout>
                </LinearLayout>
                <!--<LinearLayout />-->
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="0dp"
                    android:layout_weight="0.9"
                    android:orientation="vertical">
    
                    <android.support.v4.widget.SwipeRefreshLayout
                        android:id="@+id/swiperefresh"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content">
    
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="match_parent"
                            android:descendantFocusability="blocksDescendants"
                            android:orientation="vertical"
                            tools:ignore="NestedWeights">
    
                            <LinearLayout
                                android:layout_width="match_parent"
                                android:layout_height="match_parent"
                                android:background="@color/rv_color"
                                android:orientation="vertical">
    
                                <android.support.v7.widget.RecyclerView
                                    android:id="@+id/rvHairList"
                                    android:layout_width="match_parent"
                                    android:layout_height="wrap_content"
                                    android:layout_centerInParent="true"
                                    android:clipToPadding="false"
                                    tools:ignore="NestedWeights" />
                            </LinearLayout>
    
                            <ProgressBar
                                android:id="@+id/main_progress"
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:layout_gravity="center"
                                android:indeterminateTint="@color/user_name" />
    
                            <include layout="@layout/error_layout" />
                        </LinearLayout>
                    </android.support.v4.widget.SwipeRefreshLayout>
                </LinearLayout>
            </LinearLayout>
        </ScrollView>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:layout_gravity="bottom"
            android:background="@color/white"
            android:gravity="bottom"
            android:orientation="horizontal"
            android:padding="@dimen/value_5"
            tools:ignore="NestedWeights">
    
            <LinearLayout
                android:id="@+id/llDrawer"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:gravity="center">
    
                <ImageView
                    android:id="@+id/drawer"
                    android:layout_width="@dimen/value_30"
                    android:layout_height="@dimen/value_20"
                    android:layout_gravity="center"
                    android:layout_marginLeft="@dimen/value_5"
                    android:layout_marginRight="@dimen/value_5"
                    android:src="@drawable/more"
                    tools:ignore="NestedWeights" />
            </LinearLayout>
    
            <LinearLayout
                android:id="@+id/llHome"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:gravity="center">
    
                <ImageView
                    android:id="@+id/imgHome"
                    android:layout_width="@dimen/value_30"
                    android:layout_height="@dimen/value_20"
                    android:layout_gravity="center"
                    android:layout_marginLeft="@dimen/value_5"
                    android:layout_marginRight="@dimen/value_5"
                    android:src="@drawable/home"
                    tools:ignore="NestedWeights" />
            </LinearLayout>
    
            <FrameLayout
                android:id="@+id/imgFriendRequest"
                android:layout_width="@dimen/value_30"
                android:layout_height="@dimen/value_20"
                android:layout_gravity="center"
                android:layout_marginLeft="@dimen/value_5"
                android:layout_marginRight="@dimen/value_5"
                android:layout_weight="1"
                tools:ignore="NestedWeights">
    
                <TextView
                    android:id="@+id/friendCount"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:background="@drawable/round"
                    android:gravity="center"
                    android:textColor="@android:color/white"
                    android:textSize="@dimen/font_14" />
    
                <ImageView
                    android:id="@+id/imgFnd"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:src="@drawable/add_friend"
                    android:visibility="gone" />
            </FrameLayout>
    
            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:gravity="center"
                android:visibility="gone">
    
                <ImageView
                    android:id="@+id/gestureImg"
                    android:layout_width="@dimen/value_30"
                    android:layout_height="@dimen/value_20"
                    android:layout_gravity="center"
                    android:layout_marginLeft="@dimen/value_5"
                    android:layout_marginRight="@dimen/value_5"
                    android:src="@drawable/img_thing"
                    tools:ignore="NestedWeights" />
            </LinearLayout>
    
            <LinearLayout
                android:id="@+id/llNewPost"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:gravity="center">
    
                <ImageView
                    android:id="@+id/imgGallery"
                    android:layout_width="@dimen/value_30"
                    android:layout_height="@dimen/value_20"
                    android:layout_gravity="center"
                    android:layout_marginLeft="@dimen/value_5"
                    android:layout_marginRight="@dimen/value_5"
                    android:src="@drawable/gallery"
                    tools:ignore="NestedWeights" />
            </LinearLayout>
    
            <FrameLayout
                android:id="@+id/imgNotification"
                android:layout_width="@dimen/value_30"
                android:layout_height="@dimen/value_20"
                android:layout_gravity="center"
                android:layout_marginLeft="@dimen/value_5"
                android:layout_marginRight="@dimen/value_5"
                android:layout_weight="1"
                tools:ignore="NestedWeights">
    
                <TextView
                    android:id="@+id/notiCount"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:background="@drawable/round"
                    android:gravity="center"
                    android:textColor="@android:color/white"
                    android:textSize="@dimen/font_14" />
    
                <ImageView
                    android:id="@+id/imgNoti"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:src="@drawable/notification"
                    android:visibility="gone" />
            </FrameLayout>
    
            <LinearLayout
                android:id="@+id/llProfile"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:gravity="center">
    
                <de.hdodenhof.circleimageview.CircleImageView 
                    android:id="@+id/imgTimeline"
                    android:layout_width="@dimen/value_30"
                    android:layout_height="@dimen/value_20"
                    android:layout_gravity="center"
                    android:layout_marginLeft="@dimen/value_5"
                    android:layout_marginRight="@dimen/value_5"
                    android:layout_weight="1"
                    android:src="@drawable/loader"
                    app:civ_border_color="#FF000000"
                    tools:ignore="NestedWeights" />
            </LinearLayout>
        </LinearLayout>
    

    此外,如果序列中的keyService.get().flatMap(.latest) { (key) -> SignalProducer<[Data],Error> in return self.dataService.get()(key: key) } .flatMap(.latest) { (data) -> SignalProducer<Bool, Error> in return self.firstModelService.save(data["Model1"]) } .flatMap(.latest) { (data) -> SignalProducer<Bool, Error> in //how to get data here? return self.secondModelService.save(data["Model2"]) }.startWithFailed({ e in }) 之一发送错误,则完成序列将停止并且以错误作为参数调用回调。我不知道这里SignalProducer是否正确。

    有人有像我一样的情景,可以举个例子吗?我阅读了一些教程,但我无法弄清楚。

1 个答案:

答案 0 :(得分:0)

如果序列中的任何SignalProducer失败,则表示正确执行,并且执行将直接跳转到startWithFailed中的块。

如果keyService失败,我们就无法使用dataService,如果dataService失败,我们无法保存任何模型,因此这种行为对于这两个操作都有意义。

但是,modelService操作不依赖于彼此完成,因此应该在我们的信号模型中同时执行。要按顺序执行,您已经知道使用flatMap - 使用zipcombineLatest同时执行也很容易(请参阅documentation)。通过与zip / combineLatest同时执行模型服务操作,我们也可以在正确的范围内免费获得data

使用combineLatest,您的代码变为:

keyService.get().flatMap(.latest) { (key) -> SignalProducer<[Data],Error> in
  return self.dataService.get()(key: key)
}.flatMap(.latest) { (data) -> SignalProducer<(Bool, Bool), Error> in
  return SignalProducer.combineLatest(
    self.firstModelService.save(data["Model1"]),
    self.secondModelService.save(data["Model2"])
  )
}

您可以看到生成的信号生成器现在具有Value类型的(Bool, Bool),分别表示modelService1.savemodelService2.save的结果

回复:startWithFailed

启动信号生成器时,您选择启动它的函数将定义回调块中代码处理的事件。如果您使用SignalProducer启动startWithFailed,那么只有错误才会导致您的完成块被调用。

此类操作的最佳选择通常是startWithResult,它会将Result<Value, Error>传递到您的完成区,并在每个.value.failed事件中调用完成块。

但是,如果你想对成功的获取&amp;保存并且只需要处理错误,然后startWithFailed确实是正确的选择。