Swift: Saving photos to CoreData - ios

I need to save images downloaded from the Internet to CoreData.
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return photos.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionPhotoCell", for: indexPath) as! PhotoCollectionCell
let photo = photos[(indexPath as NSIndexPath).row]
if let getImage = photo.getImage() {
cell.photoImageView.image = getImage
}
else {
// Photo Placeholder
cell.photoImageView.image = UIImage(named: "imgPlaceholder.png")
// Activity Indicator
cell.activityIndicator.isHidden = false
cell.activityIndicator.startAnimating()
FlickrClient().imageData(photo) {
(imageData, error) in
guard error == nil else {
return
}
DispatchQueue.main.async {
cell.activityIndicator.isHidden = true
cell.activityIndicator.stopAnimating()
cell.photoImageView.image = UIImage(data: imageData!)
}
}
}
cell.photoImageView.alpha = 1.0
return cell
}
Update:
In CoreData, the entity is Photos, and the Attribute is imageData. Looking at the code below, how does managedObjectContext.save(), save the downloaded images (in the collectionView) to CoreData? I'm still confused.
let photos = NSEntityDescription.insertNewObjectForEntityForName("Photo", inManagedObjectContext: self.managedObjectContext!) as Photo
do {
try managedObjectContext.save()
} catch {
fatalError("Failure to save")
}

You can get the managed object context from AppDelegate in this way:
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let managedObjectContext = appDelegate.persistentContainer.viewContext

Step 1:-
first we have to find image's path into your simulator's document directory using
let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let fileURL = documentsDirectory.appendingPathComponent("image.png")
print(fileURL)
if let data = image.pngData() {
do {
try data.write(to: fileURL)
let imgPath = "\(fileURL)"
imgCategoryPath = imgPath
} catch {
print("error saving file to documents:", error)
}
Step 2:-
second we have to retrive that image path from your simulator's document directory using
let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
if let dirPath = paths.first{
let imageURL = URL(fileURLWithPath: dirPath).appendingPathComponent(nameOfImage).absoluteString
print(imageURL)
}
which path has got that store into core data in string formate column
Set Data
do {
try context.write(imageURL)
} catch {
print(error)
}
Read Data
do {
let imgString = try context.read(imageURL)
} catch {
print(error)
}

Related

Download and Show Array of images in UICollectionView Swift3

I want to download images from server and display in UICollectionView. First time when user connect with internet than all images will download in background and display from local directory when user is offline. I am using alamofire to download the images. Firstly i am checking existence of image, if it is not already dowloaded than i download it. The problem is that the album is not showing when it is already downloaded. I do not know how. Here is my code:
import UIKit
import Alamofire
var myurl : URL!
var imageName : String!
var bool = false
let docsurl = try! FileManager.default.url(for:.documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if (background_imageurl.count > 0) {
if Reachability.isConnectedToNetwork() == true{
downloadAllImages(urlArray : background_imageurl)
}
}
}
func downloadAllImages(urlArray:[String])->Void{
for i in 0 ..< urlArray.count {
let fullName = urlArray[i]
let fullNameArr = (fullName as AnyObject).components(separatedBy: "//")
let imgname = fullNameArr[1]
let tempimgname = imgname
let tempimgname2 = tempimgname.components(separatedBy: "/")
imageName = tempimgname2[4]
myurl = docsurl.appendingPathComponent("\("guidedCellImages")/\(self.imageName!)")
print("\n myurl", myurl)
if FileManager.default.fileExists(atPath: myurl.path, isDirectory: &bool),bool.boolValue {
print("\n fileExists", myurl.path)
}else{
downloadFile(url: urlArray[i] as! String)
}
}
}
func downloadFile(url: String)->Void{
let destination: (URL, HTTPURLResponse) -> (URL, DownloadRequest.DownloadOptions) = {
(temporaryURL, response) in
let directoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
let filePath = directoryURL?.appendingPathComponent("\("guidedCellImages")/\(self.imageName!)")
return (filePath!, [.removePreviousFile, .createIntermediateDirectories])
}
let utilityQueue = DispatchQueue.global(qos: .utility)
print("url", url)
Alamofire.download(
url,
method: .get,
encoding: JSONEncoding.default,
to: destination)
.downloadProgress(queue: utilityQueue) { progress in
}
.response(completionHandler: { (DefaultDownloadResponse) in
if (self.urlArray.count > 0){
self.urlArray.removeFirst()
print("self.urlArray", self.urlArray.count)
}
if DefaultDownloadResponse.response?.statusCode == 200 {
print(DefaultDownloadResponse.destinationURL!)
}
})
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell : CollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! CollectionViewCell
myurl = docsurl.appendingPathComponent("\("guidedCellImages")")
if FileManager.default.fileExists(atPath: myurl.path, isDirectory: &bool),bool.boolValue {
let directoryContents = try! fileManager.contentsOfDirectory(at: myurl, includingPropertiesForKeys: nil)
print("\ndirectoryContents", directoryContents)
for imageURL in directoryContents where imageURL.pathExtension == "png" {
if let image = UIImage(contentsOfFile: imageURL.path) {
cell.tab1GuidedimageView.image = image
} else {
fatalError("Can't create image from file \(imageURL)")
}
}
}else{
if (background_imageurl.count > 0 ){
cell.tab1imageView.sd_setImage(with: URL(string: background_imageurl[indexPath.row]), placeholderImage: UIImage(named: "background"),options: .refreshCached)
}
}
return cell
}
Try this below procedure, this might helps you
struct Animal{
var name: String
var url: String
var image: UIImage?
}
extension Animal{
init(info: [String: String]) {
self.name = info["name"]!
self.url = info["url"]!
}
}
class CollectionViewCell{
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var label: UILabel!
}
class ViewController: UIViewController{
var animals = [Animal]()
override func viewDidLoad(){
super.viewDidLoad()
}
func getAnimals(){
// hit server api to get the images
// assuming that the following json is coming from server
let jsonResponse = [["name":"Dog","url":"https://animals.com/images/image/dog.jpeg"],
["name":"Lion","url":"https://animals.com/images/image/lion.jpeg"],
["name":"Tiger","url":"https://animals.com/images/image/tiger.jpeg"],
["name":"Horse","url":"https://animals.com/images/image/horse.jpeg"],
["name":"Elephant","url":"https://animals.com/images/image/elephant.jpeg"]]
for animal in jsonResponse {
let lAnimal = Animal(info: animal)
// get locally saved image initially from collectionview cell, if it is existed then add it to your response model
let directoryURL = getDocumentsDirectory()
let imageURL = URL(string: lAnimal.url)
let imagePath = directoryURL.appendingPathComponent("animals/\(imageURL.lastPathComponent)")
if fileManager.fileExistsAtPath(imagePAth){
// pass locallay saved image path
lAnimal.image = UIImage(contentsOfFile: imagePAth)
}else{
print("image needs to be downloaded")
}
}
}
func getDocumentsDirectory() -> URL {
let directoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
return directoryURL!
}
}
extension ViewController: UICollectionViewDataSource{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.animals.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell : CollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "reuseIdentifier", for: indexPath) as! CollectionViewCell
let animal = self.animals[indexPath.row]
cell.label.text = animal.name
if let animalImage = animal.image{
//if animal image existis from local them simply display it
cell.imageView.image = animalImage
}else{
//download image from server using simple url task or by using alamofire
let imageURL = URL(string: animal.url)!
let task = URLSession.shared.dataTask(with: imageURL, completionHandler: { (data, response, error) in
if let lData = data {
let image = UIImage(data: lData)
cell.imageView.image = image
let filename = getDocumentsDirectory().appendingPathComponent("animals/\(imageURL.lastPathComponent)")
try? lData.write(to: filename)
//update local data model object
animal.image = image
}
if let lError = error{
/** Handle session error ..................... **/
}
})
}
return cell
}
}
The issue seems with self.imageName. When you are downloading image, the imageName Would have changed in the for loop. Make sure to generate the image name each time from url. while downloading and saving and also while checking.
In fact you can change the scope of imageName variable from global to local.
Recommended is write function to get the image name to avoid redundancy.
EDIT
The guidedCellImages folder must exists, just by adding guidedCEllImages will not create the folder automatically. make sure to add slash (/) before the guidedCellImages
Please check how to create the folder inside document directory here
Hope it helps..!!!
Try this code
func downloadFile(url: String)-> Void {
let directoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
let filePath = directoryURL?.appendingPathComponent("\("guidedCellImages")/\(self.imageName!)")
let data = NSData(contentsOf: URL(string: url)!)
data?.write(toFile: filePath, atomically: true)
}

Setting an image to coredata

I have a list of tableviewcells loaded. And beside each of those cells is an 'Add To favorite' button. When that 'Add To favorite' is clicked the image on it will change and that changed image should be stored into coredata so that when the app is run again I can know which cell was favorited. For that this is what has been tried...
func favoriteBtnTapped(cell: HistoryTableViewCell) {
if segmentControl.selectedSegmentIndex == 2 {
favBtnTapFlag = true
if let indexPath = tableview?.indexPath(for: cell) {
let myFavMsg = messages1[indexPath.row]
let likedMsg = myFavMsg.historyData
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "FavoritedMessages", in: managedContext)
let category = NSManagedObject(entity: entity!, insertInto: managedContext)
category.setValue(likedMsg, forKeyPath: "favData")
//New image is set on the cell and it is saved to coredata here...
cell.favoriteButton.setImage(UIImage(named: "pin"), for: .normal)
let imageData = UIImageJPEGRepresentation((cell.favoriteButton.imageView?.image)!, 1)
category.setValue(imageData, forKey: "favImage")
do {
try managedContext.save()
self.favMessages.append(category as! FavoritedMessages)
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
}
And it is fetched in viewWillAppear like so...
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext =
appDelegate.persistentContainer.viewContext
let fetchRequest =
NSFetchRequest<NSManagedObject>(entityName: "Messages")
let fetchRequest1 = NSFetchRequest<NSManagedObject>(entityName: "FavoritedMessages")
do {
messages1 = try managedContext.fetch(fetchRequest as! NSFetchRequest<NSFetchRequestResult>) as! [Messages]
favMessages = try managedContext.fetch(fetchRequest1 as! NSFetchRequest<NSFetchRequestResult>) as! [FavoritedMessages]
for result in favMessages as [FavoritedMessages] {
if let imageData = result.value(forKey: "favImage") as? NSData {
if let image = UIImage(data:imageData as Data) as? UIImage {
favoritedImage.image = image
}
}
}
tableview.reloadData()
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}}
Here favoritedImage.image = image I'm trying to assign the fetched image to an imageview variable and then assign it at cellForRow. But how that can be done I'm not sure...
You should not save image in coredata.
Save the model with favourite_status as 1. (0 => unfavourited and 1 => favourited ) in coredata. (Basically boolean value)
Load the image from app bundle based on favourite_status.
When loading cells also use favourite_status to load image.
/// Edited
func favoriteBtnTapped(cell: HistoryTableViewCell) {
//1. Get Entity from datasource(Array) using indexpath.row
//2. Favorite the entity by setting favaorite_status = 1
//3. Save to coredata also
//4. Reload Table view
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//1. Get Entity from datasource(Array) using indexpath= Array
//2. Set cell image based on favaorite_status. Use UIImage.init(name:””) (if favaorite_status == 0, imagename will be different)
}

Sample code changed to guard and pointing out the crash

Here is my code
func numberOfSections(in collectionView: UICollectionView) -> Int
{
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return self.getVideosArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
//let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FullImageCell", for: indexPath) as! FullImageCollectionViewCell
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FullImageCell", for: indexPath) as? FullImageCollectionViewCell else {
fatalError()
}
let indexPath = indexPath.row
//UserDefaults.standard.set(indexPath, forKey: "INDEX")
//UserDefaults.standard.synchronize()
self.value = indexPath
let videoStr = NSString.init(format: "http://52.2.212.171/wallpaper/admin/%#", self.getVideosArray.object(at: indexPath) as! String)
self.downloadVideoLinkAndCreateAsset(videoStr as String)
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize
{
return CGSize(width: self.collectionView.frame.size.width, height: self.collectionView.frame.size.height)
}
func downloadVideoLinkAndCreateAsset(_ videoLink: String)
{
self.bgView.isHidden = false
// use guard to make sure you have a valid url
guard let videoURL = URL(string: videoLink) else { return }
let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
// check if the file already exist at the destination folder if you don't want to download it twice
if !FileManager.default.fileExists(atPath: documentsDirectoryURL.appendingPathComponent(videoURL.lastPathComponent).path) {
// set up your download task
URLSession.shared.downloadTask(with: videoURL) { (location, response, error) -> Void in
// use guard to unwrap your optional url
guard let location = location else { return }
// create a deatination url with the server response suggested file name
let destinationURL = documentsDirectoryURL.appendingPathComponent(response?.suggestedFilename ?? videoURL.lastPathComponent)
do {
try FileManager.default.moveItem(at: location, to: destinationURL)
self.loadVideoWithVideoURL(destinationURL)
}
catch let error as NSError
{
print(error.localizedDescription)
}
}.resume()
}
else
{
let getPathUrl = documentsDirectoryURL.appendingPathComponent(videoURL.lastPathComponent)
self.loadVideoWithVideoURL(getPathUrl)
}
}
func loadVideoWithVideoURL(_ videoURL: URL) {
let asset = AVURLAsset(url: videoURL)
let generator = AVAssetImageGenerator(asset: asset)
generator.appliesPreferredTrackTransform = true
let time = NSValue(time: CMTimeMakeWithSeconds(CMTimeGetSeconds(asset.duration)/2, asset.duration.timescale))
generator.generateCGImagesAsynchronously(forTimes: [time]) { [weak self] _, image, _, _, _ in
if let image = image, let data = UIImagePNGRepresentation(UIImage(cgImage: image)) {
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let imageURL = urls[0].appendingPathComponent("image.jpg")
try? data.write(to: imageURL, options: [.atomic])
let image = imageURL.path
let mov = videoURL.path
let output = FilePaths.VidToLive.livePath
let assetIdentifier = UUID().uuidString
let _ = try? FileManager.default.createDirectory(atPath: output, withIntermediateDirectories: true, attributes: nil)
do {
try FileManager.default.removeItem(atPath: output + "/IMG.JPG")
try FileManager.default.removeItem(atPath: output + "/IMG.MOV")
} catch {
}
JPEG(path: image).write(output + "/IMG.JPG",
assetIdentifier: assetIdentifier)
QuickTimeMov(path: mov).write(output + "/IMG.MOV",
assetIdentifier: assetIdentifier)
guard let targetSize = self?.collectionView.bounds.size else
{
fatalError()
//return
}
PHLivePhoto.request(withResourceFileURLs: [ URL(fileURLWithPath: FilePaths.VidToLive.livePath + "/IMG.MOV"), URL(fileURLWithPath: FilePaths.VidToLive.livePath + "/IMG.JPG")],
placeholderImage: nil,
targetSize: targetSize,
contentMode: PHImageContentMode.aspectFit,
resultHandler: { (livePhoto, info) -> Void in
guard let indexValue = self?.value else
{
fatalError()
//return
}
let indexPath = IndexPath.init(row: indexValue, section: 0)
print(indexPath)
guard let cell = self?.collectionView.cellForItem(at: indexPath as IndexPath) as? FullImageCollectionViewCell
else
{
fatalError()
//return
}
cell.fullImage.livePhoto = livePhoto
self?.bgView.isHidden = true
//self?.livePhotoView.livePhoto = livePhoto
//self?.collectionView.reloadData()
})
}
}
}
Here I am setting live photo in the cell in loadVideoWithVideoUrl func. I changed to unwrap the value from ! to guard. And the app crashes at the end of func loadVideoWithVideoURL(_ videoURL: URL) where the I am setting the value to the cell.
guard let cell = self?.collectionView.cellForItem(at: indexPath as IndexPath) as? FullImageCollectionViewCell
else
{
fatalError()
//return
}
I suspect your crash is occurring because of the ! in this line:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FullImageCell", for: indexPath) as! FullImageCollectionViewCell
Change it to:
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FullImageCell", for: indexPath) as? FullImageCollectionViewCell else {
fatalError()
return
}
If it crashes executing the fatalError() line, then the problem is that the cast of cell to FullImageCollectionViewCell is failing.

User-entered values saved to Core Data (?) but not appearing in table view

I've been struggling with user-entered values showing up correctly in a table view in a project I'm working on.
The way I get the user entered values is by getting the user to enter information (company name, stock symbol, and a URL for the logo) into text fields, then calling handleSave() when the done button is pressed:
func handleSave() {
let newCompanyName = nameTextField.text
guard let newCompanyStockSymbol = stockTextField.text else {
// handle the error how you see fit
print("error getting text from field")
return
}
let newCompanyLogo = logoTextField.text
var newCompanyStockPrice = ""
// Fetch stock price from symbol provided by user for new company
let url = URL(string: "https://query.yahooapis.com/v1/public/yql?q=select%20symbol%2C%20Ask%2C%20YearHigh%2C%20YearLow%20from%20yahoo.finance.quotes%20where%20symbol%20in%20(%22\(newCompanyStockSymbol)%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys")!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error!)
} else if let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 {
let json = JSON(data: data!)
if let quotes = json["query"]["results"]["quote"].array {
for quote in quotes {
let ask = quote["Ask"].stringValue
newCompanyStockPrice = ask
}
}
}
self.viewController?.save(name: newCompanyName!, logo: newCompanyLogo!, stockPrice: newCompanyStockPrice)
//self.viewController?.tableView.reloadData()
}
task.resume()
let cc = UINavigationController()
let companyController = CompanyController()
cc.viewControllers = [companyController]
present(cc, animated: true, completion: nil)
}
Which in turn calls this save function, which saves the values into the managed context.
func save(name: String, logo: String, stockPrice: String) {
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext =
appDelegate.persistentContainer.viewContext
let entity =
NSEntityDescription.entity(forEntityName: "Company",
in: managedContext)!
let company = NSManagedObject(entity: entity,
insertInto: managedContext)
company.setValue(stockPrice, forKey: "stockPrice")
company.setValue(name, forKey: "name")
company.setValue(logo, forKey: "logo")
do {
try managedContext.save()
companies.append(company)
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
tableView.reloadData()
}
If I put a breakpoint when I call self.viewController?.save(name: newCompanyName!, logo: newCompanyLogo!, stockPrice: newCompanyStockPrice) in my handleSave() function, I can see that all three things (newCompanyName, newCompanyLogo, and newCompanyStockPrice) have values. But the new company does not appear on my table view when I try to set it in cellForRow:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return companies.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! Cell
let company = companies[indexPath.row]
let stock = company.value(forKey: "stockPrice") as? String
// Company name labels
cell.textLabel?.text = company.value(forKey: "name") as? String
// Stock price underneath
if let stock = stock {
cell.detailTextLabel?.text = "Current stock price: \(stock)"
}
// Logos
DispatchQueue.main.async {
if let url = NSURL(string: (company.value(forKey: "logo") as? String)!) {
if let data = NSData(contentsOf: url as URL) {
cell.logoView.image = UIImage(data: data as Data)
} else {
cell.logoView.image = UIImage(named: "noImage")
}
}
}
return cell
}
EDIT: viewWillAppear
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//1
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext =
appDelegate.persistentContainer.viewContext
//2
let fetchRequest =
NSFetchRequest<NSManagedObject>(entityName: "Company")
//3
do {
companies = try managedContext.fetch(fetchRequest)
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
}
I would advise placing the call to reload data explicitly on the main queue. It appears to me you are calling func save(name: String, logo: String, stockPrice: String) from within the dataTask completion handler, which then calls reloadData on that thread.
Therefore, within the save function, wrap it like this:
DispatchQueue.main.async { [weak self] in
self?.tableView.reloadData()
}

How to receive an image from cloudkit?

I am using this code to store an image in icloud, but what code do i use to retrieave it and place it in a UIImageView? I've tried everything, but it wont work?
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")
}
}
})
}
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
}
After downloading the CKAsset, we need to convert the CKAsset to a UIImage. We can use the following extension (Swift 4 code):
extension CKAsset {
func toUIImage() -> UIImage? {
if let data = NSData(contentsOf: self.fileURL) {
return UIImage(data: data as Data)
}
return nil
}
}
You have to first have a way of finding the specific ImageRecord that you want to retrieve. Assuming that you have the RecordID for the ImageRecord you saved (you can get this from the record in the saveRecord completion block) you can do:
if let database = privateDatabase {
database.fetchRecordWithID(recordID, completionHandler: { (record, error) -> Void in
guard let record = record else {
print("Error retrieving record", error)
return
}
guard let asset = record["Image"] as? CKAsset else {
print("Image missing from record")
return
}
guard let imageData = NSData(contentsOfURL: asset.fileURL) else {
print("Invalid Image")
return
}
let image = UIImage(data: imageData)
imageView.image = image
})
}
(Although you would definitely want to be doing some error handling where those print()s are)
If you don't save the recordID (or probably better: the recordID.recordName so you can make another CKRecordID later), you would need some other way of finding which record you are looking for. If that's the case you'd want to look into using CKDatabase's performQuery(_:inZoneWithID:completionHandler:) method.

Resources