按照惯例,Table 2-1中列出的每个Cocoa和Core Foundation对象都称为属性列表对象。
那么,这个协议(在下面的代码中称为PropertyListObject
)是否存在,还是我们需要自己制定?如果我们确实需要自己做,那么有人确定了吗?
public protocol UserDefaults_Value_WrappedValue {
associatedtype PropertyListObject: HM.PropertyListObject
init?(propertyListObject: Any)
var convertertedToPropertyListObject: PropertyListObject { get }
}
public protocol PropertyListObject: UserDefaults_Value_WrappedValue
where PropertyListObject == Self { }
public extension PropertyListObject {
init?(propertyListObject: Any) {
guard let object = propertyListObject as? Self
else { return nil }
self = object
}
var convertertedToPropertyListObject: Self { self }
}
extension Bool: PropertyListObject { }
extension Data: PropertyListObject { }
extension Date: PropertyListObject { }
extension String: PropertyListObject { }
extension URL: PropertyListObject { }
extension Int: PropertyListObject { }
extension Int8: PropertyListObject { }
extension Int16: PropertyListObject { }
extension Int32: PropertyListObject { }
extension Int64: PropertyListObject { }
extension UInt: PropertyListObject { }
extension UInt8: PropertyListObject { }
extension UInt16: PropertyListObject { }
extension UInt32: PropertyListObject { }
extension UInt64: PropertyListObject { }
extension Float: PropertyListObject { }
extension Double: PropertyListObject { }
extension Array: PropertyListObject & UserDefaults_Value_WrappedValue
where Element: HM.PropertyListObject {
public typealias PropertyListObject = Self
}
extension Dictionary: UserDefaults_Value_WrappedValue
where Key: LosslessStringConvertible, Value: HM.PropertyListObject {
public typealias PropertyListObject = PropertyListDictionary<Value>
public init?(propertyListObject: Any) {
guard let dictionary = propertyListObject as? PropertyListObject
else { return nil }
self.init(dictionary)
}
public var convertertedToPropertyListObject: PropertyListObject {
.init(self)
}
}
extension Dictionary: PropertyListObject
where Key == String, Value: HM.PropertyListObject { }
public typealias PropertyListDictionary<Value: PropertyListObject> = [String: Value]
import CoreGraphics
extension CGPoint: PropertyListObject { }
extension CGVector: PropertyListObject { }
extension CGSize: PropertyListObject { }
extension CGRect: PropertyListObject { }
extension CGAffineTransform: PropertyListObject { }
用例:
final class UserDefaultsTestCase: XCTestCase {
func test_subscript() {
let key = "?"
UserDefaults[key] = true
XCTAssert(UserDefaults[key] == true)
UserDefaults[key] = 9
XCTAssertEqual(UserDefaults[key], 9)
}
func test_Dictionary() {
let key = "?"
UserDefaults[key] = Day.ta
XCTAssertEqual(UserDefaults["?"], Day.ta)
UserDefaults[key] = [1: "?", 2: "?"]
XCTAssertEqual(UserDefaults["?"], Day.ta)
UserDefaults.standard[key] = ["1": "?", "2": "?"]
XCTAssertEqual(UserDefaults["?"], Day.ta)
}
func test_propertyWrapper() {
struct Type {
@UserDefaults.Value(key: "?") var dayta = Day.ta
}
var instance = Type()
XCTAssertEqual(instance.dayta, Day.ta)
instance.dayta = nil
XCTAssertNil(instance.dayta)
}
}
private enum Day: Int, LosslessStringConvertible {
case sunday = 1, monday
static let ta = [Day.sunday: "?", .monday: "?"]
}
public extension UserDefaults {
@propertyWrapper struct Value<WrappedValue: UserDefaults_Value_WrappedValue> {
public init(
wrappedValue: WrappedValue?,
key: String,
defaults: UserDefaults = .standard
) {
self.key = key
self.defaults = defaults
self.wrappedValue = wrappedValue
}
public var wrappedValue: WrappedValue? {
get { defaults[key] }
set { defaults[key] = newValue }
}
public let key: String
private let defaults: UserDefaults
}
static subscript<Object: UserDefaults_Value_WrappedValue>(key: String) -> Object? {
get { standard[key] }
set { standard[key] = newValue }
}
subscript<Object: UserDefaults_Value_WrappedValue>(key: String) -> Object? {
get { object(forKey: key).flatMap(Object.init) }
set { set(newValue?.convertertedToPropertyListObject, forKey: key) }
}
}
更多阅读内容:https://github.com/apple/swift-evolution/blob/master/proposals/0139-bridge-nsnumber-and-nsvalue.md