7 Replies
      Latest reply: Sep 11, 2016 8:59 AM by eskimo RSS
      kane.codes Level 1 Level 1 (10 points)

        Swift 3 in Xcode 8 beta 6 throws the above error when trying to store `Bool`s, `Int`s or `String`s in a `CKRecord`.

         

        It worked fine in Xcode 8 beta 5. What's the reasoning behind breaking it like this? I would think storing a `String` in a `CKRecord` would be pretty commonplace.

        • Re: Cannot assign value of 'Bool' to type 'CKRecordValue?'
          ahltorp Level 3 Level 3 (410 points)

          I have never used CloudKit, and I don't know why String and Bool don't conform to CKRecordValue, but one of the reasons may be that Swift 3 is changing quickly, and CloudKit may not have been updated properly to account for the changes.

           

          However, I tried this, and a workaround is to wrap your values in NSString or NSNumber like this:

           

          foo.setObject(NSString(string: "Smith"), forKey: "familyName")
          foo.setObject(NSNumber(value: true), forKey: "hasShoes")
          
          

           

          Since I don't have any test environment for CloudKit, I don't know if it will work properly, but given that it emulates the old behaviour and doesn't crash, it should work for you.

            • Re: Cannot assign value of 'Bool' to type 'CKRecordValue?'
              kane.codes Level 1 Level 1 (10 points)

              You don't need to do that with String, you can just cast to NSString like this:

               

              `foo.setObject("smith" as NSString, forKey: "familyName")`

               

              The reason I think is because previously in Swift 3 String would automatically be converted to NSString when needed, but now that's changed, and it's broken a lot of stuff. Now files are littered with massive amounts of casts. I've quickly gone from loving Swift 3 to despising it and I think Apple/the community made a bad move here.

               

              It's not CloudKit that needs to be updated in any case, `CKRecordValue` is a protocol so it is the conforming objects that need to be updated.

               

              The only way I can see to make it slightly less horrendous is by creating some extensions, but I think it's dumb it's the developer's responsibility for this given it's a standard framework.

               

              extension String {
              
                var CKRecordValue: CKRecordValue {
                  return self as NSString
                }
              
              }
              extension Bool {
              
                var CKRecordValue: CKRecordValue {
                  return self as NSNumber
                }
              
              }
              extension Int {
              
                var CKRecordValue: CKRecordValue {
                  return self as NSNumber
                }
              
              }
              extension Data {
              
                var CKRecordValue: CKRecordValue {
                  return self as NSData
                }
              
              }
              
                • Re: Cannot assign value of 'Bool' to type 'CKRecordValue?'
                  ahltorp Level 3 Level 3 (410 points)

                  If you meant to discuss this, please create a discussion instead of a question. Creating a question makes it look like you have a problem that you want to have resolved. I genuinely thought that you wanted help getting your code to work, and not just complain about Swift.

                   

                  Regarding what needs to be updated: conformance to CKRecordValue is in CloudKit, not Foundation, so it is CloudKit that should be updated.

                   

                  Also, Swift 3 is under development, so your complaint that it changes from version to version seems misplaced.

                    • Re: Cannot assign value of 'Bool' to type 'CKRecordValue?'
                      kane.codes Level 1 Level 1 (10 points)

                      I did need help, you gave a solution and I iterated on it.

                       

                      CloudKit doesn't need to be updated, no update to CloudKit could make Foundation objects conform without an update to Foundation, so it's Foundation that would need to be updated now that String and Bool aren't automatically bridged. Something I didn't know until I looked into why it has to be manually cast given the solution you provided, which again, I improved upon.

                        • Re: Cannot assign value of 'Bool' to type 'CKRecordValue?'
                          eskimo Apple Staff Apple Staff (6,075 points)

                          CloudKit doesn't need to be updated, no update to CloudKit could make Foundation objects conform without an update to Foundation …

                          Ah um, that’s not quite true.  The CloudKit overlay could enable this support via a process with the fancy name of retroactive modelling.  You should file a bug against CloudKit requesting improvements in this space (please post your bug number).  In the meantime, you could fix this yourself via the same means.  For example:

                          import CloudKit
                          
                          protocol MyCKRecordValueType {
                              var asObject: CKRecordValue { get }
                          }
                          
                          extension CKRecord {
                              func set<ValueType where ValueType : MyCKRecordValueType>(value: ValueType, forKey key: String) {
                                  let object = value.asObject
                                  self.setObject(object, forKey: key)
                              }
                          }
                          
                          extension String : MyCKRecordValueType {
                              var asObject: CKRecordValue { return self as NSString }
                          }
                          
                          let record: CKRecord! = nil
                          record.set("value", forKey: "key")
                          

                          Share and Enjoy

                          Quinn “The Eskimo!”
                          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                          let myEmail = "eskimo" + "1" + "@apple.com"

                            • Re: Cannot assign value of 'Bool' to type 'CKRecordValue?'
                              kauai Level 1 Level 1 (0 points)

                              Tried quin's suggestion in the final iOS 10 release of Swift3. It generated a compile error; when taking the suggested fix from the compiler, it did not appear to work. Still required casting.

                                • Re: Cannot assign value of 'Bool' to type 'CKRecordValue?'
                                  eskimo Apple Staff Apple Staff (6,075 points)

                                  Try this:

                                  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) 
                                      } 
                                  } 
                                  
                                  extension String : MyCKRecordValueType { 
                                      var asObject: CKRecordValue { return self as NSString } 
                                  } 
                                  
                                  let record: CKRecord! = nil 
                                  record.set(value: "value", forKey: "key")
                                  

                                  Share and Enjoy

                                  Quinn “The Eskimo!”
                                  Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                                  let myEmail = "eskimo" + "1" + "@apple.com"