How to Properly Send an Image to Cloudkit as Ckasset

How to properly send an image to CloudKit as CKAsset?

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.

Swift 3 Send image to CloudKit with CKAsset

Here is a simple way to save an image as a CKAsset with CloudKit. Please make sure to change the name for your Record, and the field name for the asset from when you set up the record.

let documentsDirectoryPath:NSString = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString
var imageURL: URL!
let tempImageName = "Image2.jpg"

func saveImage(_ image: UIImage?) {

// Create a CKRecord
let newRecord:CKRecord = CKRecord(recordType: "<INSERT_RECORD_NAME")

if let image = image {

let imageData:Data = UIImageJPEGRepresentation(image, 1.0)!
let path:String = self.documentsDirectoryPath.appendingPathComponent(self.tempImageName)
try? UIImageJPEGRepresentation(image, 1.0)!.write(to: URL(fileURLWithPath: path), options: [.atomic])
self.imageURL = URL(fileURLWithPath: path)
try? imageData.write(to: self.imageURL, options: [.atomic])

let File:CKAsset? = CKAsset(fileURL: URL(fileURLWithPath: path))
newRecord.setObject(File, forKey: "<INSERT_RECORD_ASSET_FIELD_NAME")
}

if let database = self.publicDatabase {

database.save(newRecord, completionHandler: { (record:CKRecord?, error:Error?) in

// Check if there was an error
if error != nil {
NSLog((error?.localizedDescription)!)
}
else if let record = record {

// Do whatever you want with the record, but image record was saved, asset should be saved.

}

})

}

}

If you can't do JPEG format, and need to save as .png you can substitute the UIImageJPEGRepresentation section with this:

let imageData:Data = UIImagePNGRepresentation(image)!
try? UIImagePNGRepresentation(image)!.write(to: URL(fileURLWithPath: path), options: [.atomic])

And make the tempImageName something like let tempImageName = "Image2.png"

Hope this helps

SwiftUI, CloudKit and Images

So, let's go... extract ForEach image dependent internals into subview, like (of course it is not testable, just idea):

ForEach(gamesViewModel.games.indices, id: \.self) { index in
GeometryReader { proxy in
GameImageView(model: gamesViewModel, index: index) // << here !!
.frame(width: proxy.size.width, height: proxy.size.height)
.cornerRadius(1)
//.onDisappear { // if you think about cancelling
// gamesViewModel.cancelLoad(for: index)
//}
}
.ignoresSafeArea()
.offset(y: -100)
}
.onAppear(perform: loadImage)

and now subview itself

struct GameImageView: View {
var model: Your_model_type_here
var index: Int

@State private var image: UIImage? // << here !!

var body: some View {
Group {
if let loadedImage = image {
Image(uiImage: loadedImage) // << here !!
.resizable()
.aspectRatio(contentMode: .fill)
} else {
Text("Loading...")
}
}.onAppear {
model.getGameImageFromCloud(for: model.games[index]) { image in
self.image = image
}
}
}
}

How to upload images with cloud kit using swift?

You need to create a CKAsset and add that to your record. You can do that with code like this:

func SaveImageInCloud(ImageToSave: UIImage) {
let newRecord:CKRecord = CKRecord(recordType: "ImageRecord")

let nsDocumentDirectory = NSSearchPathDirectory.DocumentDirectory
let nsUserDomainMask = NSSearchPathDomainMask.UserDomainMask
if let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true) {
if paths.count > 0 {
if let dirPath = paths[0] as? String {
let writePath = dirPath.stringByAppendingPathComponent("Image2.png")
UIImagePNGRepresentation(ImageToSave).writeToFile(writePath, atomically: true)

var File : CKAsset? = CKAsset(fileURL: NSURL(fileURLWithPath: writePath))
newRecord.setValue(File, forKey: "Image")

}
}
}

if let database = self.privateDatabase {
database.saveRecord(newRecord, completionHandler: { (record:CKRecord!, error:NSError! ) in
if error != nil {
NSLog(error.localizedDescription)
} else {
dispatch_async(dispatch_get_main_queue()) {
println("finished")
}
}
})
}

Using Cloudkit Assets as a UIimage

Maybe the problem is that the CKAsset record is nil, but you are forcing to have a fileURL value.

Try to obtain CloudKit image with this snippet

if let asset = record["myImageKey"] as? CKAsset,
let data = try? Data(contentsOf: (asset.fileURL)),
let image = UIImage(data: data)
{
self.detailImage.image = image
}

How to store big image in CloudKit?

You should store pictures as a CKAsset. For a CKRecord there is a size limitation. For a CKAsset there is not (beside the CloudKit storage limitations). According to the documentation:

Use assets for discrete data files. When you want to associate images
or other discrete files with a record, use a CKAsset object to do so.
The total size of a record’s data is limited to 1 MB though assets do
not count against that limit.

You can create a CKAsset like this:

var File : CKAsset = CKAsset(fileURL: NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("image-not-available", ofType: "jpg")!))

How to receive an image from cloudkit?

Just read the CKRecord that you wrote and you can get the CKAsset by reading the key Image. You can get a UIImage using the code below.

var file : CKAsset? = record.objectForKey("Image")

func image() -> UIImage? {
if let file = file {
if let data = NSData(contentsOfURL: file.fileURL) {
return UIImage(data: data)
}
}
return nil
}


Related Topics



Leave a reply



Submit