在进行项目开发时,遇到了这么个情况:某个属性需要和蓝牙交互,但是这个操作会比较耗时,现在想实现当这个属性的值在更改前后未发生变动的时候,跳过蓝牙交互,直接进行下一步操作,从而提升用户体验,下面是我的@propertyWrapper实现,请大家指正:
@propertyWrapper
final class EditDetectable<E> where E: Equatable {
var projectedValue: EditDetectable<E> {
self
}
private var value: E?
var wrappedValue: E? {
get { value }
set {
value = newValue
if requirements.contains(.valid), newValue == .none { return }
if let string = newValue as? String,
requirements.contains(.validString),
string.isEmptyString { return }
hit(newValue)
}
}
var needsUpdate: Bool {
if hitCache.isEmpty {
return false
} else {
guard hitCache.count > 1 else {
if requirements.contains(.ignoreInitialValue) {
return false
}
return true
}
var isValid: Bool {
guard requirements.contains(.valid) else { return true }
return wrappedValue != .none
}
var isNotEmptyString: Bool {
guard requirements.contains(.validString) else { return true }
guard let string = wrappedValue as? String else { return false }
return !string.isEmptyString
}
return isValid && isNotEmptyString && hitCache.first != hitCache.last
}
}
private var lock = NSRecursiveLock()
private var hitCache: [E?] = []
private func hit(_ value: E?) {
lock.lock()
if hitCache.count == 2 {
hitCache.removeLast()
}
hitCache.append(value)
lock.unlock()
}
private let requirements: ValueRequirement
init(wrappedValue: E?, requirements: ValueRequirement = [.valid]) {
self.requirements = requirements
self.wrappedValue = wrappedValue
}
}
struct ValueRequirement: OptionSet {
let rawValue: Int
static let valid = ValueRequirement(rawValue: 1 << 0)
static let validString = ValueRequirement(rawValue: 1 << 1)
static let ignoreInitialValue = ValueRequirement(rawValue: 1 << 2)
}
使用时调用EditDetectable.needsUpdate属性判断是否需要更新
@EditableProperty(requirements: [.valid, .validString])
var name: String? = ""
name = ""
name = nil
name = "7788"
name = "8899"
name = "9090"
name = "7788"
name = "8899"
name = nil
print("更新? ", $name.needsUpdate)