ValidatedPropertyKit Logo

ValidatedPropertyKit

一个 Swift 包,可以使用属性包装器轻松验证您的属性 👮

Swift Version Platforms
Build and Test Status Documentation Twitter

import SwiftUI
import ValidatedPropertyKit

struct LoginView: View {

    @Validated(!.isEmpty && .isEmail)
    var mailAddress = String()

    @Validated(.range(8...))
    var password = String()

    var body: some View {
        List {
            TextField(
               "E-Mail",
               text: self.$mailAddress
            )
            if self._mailAddress.isInvalidAfterChanges {
                Text(verbatim: "Please enter a valid E-Mail address.")
            }
            TextField(
               "Password",
               text: self.$password
            )
            if self._password.isInvalidAfterChanges {
                Text(verbatim: "Please enter a valid password.")
            }
            Button {
               print("Login", self.mailAddress, self.password)
            } label: {
               Text(verbatim: "Submit")
            }
            .validated(
                self._mailAddress,
                self._password
            )
        }
    }

}

特性

安装

Swift 包管理器

要使用 Apple 的 Swift 包管理器集成,请将以下内容作为依赖项添加到您的 Package.swift 文件中

dependencies: [
    .package(url: "https://github.com/SvenTiigi/ValidatedPropertyKit.git", from: "0.0.6")
]

或者导航到您的 Xcode 项目,然后选择 Swift Packages,单击“+”图标并搜索 ValidatedPropertyKit

手动

如果您不想使用上述任何依赖管理器,您可以手动将 ValidatedPropertyKit 集成到您的项目中。 只需将 Sources 文件夹拖到您的 Xcode 项目中即可。

Validated 👮‍♂️

@Validated 属性允许您在属性声明旁边指定验证。

注意:@Validated 支持 SwiftUI View 更新,并且基本上以与 @State 相同的方式工作。

@Validated(!.isEmpty)
var username = String()

@Validated(.hasPrefix("https"))
var avatarURL: String?

如果 @Validated 应用于可选类型(例如 String?),您可以指定当值为 nil 时验证应该失败还是成功。

@Validated(
   .isURL && .hasPrefix("https"),
   isNilValid: true
)
var avatarURL: String?

默认情况下,参数 nilValidation 设置为 .constant(false)

此外,SwiftUI.View 扩展 validated() 允许您根据您的 @Validated 属性禁用或启用特定的 SwiftUI.View。 如果至少一个传入的 @Validated 属性的计算结果为 false,则 validated() 函数将禁用 SwiftUI.View

@Validated(!.isEmpty && .contains("@"))
var mailAddress = String()

@Validated(.range(8...))
var password = String()

Button(
   action: {},
   label: { Text("Submit") }
)
.validated(self._mailAddress && self._password)

通过使用下划线表示法,您可以将 @Validated 属性包装器传递给 validated() 函数

验证 🚦

每个 @Validated 属性都将使用 Validation 进行初始化,该 Validation 可以使用一个简单的闭包进行初始化,该闭包必须返回一个 Bool 值。

@Validated(.init { value in
   value.isEmpty
})
var username = String()

因此,ValidatedPropertyKit 附带了许多用于各种类型和协议的内置便利函数。

@Validated(!.contains("Android", options: .caseInsensitive))
var favoriteOperatingSystem = String()

@Validated(.equals(42))
var magicNumber = Int()

@Validated(.keyPath(\.isEnabled, .equals(true)))
var object = MyCustomObject()

前往 预定义的验证 部分了解更多信息

此外,您可以通过条件一致性扩展 Validation,以便轻松声明您自己的验证。

extension Validation where Value == Int {

    /// Will validate if the Integer is the meaning of life
    static var isMeaningOfLife: Self {
        .init { value in
            value == 42
        }
    }

}

并将它们应用于您已验证的属性。

@Validated(.isMeaningOfLife)
var number = Int()

isValid ✅

您可以通过使用下划线表示法直接访问 @Validated 属性包装器,随时访问 isValid 状态。

@Validated(!.isEmpty)
var username = String()

username = "Mr.Robot"
print(_username.isValid) // true

username = ""
print(_username.isValid) // false

验证运算符 🔗

验证运算符允许您组合多个验证,就像处理布尔值一样。

// Logical AND
@Validated(.hasPrefix("https") && .hasSuffix("png"))
var avatarURL = String()

// Logical OR
@Validated(.hasPrefix("Mr.") || .hasPrefix("Mrs."))
var name = String()

// Logical NOT
@Validated(!.contains("Android", options: .caseInsensitive))
var favoriteOperatingSystem = String()

预定义的验证

ValidatedPropertyKit 带有许多预定义的通用验证,您可以利用这些验证来为已验证的属性指定 Validation

KeyPath

keyPath 验证将允许您为 attributed 属性的给定 KeyPath 指定验证。

@Validated(.keyPath(\.isEnabled, .equals(true)))
var object = MyCustomObject()

字符串

可以使用多种方式验证 String 属性,例如 containshasPrefix 甚至 RegularExpressions

@Validated(.isEmail)
var string = String()

@Validated(.contains("Mr.Robot"))
var string = String()

@Validated(.hasPrefix("Mr."))
var string = String()

@Validated(.hasSuffix("OS"))
var string = String()

@Validated(.regularExpression("[0-9]+$"))
var string = String()

Equatable

可以针对指定的值验证 Equatable 类型。

@Validated(.equals(42))
var number = Int()

Sequence

可以通过 containsstartsWith 验证来验证 Sequence 类型的属性。

@Validated(.contains("Mr.Robot", "Elliot"))
var sequence = [String]()

@Validated(.startsWith("First Entry"))
var sequence = [String]()

Collection

每个 Collection 类型都提供 isEmpty 验证和 range 验证,您可以在其中轻松声明有效容量。

@Validated(!.isEmpty)
var collection = [String]()

@Validated(.range(1...10))
var collection = [String]()

Comparable

可以使用所有常见的可比较运算符来验证 Comparable 类型。

@Validated(.less(50))
var comparable = Int()

@Validated(.lessOrEqual(50))
var comparable = Int()

@Validated(.greater(50))
var comparable = Int()

@Validated(.greaterOrEqual(50))
var comparable = Int()

许可证

ValidatedPropertyKit
Copyright (c) 2022 Sven Tiigi sven.tiigi@gmail.com

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.