Stack overflow when defining subscript on CKRecord in Swift

前端 未结 3 1140
有刺的猬
有刺的猬 2021-01-18 12:22

This question asks whether one can use subscripting with CKRecord in Swift. While I already knew how to do what the questioner wanted, every permutation of it g

相关标签:
3条回答
  • 2021-01-18 13:05

    I was able to successfully subscript by piggy-backing off of some code written by an Apple engineer on dev forums.

    import CloudKit
    
    protocol MyCKRecordValueType {
        var asObject: CKRecordValue { get }
    }
    
    extension CKRecord {
        func set<ValueType>(value: ValueType, forKey key: String) where ValueType : MyCKRecordValueType {
            let object = value.asObject
            self.setObject(object, forKey: key)
        }
        subscript(key : String) -> MyCKRecordValueType? {
            set {
                self.setObject(newValue?.asObject, forKey: key)
            }
            get {
                return object(forKey: key) as? MyCKRecordValueType
            }
        }
    }
    
    extension String : MyCKRecordValueType {
        var asObject: CKRecordValue { return self as NSString }
    }
    extension Bool : MyCKRecordValueType {
        var asObject: CKRecordValue { return self as NSNumber }
    }
    extension Int : MyCKRecordValueType {
        var asObject: CKRecordValue { return self as NSNumber }
    }
    extension Data : MyCKRecordValueType {
        var asObject: CKRecordValue { return self as NSData }
    }
    

    you can then call the subscript as you would expect:

    let firstRecordID = CKRecordID(recordName: "0")
    
            let record = CKRecord(recordType: "Foo", recordID: firstRecordID)
    
            record["title"] = "Hello World"
    
            record["year_established"] = 2000
    
    0 讨论(0)
  • 2021-01-18 13:16

    Here’s a simple extension to CKRecord to make it easier to subscript with.

    extension CKRecord {
        struct Sub {
            let record: CKRecord
    
            subscript(key: String) -> CKRecordValue? {
                get {
                    return record.objectForKey(key) as? CKRecordValue
                }
                set {
                    record.setObject(newValue, forKey: key)
                }
            }
        }
    
        var sub: Sub {
            return Sub(record: self)
        }
    
        var                                                                     
    0 讨论(0)
  • 2021-01-18 13:19

    After some testing and debugging (via a subclass), I discovered that, for CKRecord, objectForKey: does indeed call objectForKeyedSubscript:. Also, implementing subscript in a Swift class that is marked @objc implicitly (by descending from NSObject) or explicitly means that subscript is implemented as objectForKeyedSubscript:.

    This means that implementing subscript on CKRecord in an extension hides the default implementation, which causes the stack overflow.

    0 讨论(0)
提交回复
热议问题