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