Swift 3 使用 CKAsset 将图像发送到 CloudKit

Swift 3 Send image to CloudKit with CKAsset

N.B:这不是重复问题,我看过其他解决方案,但 none 在 Swift 3 中有效,但它们在 Swift 中有效2.

我需要使用 UIImagePickerController 从照片库中获取图像,它工作正常,然后我需要做的是以某种方式将其保存到 CloudKit 中的 public 记录,我对如何做到这一点持开放态度。请尽可能清楚地说明我需要什么 change/add 以及在哪里。

为了保险起见,我提供了整个视图控制器文件。

import UIKit
import CloudKit

var email: String = ""



class ViewController: UIViewController, UITextFieldDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {


    //MARK: Properties

    @IBOutlet weak var firstNameField: UITextField!
    @IBOutlet weak var lastNameField: UITextField!
    @IBOutlet weak var emailField: UITextField!
    @IBOutlet weak var passwordField: UITextField!
    @IBOutlet weak var confirmPasswordField: UITextField!
    @IBOutlet weak var notMatching: UILabel!
    @IBOutlet weak var emailLabel: UILabel!
    @IBOutlet weak var errorLabel: UILabel!

    @IBOutlet weak var photoImageView: UIImageView!



    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        self.firstNameField.autocorrectionType = .no
        self.lastNameField.autocorrectionType = .no
        self.emailField.autocorrectionType = .no
        self.passwordField.autocorrectionType = .no
        self.confirmPasswordField.autocorrectionType = .no
        self.notMatching.isHidden = true

        firstNameField.delegate = self
        lastNameField.delegate = self
        emailField.delegate = self
        passwordField.delegate = self
        confirmPasswordField.delegate = self


    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    //MARK: UIImagePickerControllerDelegate

    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {

        // Dismiss the picker if the user canceled.
        dismiss(animated: true, completion: nil)

    }

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {

        // The info dictionary may contain multiple representations of the image. You want to use the original.
        guard let selectedImage = info[UIImagePickerControllerOriginalImage] as? UIImage else {
            fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
        }

        // Set photoImageView to display the selected image.
        photoImageView.image = selectedImage



        // Dismiss the picker.
        dismiss(animated: true, completion: nil)


    }


    //MARK: Actions

    @IBAction func selectImageFromPhotoLibrary(_ sender: UITapGestureRecognizer) {

        //Hide keyboards
        firstNameField.resignFirstResponder()
        lastNameField.resignFirstResponder()
        emailField.resignFirstResponder()
        passwordField.resignFirstResponder()
        confirmPasswordField.resignFirstResponder()

        let imagePickerController = UIImagePickerController()

        imagePickerController.sourceType = .photoLibrary


        imagePickerController.delegate = self
        present(imagePickerController, animated: true, completion: nil)

    }



    @IBAction func signUpPressed(_ sender: UIButton) {

        let container = CKContainer.default()
        let pubDB = container.publicCloudDatabase
        //let privDB = container.privateCloudDatabase

        //Check if users exist
        let query = CKQuery(recordType: "MyUsers", predicate: NSPredicate(format: "TRUEPREDICATE", argumentArray: nil))
        pubDB.perform(query, inZoneWith: nil, completionHandler: { (records, error) in

            //error code 11 is no objects found
            if error == nil || error?._code == 11 {

                var emailExists = false

                for record in records! {

                    if record.object(forKey: "email") as? String == self.emailField.text {
                        //other user with the same username exists - don't allow user to create account
                        emailExists = true

                    }

                }

                if emailExists == true {


                    self.emailLabel.text = "\(self.emailField.text!) is taken. Please choose another one."

                } else {

                    if self.firstNameField.text != nil && self.lastNameField.text != nil && self.passwordField.text == self.confirmPasswordField.text {

                        //user can sign up


                        let record = CKRecord(recordType: "MyUsers")
                        record.setObject(self.emailField.text! as CKRecordValue?, forKey: "email")
                        record.setObject(self.passwordField.text! as CKRecordValue?, forKey: "password")
                        record.setObject(self.firstNameField.text! as CKRecordValue?, forKey: "firstName")
                        record.setObject(self.lastNameField.text! as CKRecordValue?, forKey: "lastName")



                        print("all good")

                        pubDB.save(record, completionHandler: { (record, error) in

                            if error == nil {

                                OperationQueue.main.addOperation {

                                    UserDefaults.standard.set(self.emailField.text!, forKey: "Email")
                                    email = self.emailField.text!
                                    //self.performSegue(withIdentifier: "Games", sender: self)

                                }

                            } else {

                                print(error)

                            }

                        })


                    } else {



                    }


                }



            } else {

                print(error)

            }

        })

    }



    // MARK: UITextFieldDelegate

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        // Hide the keyboard.
        textField.resignFirstResponder()
        return true
    }



}

谢谢!

这是将图像保存为 CKAssetCloudKit 的简单方法。请确保在设置记录时更改记录的名称和资产的字段名称。

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.

            }


        })


    }


}

如果你不能做 JPEG 格式,并且需要另存为 .png 你可以用这个代替 UIImageJPEGRepresentation 部分:

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

并使 tempImageName 类似于 let tempImageName = "Image2.png"

希望对您有所帮助

Swift 5 版本,但抽象为一个函数,我可以在其中传入 UI Image 对象和 return 要使用的 URL。在我将图像保存在 CoreData 中并希望稍后上传到 CloudKit 时很有用。

func getImageURL(for image: UIImage?) -> URL {
    let documentsDirectoryPath:NSString = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString
    let tempImageName = "tempImage.jpg"
    var imageURL: URL?

    if let image = image {

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

然后是我如何使用它:

  let imageURL = getImageURL(for: UIImage(data: itemToPublish!.Photo!)!)
  let imageAsset = CKAsset(fileURL: imageURL)
            itemBeingUpdated["photo"] = imageAsset  

  CKContainer.default().publicCloudDatabase.save(challengeRecord) { ...