mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
289 lines
13 KiB
Swift
289 lines
13 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
@_exported import CloudKit
|
|
|
|
// __CKRecordObjCValue - an ObjC object that ObjectiveC clients use as CKRecord values
|
|
// CKRecordValueProtocol - a struct or class used only by Swift clients as CKRecord values
|
|
// CKRecordValueConvertible - an ObjectiveC object that should be converted to a native Swift type before being used in Swift clients.
|
|
// CKObjCRecordValueConvertible - a Swift struct or object that should be converted to a CKRecordObjCValue when set on a CKRecord
|
|
|
|
/* CKRecordValueProtocol CKObjCRecordValueConvertible
|
|
__CKRecordObjCValue CKRecordValueConvertible
|
|
----------------|-----------|-----------|-----------|-----------
|
|
String | | X | | X
|
|
Date | | X | | X
|
|
Data | | X | | X
|
|
Bool | | X | | X
|
|
Int | | X | | X
|
|
UInt | | X | | X
|
|
Float | | X | | X
|
|
Double | | X | | X
|
|
[U]Int8 et al| | X | | X
|
|
Int64 | | X | | X
|
|
Array | | X | | X
|
|
NSString | X | X | X |
|
|
NSDate | X | X | X |
|
|
NSData | X | X | X |
|
|
NSNumber | X | X | X |
|
|
NSArray | X | X | X |
|
|
CKReference | X | X | |
|
|
aka CKRecord.Reference
|
|
CKAsset | X | X | |
|
|
CLLocation | X | X | |
|
|
|
|
*/
|
|
|
|
// MARK: - Protocols for bridging record value types
|
|
|
|
/// Anything that can be a record value in Swift.
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
public protocol CKRecordValueProtocol {}
|
|
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
public typealias CKRecordValue = __CKRecordObjCValue
|
|
|
|
// A Swift data type that is convertible to and from a __CKRecordObjCValue
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
private protocol CKObjCRecordValueConvertible : CKRecordValueProtocol {
|
|
// Convert to __CKRecordObjCValue
|
|
func objcRecordValue() -> __CKRecordObjCValue
|
|
// Convert from __CKRecordObjCValue
|
|
static func fromObjcRecordValue(_ objcRecordValue: __CKRecordObjCValue) -> Self
|
|
}
|
|
|
|
// An ObjC data type that is more naturally represented as a native Swift type when pulled from a CKRecord
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
internal protocol CKRecordValueConvertible : __CKRecordObjCValue {
|
|
// Convert to CKRecordValueProtocols
|
|
func swiftNativeValue() -> CKRecordValueProtocol
|
|
}
|
|
|
|
// MARK: - Converting between record value types
|
|
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
extension __CKRecordObjCValue {
|
|
internal func asSwiftNativeValue() -> CKRecordValueProtocol {
|
|
let swiftValue: CKRecordValueProtocol
|
|
if let convertibleObjcRecordValue = self as? CKRecordValueConvertible {
|
|
swiftValue = convertibleObjcRecordValue.swiftNativeValue()
|
|
} else {
|
|
swiftValue = self as! CKRecordValueProtocol
|
|
}
|
|
return swiftValue
|
|
}
|
|
}
|
|
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
extension CKRecordValueProtocol {
|
|
fileprivate func asObjCRecordValue() -> __CKRecordObjCValue {
|
|
let objcValue: __CKRecordObjCValue
|
|
if let convertibleSwiftRecordValue = self as? CKObjCRecordValueConvertible {
|
|
objcValue = convertibleSwiftRecordValue.objcRecordValue()
|
|
} else {
|
|
objcValue = self as! __CKRecordObjCValue
|
|
}
|
|
return objcValue
|
|
}
|
|
}
|
|
|
|
// MARK: - Get and Set RecordValues on records
|
|
|
|
@available(macOS 10.11, iOS 9.0, watchOS 3.0, *)
|
|
extension CKRecordKeyValueSetting {
|
|
@nonobjc
|
|
public subscript<T:CKRecordValueProtocol>(key: CKRecord.FieldKey) -> T? {
|
|
get {
|
|
if let objcValue: __CKRecordObjCValue = self.object(forKey: key) {
|
|
/* I'd really like to do this statically, by implementing a separate subscript that takes <T:CKObjCRecordValueConvertible>. But that doesn't seem to work: <rdar://problem/32911583> Can't overload subscript generics with inherited protocols in protocol extension */
|
|
if let ConvertibleT = T.self as? CKObjCRecordValueConvertible.Type {
|
|
return (ConvertibleT.fromObjcRecordValue(objcValue) as! T)
|
|
} else {
|
|
return (objcValue.asSwiftNativeValue() as! T)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
set {
|
|
self[key] = newValue?.asObjCRecordValue()
|
|
}
|
|
}
|
|
|
|
@nonobjc
|
|
public subscript(key: CKRecord.FieldKey) -> CKRecordValueProtocol? {
|
|
get {
|
|
if let objcValue: __CKRecordObjCValue = self.object(forKey: key) {
|
|
return objcValue.asSwiftNativeValue()
|
|
}
|
|
return nil
|
|
}
|
|
set {
|
|
self[key] = newValue?.asObjCRecordValue()
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - CKRecord Value Protocol conformance
|
|
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
extension CKObjCRecordValueConvertible {
|
|
static func fromObjcRecordValue(_ objcRecordValue: __CKRecordObjCValue) -> Self {
|
|
return objcRecordValue as! Self
|
|
}
|
|
}
|
|
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
extension String : CKRecordValueProtocol, CKObjCRecordValueConvertible {
|
|
fileprivate func objcRecordValue() -> __CKRecordObjCValue { return self as NSString }
|
|
}
|
|
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
extension Date : CKRecordValueProtocol, CKObjCRecordValueConvertible {
|
|
fileprivate func objcRecordValue() -> __CKRecordObjCValue { return self as NSDate }
|
|
}
|
|
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
extension Data : CKRecordValueProtocol, CKObjCRecordValueConvertible {
|
|
fileprivate func objcRecordValue() -> __CKRecordObjCValue { return self as NSData }
|
|
}
|
|
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
extension Bool : CKRecordValueProtocol, CKObjCRecordValueConvertible {
|
|
fileprivate func objcRecordValue() -> __CKRecordObjCValue { return NSNumber(value: self) }
|
|
fileprivate static func fromObjcRecordValue(_ objcRecordValue: __CKRecordObjCValue) -> Bool { return (objcRecordValue as! NSNumber).boolValue }
|
|
}
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
extension Double : CKRecordValueProtocol, CKObjCRecordValueConvertible {
|
|
fileprivate func objcRecordValue() -> __CKRecordObjCValue { return NSNumber(value: self) }
|
|
fileprivate static func fromObjcRecordValue(_ objcRecordValue: __CKRecordObjCValue) -> Double { return (objcRecordValue as! NSNumber).doubleValue }
|
|
}
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
extension Int : CKRecordValueProtocol, CKObjCRecordValueConvertible {
|
|
fileprivate func objcRecordValue() -> __CKRecordObjCValue { return NSNumber(value: self) }
|
|
fileprivate static func fromObjcRecordValue(_ objcRecordValue: __CKRecordObjCValue) -> Int { return (objcRecordValue as! NSNumber).intValue }
|
|
}
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
extension UInt :CKRecordValueProtocol, CKObjCRecordValueConvertible {
|
|
fileprivate func objcRecordValue() -> __CKRecordObjCValue { return NSNumber(value: self) }
|
|
fileprivate static func fromObjcRecordValue(_ objcRecordValue: __CKRecordObjCValue) -> UInt { return (objcRecordValue as! NSNumber).uintValue }
|
|
}
|
|
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
extension Int8 : CKRecordValueProtocol, CKObjCRecordValueConvertible {
|
|
fileprivate func objcRecordValue() -> __CKRecordObjCValue { return NSNumber(value: self) }
|
|
fileprivate static func fromObjcRecordValue(_ objcRecordValue: __CKRecordObjCValue) -> Int8 { return (objcRecordValue as! NSNumber).int8Value }
|
|
}
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
extension UInt8 : CKRecordValueProtocol, CKObjCRecordValueConvertible {
|
|
fileprivate func objcRecordValue() -> __CKRecordObjCValue { return NSNumber(value: self) }
|
|
fileprivate static func fromObjcRecordValue(_ objcRecordValue: __CKRecordObjCValue) -> UInt8 { return (objcRecordValue as! NSNumber).uint8Value }
|
|
}
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
extension Int16 : CKRecordValueProtocol, CKObjCRecordValueConvertible {
|
|
fileprivate func objcRecordValue() -> __CKRecordObjCValue { return NSNumber(value: self) }
|
|
fileprivate static func fromObjcRecordValue(_ objcRecordValue: __CKRecordObjCValue) -> Int16 { return (objcRecordValue as! NSNumber).int16Value }
|
|
}
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
extension UInt16 : CKRecordValueProtocol, CKObjCRecordValueConvertible {
|
|
fileprivate func objcRecordValue() -> __CKRecordObjCValue { return NSNumber(value: self) }
|
|
fileprivate static func fromObjcRecordValue(_ objcRecordValue: __CKRecordObjCValue) -> UInt16 { return (objcRecordValue as! NSNumber).uint16Value }
|
|
}
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
extension Int32 : CKRecordValueProtocol, CKObjCRecordValueConvertible {
|
|
fileprivate func objcRecordValue() -> __CKRecordObjCValue { return NSNumber(value: self) }
|
|
fileprivate static func fromObjcRecordValue(_ objcRecordValue: __CKRecordObjCValue) -> Int32 { return (objcRecordValue as! NSNumber).int32Value }
|
|
}
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
extension UInt32 : CKRecordValueProtocol, CKObjCRecordValueConvertible {
|
|
fileprivate func objcRecordValue() -> __CKRecordObjCValue { return NSNumber(value: self) }
|
|
fileprivate static func fromObjcRecordValue(_ objcRecordValue: __CKRecordObjCValue) -> UInt32 { return (objcRecordValue as! NSNumber).uint32Value }
|
|
}
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
extension Int64 : CKRecordValueProtocol, CKObjCRecordValueConvertible {
|
|
fileprivate func objcRecordValue() -> __CKRecordObjCValue { return NSNumber(value: self) }
|
|
fileprivate static func fromObjcRecordValue(_ objcRecordValue: __CKRecordObjCValue) -> Int64 { return (objcRecordValue as! NSNumber).int64Value }
|
|
}
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
extension UInt64 : CKRecordValueProtocol, CKObjCRecordValueConvertible {
|
|
fileprivate func objcRecordValue() -> __CKRecordObjCValue { return NSNumber(value: self) }
|
|
fileprivate static func fromObjcRecordValue(_ objcRecordValue: __CKRecordObjCValue) -> UInt64 { return (objcRecordValue as! NSNumber).uint64Value }
|
|
}
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
extension Float : CKRecordValueProtocol, CKObjCRecordValueConvertible {
|
|
fileprivate func objcRecordValue() -> __CKRecordObjCValue { return NSNumber(value: self) }
|
|
fileprivate static func fromObjcRecordValue(_ objcRecordValue: __CKRecordObjCValue) -> Float { return (objcRecordValue as! NSNumber).floatValue }
|
|
}
|
|
|
|
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
extension Array : CKRecordValueProtocol, CKObjCRecordValueConvertible where Element: CKRecordValueProtocol {
|
|
fileprivate func objcRecordValue() -> __CKRecordObjCValue {
|
|
let retVal = NSMutableArray()
|
|
self.forEach { retVal.add($0.asObjCRecordValue()) }
|
|
return retVal
|
|
}
|
|
}
|
|
|
|
@nonobjc
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
extension NSString : CKRecordValueProtocol, CKRecordValueConvertible {
|
|
internal func swiftNativeValue() -> CKRecordValueProtocol { return self as String }
|
|
}
|
|
@nonobjc
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
extension NSDate : CKRecordValueProtocol, CKRecordValueConvertible {
|
|
internal func swiftNativeValue() -> CKRecordValueProtocol { return self as Date }
|
|
}
|
|
@nonobjc
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
extension NSData : CKRecordValueProtocol, CKRecordValueConvertible {
|
|
internal func swiftNativeValue() -> CKRecordValueProtocol { return self as Data }
|
|
}
|
|
@nonobjc
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
extension NSNumber: CKRecordValueProtocol, CKRecordValueConvertible {
|
|
internal func swiftNativeValue() -> CKRecordValueProtocol {
|
|
// All numbers come back as Int64 or Double, matching our protobuf conversion
|
|
// In some cases (record accessor methods) we have more type info, and can be smarter. But not here.
|
|
if CFNumberIsFloatType(self) {
|
|
return self.doubleValue
|
|
} else {
|
|
return self.int64Value
|
|
}
|
|
}
|
|
}
|
|
@nonobjc
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
extension NSArray : CKRecordValueProtocol, CKRecordValueConvertible {
|
|
internal func swiftNativeValue() -> CKRecordValueProtocol {
|
|
var retVal = [CKRecordValueProtocol]()
|
|
for element in self {
|
|
let objcRecordValue = element as! __CKRecordObjCValue
|
|
let swiftValue = objcRecordValue.asSwiftNativeValue()
|
|
retVal.append(swiftValue)
|
|
}
|
|
return retVal as CKRecordValueProtocol
|
|
}
|
|
}
|
|
|
|
@nonobjc
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
extension CKRecord.Reference : CKRecordValueProtocol {}
|
|
@nonobjc
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
extension CKAsset : CKRecordValueProtocol {}
|
|
@nonobjc
|
|
@available(macOS 10.10, iOS 8.0, watchOS 3.0, *)
|
|
extension CLLocation : CKRecordValueProtocol {}
|
|
|
|
|