Swift Combine:使用其他发布服务器(使用CombineTest)的后续发布服务器不';";“火灾”;

Swift Combine:使用其他发布服务器(使用CombineTest)的后续发布服务器不';";“火灾”;,swift,swiftui,ios13,combine,Swift,Swiftui,Ios13,Combine,我正在尝试复制“巫师学校注册”——在WWDC 2019课程“实践中结合”中给出的示例,从22:50开始使用SwiftUI(与课程期间使用的UIKit相反) 我已经根据示例创建了所有发布服务器:validatedEMail、validatedPassword和validatedCredentials。虽然ValidateMail和ValidatePassword工作正常,但ValidateCredentials(使用CombineTest同时使用两个发布服务器)从不触发 // //注册视图.swi

我正在尝试复制“巫师学校注册”——在WWDC 2019课程“实践中结合”中给出的示例,从22:50开始使用SwiftUI(与课程期间使用的UIKit相反)

我已经根据示例创建了所有发布服务器:validatedEMail、validatedPassword和validatedCredentials。虽然ValidateMail和ValidatePassword工作正常,但ValidateCredentials(使用CombineTest同时使用两个发布服务器)从不触发

//
//注册视图.swift
//
//由Lars Sonchocky Helldorf于19年7月4日创作。
//版权所有©2019 Lars Sonchocky Helldorf。版权所有。
//
导入快捷键
进口联合收割机
结构注册视图:视图{
@ObjectBinding var registrationModel=registrationModel()
@状态私有变量showAlert=false
@国家私有var alertTitle:String=“”
@国家私有var alertMessage:String=“”
@国家私有var注册ButtonDisabled=true
@国家私有var ValidateMail:String=“”
@国家私有var validatedPassword:String=“”
var body:一些观点{
形式{
部分{
TextField(“输入您的电子邮件”,text:$registrationModel.EMail)
SecureField(“输入密码”,文本:$registrationModel.Password)
SecureField(“再次输入密码”,文本:$registrationModel.passwordRepeat)
按钮(操作:注册按钮操作){
文本(“创建帐户”)
}
.disabled($registrationButtonDisabled.value)
.演示文稿($showAlert){
警报(标题:文本(\(警报标题)”),消息:文本(\(警报消息)”)
}
.onReceive(self.registrationModel.validatedCredentials){newValidatedCredentials在
self.registrationButtonDisabled=(newValidatedCredentials==nil)
}
}
部分{
文本(“已验证电子邮件:\(validatedEMail)”)
.onReceive(self.registrationModel.ValidateMail){newValidateMail in
self.validatedEMail=newValidatedEMail!=nil?newValidatedEMail!:“电子邮件无效”
}
文本(“已验证密码:\(已验证密码)”)
.onReceive(self.registrationModel.validatedPassword){newValidatedPassword in
self.validatedPassword=newValidatedPassword!=nil?newValidatedPassword!:“短密码或不匹配密码”
}
}
}
.navigationBarTitle(文本(“注册”))
}
func registrationButtonAction(){
让trimmedEMail:String=self.registrationModel.eMail.trimmingCharacters(在:。空格中)
if(trimmedEMail!=“”&&self.registrationModel.password!=“”){
NetworkManager.sharedInstance.registerUser(NetworkManager.RegisterRequest(uid:trimmedEMail,密码:self.registrationModel.password)){(状态)在
如果状态==200{
self.showart=true
self.alertTitle=NSLocalizedString(“注册成功”,注释:“”)
self.alertMessage=NSLocalizedString(“请验证您的电子邮件和登录”,注释:”)
}如果状态==400,则为else{
self.showart=true
self.alertTitle=NSLocalizedString(“注册错误”,注释:“”)
self.alertMessage=NSLocalizedString(“已注册”,注释:“”)
}否则{
self.showart=true
self.alertTitle=NSLocalizedString(“注册错误”,注释:“”)
self.alertMessage=NSLocalizedString(“网络或应用程序错误”,注释:“”)
}
}
}否则{
self.showart=true
self.alertTitle=NSLocalizedString(“注册错误”,注释:“”)
self.alertMessage=NSLocalizedString(“用户名/密码为空”,注释:“”)
}
}
}
类注册模型:BindableObject{
@已发布的var电子邮件:String=“”
@已发布的var密码:String=“”
@已发布的var passwordRepeat:String=“”
public var didChange=PassthroughSubject()
var validatedEMail:AnyPublisher{
返回$eMail
.debounce(对于:0.5,调度程序:RunLoop.main)
.removeDuplicates()
.flatMap{中的用户名
回报未来{承诺未来}
self.usernameavable(username){在
承诺(.success(可用?用户名:nil))
}
}
}
.删除任何发布者()
}
var validatedPassword:AnyPublisher{
返回publisher.combineTest($password,$passwordRepeat)
.debounce(对于:0.5,调度程序:RunLoop.main)
.map{密码,passwordRepeat in
guard password==passwordRepeat,password.count>5 else{return nil}
返回密码
}
.删除任何发布者()
}
var validatedCredentials:AnyPublisher{
返回publisher.CombineTest(ValidatedMail,validatedPassword)
.map{validatedEMail,validatedPassword in
guard let eMail=validatedEMail,let password=validatedPassword else{return nil}
返回(电子邮件、密码)
}
.删除任何发布者()
}
func usernameavable(username:String,completion:(Bool)->Void){
让isValidEMailAddress:Bool=NSPredicate(格式:“自匹配%@”,[A-Z0-9a-z.\u%+-]+@[A-Za-Z0-9.-]+\.[A-Za-z]{2,64})。评估(使用:用户名)
完成(isValidEMailAddress)
}
}
#如果调试
结构注册视图\u预览:PreviewProvider{
斯达
.debounce(for: 0.5, scheduler: RunLoop.main)
.throttle(for: 0.5, scheduler: RunLoop.main, latest: true)
        .receive(on: RunLoop.main) // run on main thread 
var validatedCredentials: AnyPublisher<(String, String)?, Never> {
    return Publishers.CombineLatest(validatedEMail, validatedPassword)

        .receive(on: RunLoop.main) // <<—— run on main thread

        .map { validatedEMail, validatedPassword in
            print("validatedEMail: \(validatedEMail ?? "not set"), validatedPassword: \(validatedPassword ?? "not set")")

            guard let eMail = validatedEMail, let password = validatedPassword else { return nil }

            return (eMail, password)

    }
    .eraseToAnyPublisher()
//
//  RegistrationView.swift
//  Combine-Beta-Feedback
//
//  Created by Lars Sonchocky-Helldorf on 09.07.19.
//  Copyright © 2019 Lars Sonchocky-Helldorf. All rights reserved.
//

import SwiftUI
import Combine

struct RegistrationView : View {
    @ObservedObject var registrationModel = RegistrationModel()

    @State private var registrationButtonDisabled = true

    @State private var validatedEMail: String = ""
    @State private var validatedPassword: String = ""

    var body: some View {
        Form {
            Section {
                TextField("Enter your EMail", text: $registrationModel.eMail)
                SecureField("Enter a Password", text: $registrationModel.password)
                SecureField("Enter the Password again", text: $registrationModel.passwordRepeat)
                Button(action: registrationButtonAction) {
                    Text("Create Account")
                }
                .disabled($registrationButtonDisabled.wrappedValue)
                    .onReceive(self.registrationModel.validatedCredentials) { newValidatedCredentials in
                        self.registrationButtonDisabled = (newValidatedCredentials == nil)
                }
            }

            Section {
                Text("Validated EMail: \(validatedEMail)")
                    .onReceive(self.registrationModel.validatedEMail) { newValidatedEMail in
                        self.validatedEMail = newValidatedEMail != nil ? newValidatedEMail! : "EMail invalid"
                }
                Text("Validated Password: \(validatedPassword)")
                    .onReceive(self.registrationModel.validatedPassword) { newValidatedPassword in
                        self.validatedPassword = newValidatedPassword != nil ? newValidatedPassword! : "Passwords to short or don't match"
                }
            }
        }
        .navigationBarTitle(Text("Sign Up"))
    }

    func registrationButtonAction() {

    }
}

class RegistrationModel : ObservableObject {

    @Published var eMail: String = ""
    @Published var password: String = ""
    @Published var passwordRepeat: String = ""

    var validatedEMail: AnyPublisher<String?, Never> {
        return $eMail
            .debounce(for: 0.5, scheduler: RunLoop.main)
            .removeDuplicates()
            .map { username in
                return Future { promise in
                    print("username: \(username)")
                    self.usernameAvailable(username) { available in
                        promise(.success(available ? username : nil))
                    }
                }
        }
        .switchToLatest()
            .eraseToAnyPublisher()
    }

    var validatedPassword: AnyPublisher<String?, Never> {
        return Publishers.CombineLatest($password, $passwordRepeat)
            .debounce(for: 0.5, scheduler: RunLoop.main)
            .map { password, passwordRepeat in
                print("password: \(password), passwordRepeat: \(passwordRepeat)")
                guard password == passwordRepeat, password.count > 5 else { return nil }
                return password
        }
        .eraseToAnyPublisher()
    }

    var validatedCredentials: AnyPublisher<(String, String)?, Never> {
        return Publishers.CombineLatest(validatedEMail, validatedPassword)
            .receive(on: RunLoop.main)
            .map { validatedEMail, validatedPassword in
                print("validatedEMail: \(validatedEMail ?? "not set"), validatedPassword: \(validatedPassword ?? "not set")")
                guard let eMail = validatedEMail, let password = validatedPassword else { return nil }
                return (eMail, password)
        }
        .eraseToAnyPublisher()
    }


    func usernameAvailable(_ username: String, completion: (Bool) -> Void) {
        let isValidEMailAddress: Bool = NSPredicate(format:"SELF MATCHES %@", "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}").evaluate(with: username)

        completion(isValidEMailAddress)
    }
}

#if DEBUG
struct RegistrationView_Previews : PreviewProvider {
    static var previews: some View {
        RegistrationView()
    }
}
#endif