Pedro de Sá Pedro de Sá - 3 months ago 50
iOS Question

How to properly send an image to CloudKit as CKAsset?

I have an image (UIImage and it's url too) and I'm trying to send it to CloudKit as a CKAsset but I'm having this error:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Non-file URL'
. Here is the code:

override func viewDidLoad() {
super.viewDidLoad()

send2Cloud()
}

func send2Cloud() {
let newUser = CKRecord(recordType: "User")

let url = NSURL(string: self.photoURL)

let asset = CKAsset(fileURL: url!)

newUser["name"] = self.name
newUser["photo"] = asset

let publicData = CKContainer.defaultContainer().publicCloudDatabase

publicData.saveRecord(newUser, completionHandler: { (record: CKRecord?, error: NSError?) in

if error == nil {

dispatch_async(dispatch_get_main_queue(), { () -> Void in
print("User saved")
})

} else {
print(error?.localizedDescription)
}
})
}


I have the URL, I can print it, copy and paste to my navigator and it will show my image! So, I don't know what is happening here...

It would be easier if I worked with an UIImage instead of it's URL? Because, as I sais before, I have both of them! Any help is very appreciated! Thanks, guys!!

Answer

In my experience, the only way to save upload UIImage as a CKAsset is to:

  1. Save the image temporarily to disk
  2. Create the CKAsset
  3. Delete the temporary file

let data = UIImagePNGRepresentation(myImage); // UIImage -> NSData, see also UIImageJPEGRepresentation
let url = NSURL(fileURLWithPath: NSTemporaryDirectory()).URLByAppendingPathComponent(NSUUID().UUIDString+".dat")
do {
    try data!.writeToURL(url, options: [])
} catch let e as NSError {
    print("Error! \(e)");
    return
}
newUser["photo"] = CKAsset(fileURL: url)

// ...

publicData.saveRecord(newUser, completionHandler: { (record: CKRecord?, error: NSError?) in
    // Delete the temporary file
    do { try NSFileManager.defaultManager().removeItemAtURL(url) }
    catch let e { print("Error deleting temp file: \(e)") }

    // ...
}


I filed a bug report a few months ago requesting the ability to initialize CKAsset from in-memory NSData, but it hasn't been done yet.

Comments