Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/114.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 合并:如何在不完成原始发布服务器的情况下替换/捕获错误?_Ios_Swift_Combine - Fatal编程技术网

Ios 合并:如何在不完成原始发布服务器的情况下替换/捕获错误?

Ios 合并:如何在不完成原始发布服务器的情况下替换/捕获错误?,ios,swift,combine,Ios,Swift,Combine,给定以下代码: enum MyError: Error { case someError } myButton.publisher(for: .touchUpInside).tryMap({ _ in if Bool.random() { throw MyError.someError } else { return "we're in the else case"

给定以下代码:

    enum MyError: Error {
        case someError
    }

    myButton.publisher(for: .touchUpInside).tryMap({ _ in
        if Bool.random() {
            throw MyError.someError
        } else {
            return "we're in the else case"
        }
    })
        .replaceError(with: "replaced Error")
        .sink(receiveCompletion: { (completed) in
            print(completed)
        }, receiveValue: { (sadf) in
            print(sadf)
        }).store(in: &cancellables)
每当我点击按钮时,我都会得到
我们处于else情况下
,直到
Bool.random()
为真-现在抛出一个错误。我尝试了不同的方法,但我无法捕获/替换/忽略错误并在点击按钮后继续

在代码示例中,我希望有以下输出

we're in the else case
we're in the else case
replaced Error
we're in the else case
...
相反,我在
替换错误之后得到
完成
,并且没有发出任何事件

编辑
给定一个拥有
AnyPublisher
的发布者,我如何在发生错误时将其转换为
AnyPublisher
而不完成,即忽略原始发布者发出的错误?

只需按以下方式插入flatMap,您就可以实现所需的功能

   self.myButton.publisher(for: \.touchUpInside).flatMap{
            (data: Bool) in
        return Just(data).tryMap({ _ -> String in
        if Bool.random() {
            throw MyError.someError
        } else {
            return "we're in the else case"
        }}).replaceError(with: "replaced Error")
    }.sink(receiveCompletion: { (completed) in
            print(completed)
        }, receiveValue: { (sadf) in
            print(sadf)
       }).store(in: &cancellables)
工作模式如下所示:

 Just(parameter).
 flatMap{ (value)->AnyPublisher<String, Never> in 
 return MyPublisher(value).catch { <String, Never>() } 
 }.sink(....)
let firstPublisher    = {(value: Int) -> AnyPublisher<String, Error> in
           Just(value).tryMap({ _ -> String in
           if Bool.random() {
               throw MyError.someError
           } else {
               return "we're in the else case"
            }}).eraseToAnyPublisher()
    }

    Just(1).flatMap{ (value: Int) in
        return  firstPublisher(value).replaceError(with: "replaced Error")
   }.sink(receiveCompletion: { (completed) in
            print(completed)
        }, receiveValue: { (sadf) in
            print(sadf)
       }).store(in: &cancellables)
Just(参数)。
flatMap{(值)->中的任意发布者
返回MyPublisher(value).catch{()}
}.水槽(……)
如果我们使用上述示例,它可能是这样的:

 Just(parameter).
 flatMap{ (value)->AnyPublisher<String, Never> in 
 return MyPublisher(value).catch { <String, Never>() } 
 }.sink(....)
let firstPublisher    = {(value: Int) -> AnyPublisher<String, Error> in
           Just(value).tryMap({ _ -> String in
           if Bool.random() {
               throw MyError.someError
           } else {
               return "we're in the else case"
            }}).eraseToAnyPublisher()
    }

    Just(1).flatMap{ (value: Int) in
        return  firstPublisher(value).replaceError(with: "replaced Error")
   }.sink(receiveCompletion: { (completed) in
            print(completed)
        }, receiveValue: { (sadf) in
            print(sadf)
       }).store(in: &cancellables)
let firstPublisher={(值:Int)->AnyPublisher-in
Just(value).tryMap({u0->字符串输入)
if Bool.random(){
抛出我的错误
}否则{
return“我们在其他情况下”
}}).删除任何发布者()
}
仅(1).flatMap{(值:Int)在
返回firstPublisher(value).replaceError(带:“已替换错误”)
}.sink(receiveCompletion:{(completed)in
打印(已完成)
},receiveValue:{(sadf)在
打印(sadf)
}).store(在:&可取消项中)
在这里,您可以将
firstPublisher
替换为接受一个参数的任何publisher


在这里,firstPublisher只有一个值,它只能产生一个值。但是,如果您的publisher可以生成多个值,则在发出所有值之前,它不会完成。

我建议将
publisher
typealias Failure=Never

并作为可选结果输出:
typealias output=Result

要执行此操作,可以使用
catch
操作符和
Empty
发布者:

让stringErrorPublisher=Just(“你好”)
.setFailureType(收件人:Error.self)
.eraseToAnyPublisher()//AnyPublisher
设stringPublisher=stringErrorPublisher
.catch{inempty()}
.eraseToAnyPublisher()//AnyPublisher

我也在努力解决这个问题,最终找到了解决办法。需要了解的一件事是,您无法从完成的流量中恢复。解决方案是返回
结果
,而不是
错误

let button = UIButton()
button.publisher(for: .touchUpInside)
    .map({ control -> Result<String, Error> in
        if Bool.random() {
            return .failure(MyError.someError)
        } else {
            return .success("we're in the else case")
        }
    }).sink (receiveValue: { (result) in
        switch(result) {
        case .success(let value):
            print("Received value: \(value)")
        case .failure(let error):
            print("Failure: \(String(describing: error))")
        }
    })

您不能直接使用
PassthroughSubject()
,否则,当出现错误时,通量将完成。

我相信E.com的答案是正确的,但我会说得简单得多。处理错误而不导致管道在错误后停止处理值的关键是将错误处理发布服务器嵌套在
flatMap
中:

import UIKit
import Combine

enum MyError: Error {
  case someError
}

let cancel = [1,2,3]
  .publisher
  .flatMap { value in
    Just(value)
      .tryMap { value throws -> Int in
        if value == 2 { throw MyError.someError }
        return value
    }
    .replaceError(with: 666)
  }
  .sink(receiveCompletion: { (completed) in
    print(completed)
  }, receiveValue: { (sadf) in
    print(sadf)
  })
输出:

1
666
3
finished
您可以在操场上运行此示例


关于OP的编辑:

编辑如果某个发布者拥有
AnyPublisher
,我如何将其转换为
AnyPublisher
,而不在发生错误时完成,即忽略原始发布者发出的错误


你不能。

提到了一部WWDC电影,我相信它是2019年的“实践中的结合”,从6:24左右开始观看:

是的,
.catch()
终止上游发布服务器(电影7:45),并将其替换为
.catch
参数中的给定发布服务器,因此通常会导致在使用
Just()
作为替换发布服务器时交付
.finished

如果原始发布者在失败后继续工作,则需要一个涉及
.flatMap()
的构造(电影9:34)。导致可能故障的运算符需要在
.flatMap
中执行,必要时可以在那里处理。诀窍是使用

.flatMap { data in
    return Just(data).decode(...).catch { Just(replacement) }
}
而不是

.catch { return Just(replacement) } // DOES STOP UPSTREAM PUBLISHER
.flatMap
内部,您总是替换发布服务器,因此不关心替换发布服务器是否被
.catch
终止,因为它已经是一个替换服务器,并且我们的原始上游发布服务器是安全的。这个例子来自电影

这也是您的编辑:问题的答案,关于如何将
转换为
,因为
.flatMap
不会输出任何错误,在flatMap之前和之后都不会有错误。所有与错误相关的步骤都封装在flatMap中。 (提示检查
Failure=Never
:如果您获得了
的Xcode自动完成。分配(to:)
,那么我相信您有一个Failure=Never流,否则订户不可用。 最后是完整的操场代码

PlaygroundSupport.PlaygroundPage.current.needsIndefiniteExecution=true
枚举MyError:错误{
案例错误
}
let cancelable=Timer.publish(每:1,on:.main,in:.default)
.自动连接()
.flatMap({(输入)在
只是(输入)
.tryMap({(输入)->中的字符串
if Bool.random(){
抛出我的错误
}否则{
return“我们在其他情况下”
}
})
.catch{(错误)在
只是(“替换错误”)
}
})
.sink(receiveCompletion:{(completion)in
打印(完成)
PlaygroundSupport.PlaygroundPage.current.finishExecution()
}){(输出)输入
打印(输出)
}

发布服务器将发出消息,直到它完成或失败(出现错误),然后流将被终止

克服此问题的一种方法是将结果用作发布者类型

出版商

protocol SerivceProtocol {
    var value: Published<Result<Double, MyError>>.Publisher { get }
}
service.value
        .sink { [weak self] in
            switch $0 {
            case let .success(value): self?.receiveServiceValue(value)
            case let .failure(error): self?.receiveServiceError(error)
            }
        }
        .store(in: &subscriptions)

您需要使用catch{},但是在catch块中写什么呢?如果我使用Just