swift - 如何仅在接收数据时制作已发布的属性调用映射
问题描述
我是Combine的新手,我正在尝试创建一个登录流程,其中:
- 当我单击登录按钮时,应用程序会触发 GoogleSignIn
sign
功能 - 然后,当在 GoogleDelegate 上收到会话数据时,它需要向我的服务器端登录方法发起请求。
为此,我有一个控制登录过程的 GoogleSignInController:
class GoogleSignInController: GIDSignInDelegate {
@Published var onSessionAcquired: GoogleSignInSessionData = ("", "")
func signIn() {
if (GIDSignIn.sharedInstance()?.presentingViewController == nil) {
GIDSignIn.sharedInstance()?.presentingViewController = UIApplication.shared.windows.last?.rootViewController
}
GIDSignIn.sharedInstance()?.signIn()
}
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
if let error = error {
if (error as NSError).code == GIDSignInErrorCode.hasNoAuthInKeychain.rawValue {
print("The user has not signed in")
} else {
print("\(error.localizedDescription)")
}
return
}
onSessionAcquired = GoogleSignInSessionData(idToken: user.authentication.idToken ?? "", serverAuthCode: user.serverAuthCode ?? "")
print("Successful sign-in!")
signedIn = true
}
}
然后在 ViewModel 中,我使用一些状态来控制流程:
static func whenStartedLogin() -> Feedback<State, Event> {
Feedback { (state: State) -> AnyPublisher<Event, Never> in
guard case .loadingGoogleSignIn = state else { return Empty().eraseToAnyPublisher() }
GoogleSignInController.shared.signIn()
return GoogleSignInController.shared.$onSessionAcquired
.receive(on: DispatchQueue.main)
.map { Event.onGoogleSessionAcquired($0) }
.eraseToAnyPublisher()
}
}
static func whenReceivedGoogleSession() -> Feedback<State, Event> {
Feedback { (state: State) -> AnyPublisher<Event, Never> in
guard case let .loadingServerSession(googleSession) = state else { return Empty().eraseToAnyPublisher() }
return self.signIn(idToken: googleSession.idToken, serverAuthCode: googleSession.serverAuthCode)
.map { (userInfo, error) in
if let error = error {
return Event.onFailedToAcquireSession(error)
} else if let userInfo = userInfo {
return Event.onUserInfoAcquired(userInfo)
} else {
return Event.onFailedToAcquireSession(AppError.unknown)
}
}
.eraseToAnyPublisher()
}
}
问题是:当我单击登录按钮时,该whenStatedLogin
函数被触发,并将我的事件映射为Event.onGoogleSessionAcquired
. 这应该仅在onSessionAcquired
更改时(在sign
调用委托后)进行映射。我怎样才能做到这一点?
解决方案
刚刚想出了这个问题的解决方案。在我的情况下要使用的正确数据类型是PassthroughSubject
.
let sessionSubject = PassthroughSubject<GoogleSignInSessionData, Never>()
...
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
if let error = error {
if (error as NSError).code == GIDSignInErrorCode.hasNoAuthInKeychain.rawValue {
print("The user has not signed in")
} else {
print("\(error.localizedDescription)")
}
return
}
sessionSubject.send(GoogleSignInSessionData(idToken: user.authentication.idToken ?? "", serverAuthCode: user.serverAuthCode ?? ""))
print("Successful sign-in!")
signedIn = true
}
以这种方式使地图仅在主题收到事件时才被调用。
推荐阅读
- laravel - 修补程序和 laravel 的问题
- html - css 文件不可见 - 文件未设置样式
- android - org.json.JSONArray 不能转换为 double[]
- javascript - 使用带有 ReactJs 的钩子的多搜索过滤器
- pyspark - 连接数组pyspark
- kubernetes - 如何使 daemonSet 可被其他 pod 发现?
- ios - 当我想在我的代码上使用付款方式进行集成测试时,我收到了这个错误。预期声明
- python - 如果字符串中包含日期和时间,如何删除它?
- typescript - 订阅 rxjs 主题获取的打字稿类型错误?
- android - Widget.AppCompat.Button.Colored 默认情况下不可聚焦