【问题标题】:flatMap doesn't get invokedflatMap 没有被调用
【发布时间】:2020-04-15 12:19:52
【问题描述】:

我正在尝试使用两个单独的函数调用来验证用户的电子邮件和密码。

这两个函数都返回 AnyPublisher 发布者,我使用 combineLatest 将返回的值(每个验证调用返回它正在验证的字符串)收集到一个元组中。

然后我使用 flatMap 发出网络请求,以使用 combineLatest 返回的值来注册用户,但是 flatMap 运算符永远不会被调用。

validator.validate(text: email, with: [.validEmail])
  .combineLatest(validator.validate(text: password, with: [.notEmpty]))
  .flatMap { credentials in
    return self.userSessionRepository.signUp(email: credentials.0, password: credentials.1)
  }
  .sink(receiveCompletion: { completion in
    switch completion {
    case .failure(let error):
      print(error)
      self.indicateErrorSigningIn(error)
    case .finished:
      self.goToSignInNavigator.navigateToOtp()
    }
  }, receiveValue: { _ in })
  .store(in: &subscriptions)

signUp(email:password:) 返回 AnyPublisher

这里是验证器函数:

public func validate(text: String, with rules: [Rule]) -> AnyPublisher<String, ErrorMessage> {
  rules.publisher
    .compactMap { $0.check(text) }
    .setFailureType(to: ErrorMessage.self)
    .flatMap {
      Fail<Void, ErrorMessage>(error: ErrorMessage(title: "Error", message: $0.description))
    }
    .map { text }
    .eraseToAnyPublisher()
}

还有注册功能:

public func signUp(email: String, password: String) -> AnyPublisher<Void, ErrorMessage> {
  remoteAPI.signUp(email: email, password: password)
    .flatMap(dataStore.save)
    .mapError { error -> ErrorMessage in
      return ErrorMessage(title: "Error", message: error.description)
    }
    .eraseToAnyPublisher()
}

它调用了这两个函数:

public func signUp(email: String, password: String) -> AnyPublisher<Confirmation, RemoteError> {
  guard email == "john.doe@email.com" else {
    return Fail<Confirmation, RemoteError>(error: .invalidCredentials)
      .eraseToAnyPublisher()
  }

  return Just(Confirmation(otp: "", nonce: "abcd"))
    .setFailureType(to: RemoteError.self)
    .eraseToAnyPublisher()
}

public func save(confirmation: Confirmation) -> AnyPublisher<Void, RemoteError> {
  self.nonce = confirmation.nonce

  return Empty().eraseToAnyPublisher()
}

我不确定出了什么问题,尽管我可能对 Combine 的理解不够,因为我最近才开始学习它。

【问题讨论】:

    标签: swift combine


    【解决方案1】:

    我想通了。

    问题出在 validate(text:with:) 函数上。

    如果发生错误,函数会正常运行,但如果没有错误,函数不会发出任何值,这就是为什么 flatMap 或管道中的任何其他运算符没有被调用的原因。

    它没有发出任何值的原因归结为在 compactMap 中调用的 check(_:) 函数是如何工作的。它返回一个可选字符串,这是一条错误消息。但是如果没有错误,就没有字符串,因此不会发出任何值。

    因此,不会评估对 .map { text } 的调用,也不会返回凭据。

    我已经把代码改成了这个,现在程序可以正常运行了:

    public func validate(text: String, with rules: [Rule]) -> AnyPublisher<String, ErrorMessage> {
      rules.publisher
        .setFailureType(to: ErrorMessage.self)
        .tryMap { rule -> String in
          if let error = rule.check(text) {
            throw ErrorMessage(title: "Error", message: error)
          }
          return text
        }
        .mapError { error -> ErrorMessage in
          return error as! ErrorMessage
        }
        .eraseToAnyPublisher()
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-11-15
      • 1970-01-01
      • 1970-01-01
      • 2018-11-25
      • 2019-03-31
      • 2012-12-16
      • 2015-03-28
      相关资源
      最近更新 更多