@propertyWrapper解决正则验证问题

290 阅读2分钟

propertyWrapper

在Swift语法开发时,会将我们需要的逻辑层封装于函数中,除此之外,对于属性中存在逻辑,也可以进行封装,Swift5.1引入了一种特定的方式,用于存放我们对于属性的各种想法,也就是属性包装器。它封装了对属性的读写访问,也可以对当前属性新增其他行为。并且,由于包装器的通用效果,使它可以复用于多个属性。(如果还需要增加它的应用范围,可以使用泛型+属性包装器的方式)

Example

问题:解决一个购买商品的货量限制问题,数量下限为1,上限为99

应用:钳制一个值的实际范围

@propertyWrapper
struct Clamping<Value: Comparable> {
    var value: Value?
    let range: ClosedRange<Value>

    init(wrappedValue value: Value? = nil, _ range: ClosedRange<Value>) {
        // 先决条件: 限制范围内
        //precondition(range.contains(value))
        self.value = value
        self.range = range
    }

    var wrappedValue: Value? {
        get {
            guard let value = value else {
                return range.lowerBound
            }
            return max(min(value, range.upperBound), range.lowerBound)
        }
        set {
            value = newValue
        }
    }
}

调用 @Clamping(1...99) var goodsNumberValue: Int!

正则转换

@propertyWrapper
struct Validation<Value: StringProtocol> {
    
    var value: Value?
    
    var conditions: MatchesType
    
    init(wrappedValue value: Value? = nil, conditions: MatchesType) {
        self.value = value
        self.conditions = conditions
    }
    
    var wrappedValue: Value? {
        get {
            return matches(value: value, conditions: conditions) ? value : nil
        }
        set {
            value = newValue
        }
    }

    func matches(value: Value?, conditions: MatchesType) -> Bool {
        guard let value = value else {
            return false
        }
        // NSPredicate: 限制过滤条件 (包括: 比较字符串 比较运算 逻辑运算等)
        let pre = NSPredicate(format: "SELF MATCHES %@", conditions.string)
        return pre.evaluate(with: value)
    }
}
public enum MatchesType {
    case phone
    case custom(String)

    var string: String {
        switch self {
        case .phone:
            return "^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\\d{8}$"
        case .custom(let string):
            return string
        }
    }
}

调用 @Validation(conditions:.phone) var phone: String?

Explain#

在使用propertyWrapper时,需要注意以下问题:

1.在创建一个@propertyWrapper时,需要有一个必要值wrappedValue。它对应我们外部属性包装器包装的属性值,且类型保持一致。

2.当我们需要初始值,需要在init方法中进行初始化赋值

3.可以使用struct、enum、class定义

4.propertyWrapper是可以嵌套且共存的