Swift 3 使用 CKAsset 将图像发送到 CloudKit
Posted
技术标签:
【中文标题】Swift 3 使用 CKAsset 将图像发送到 CloudKit【英文标题】:Swift 3 Send image to CloudKit with CKAsset 【发布时间】:2017-01-13 21:25:18 【问题描述】:注意:这不是一个重复的问题,我已经查看了其他解决方案,但没有一个在 Swift 3 中有效,但它们在 Swift 2 中有效。
我需要使用 UIImagePickerController 从照片库中获取图像,这可以正常工作,然后我需要做的就是以某种方式将其保存到 CloudKit 中的公共记录中,我对此非常开放.如果可能,请清楚我需要更改/添加什么以及在哪里。
为了确定,我已经提供了我的整个视图控制器文件。
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
谢谢!
【问题讨论】:
请看下面我的回答。您还应该知道如何在某个时候检索CKAsset
。如果您要存储资产,您也需要获取它。
【参考方案1】:
这是将图像另存为CKAsset
和CloudKit
的简单方法。请确保从您设置记录时更改您的记录名称和资产的字段名称。
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"
希望对你有帮助
【讨论】:
非常感谢,我有两个应用程序无法执行此操作,并且已经卡了将近 4 个月,这是第一个可行的解决方案! @RufusV - 不客气。如果您有任何问题,请随时问我。我有很多使用CloudKit
的经验
嗨 Pierce,如果你有时间,我有一个关于 CloudKit 的问题。这是链接:***.com/questions/42370112/… 谢谢! :)
@JackRobson - 我刚刚检查过了,看起来你解决了!干得好
感谢 Pierce 的检查!非常感谢:)【参考方案2】:
Swift 5 版本,但被抽象为一个函数,我可以在其中传递 UI Image 对象并返回要使用的 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) ...
【讨论】:
以上是关于Swift 3 使用 CKAsset 将图像发送到 CloudKit的主要内容,如果未能解决你的问题,请参考以下文章
通过 segue 将 CKAsset 图像传递给 ViewController?
CKAsset 获取 PDF 并呈现在 UIWebView Swift3 中
将 CKAsset 异步加载到 UICollectionView