如何将图像作为 CKAsset 正确发送到 CloudKit?
How to properly send an image to CloudKit as CKAsset?
我有一张图片(UIImage,它也是 url),我正尝试将其作为 CKAsset 发送到 CloudKit,但出现此错误:Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Non-file URL'
.这是代码:
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)
}
})
}
我有 URL,我可以打印它,复制并粘贴到我的导航器上,它会显示我的图像!所以,我不知道这里发生了什么......
如果我使用 UIImage 而不是 URL 会更容易吗?因为,正如我之前所说,我两者都有!非常感谢任何帮助!谢谢大家!!
根据我的经验,将上传 UIImage
保存为 CKAsset
的唯一方法是:
- 将图像临时保存到磁盘
- 创建 CKAsset
- 删除临时文件
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)") }
// ...
}
几个月前,我提交了一份错误报告,要求能够从内存 NSData
中初始化 CKAsset
,但尚未完成。
我做了一些不同的事情:我制作了一个可以在多个地方使用的 class,并且由于 Swift 具有有效的反初始化(与 C++ 不同),它可以清理自己起来:
//
// ImageAsset.swift
//
import CloudKit
import UIKit
class ImageAsset {
let image:UIImage
var url:NSURL?
var asset:CKAsset? {
get {
let data = UIImagePNGRepresentation(self.image)
self.url = NSURL(fileURLWithPath: NSTemporaryDirectory()).URLByAppendingPathComponent(NSUUID().UUIDString+".dat")
if let url = self.url {
do {
try data!.writeToURL(url, options: [])
} catch let e as NSError {
print("Error! \(e)")
}
return CKAsset(fileURL: url)
}
return nil
}
}
init(image:UIImage){
self.image = image
}
deinit {
if let url = self.url {
do {
try NSFileManager.defaultManager().removeItemAtURL(url) }
catch let e {
print("Error deleting temp file: \(e)")
}
}
}
}
下面是一个单元测试(假设测试目标中有一个名为秒表的图像):
//
// ImageExtensionTests.swift
//
import CloudKit
import XCTest
@testable import BudgetImpactEstimator
class ImageExtensionTests: XCTestCase {
let testImageName = "stopwatch" // provide the name of an image in test bundle
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testConvertingImageToAsset() {
guard let image = UIImage(named: self.testImageName) else {
XCTFail("failed to load image")
return
}
let imageAsset = ImageAsset(image: image)
XCTAssertNotNil(imageAsset)
guard let asset = imageAsset.asset else {
XCTFail("failed to get asset from image")
return
}
print("constructed asset: \(asset)")
}
}
本来打算把它作为 UIImage 的扩展来做,但后来 deinit 让我搬到了 class。
这是如何将图像保存到 Cloudkit
的 Objective C 版本
由于没有太多信息可以继续,因此需要进行大量挖掘,但这是有效的
if([results count] <= 0) {
NSLog(@"this Record doesnt exist so add it ok!! %@", error);
CKRecordID *wellKnownID = [[CKRecordID alloc]
initWithRecordName:idString];
CKRecord *entitiesName = [[CKRecord alloc] initWithRecordType:@"mySavedDetails"
recordID:wellKnownID];
[entitiesName setObject:idString
forKey:@"myDetailsId"];
[entitiesName setObject:self.myName.text
forKey:@"myName"];
if (myUIImage.image != nil)
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString* path = [documentsDirectory stringByAppendingPathComponent:
@"test.png" ];
NSData* data = UIImagePNGRepresentation(myUIImage.image.image);
[data writeToFile:path atomically:YES];
//so we get the full path of the uiimage
NSLog(@"Path details %@",path);
NSURL* myImagePath = nil;
myImagePath =
[[NSBundle mainBundle] URLForResource:path
withExtension:@"png"];
//here we change the path of Image which is a string to a URL
NSURL *yourURL = [NSURL fileURLWithPath:path];
CKAsset* myImageAsset = nil;
myImageAsset =
[[CKAsset alloc] initWithFileURL:yourURL];
[entitiesName setObject: myImageAsset
forKey:@"myImage"];
[publicDatabase saveRecord: entitiesName
completionHandler:^(CKRecord *savedState, NSError *error) {
if (error) {
NSLog(@"ERROR SAVING: %@", error);
}
}];
}
}
我有一张图片(UIImage,它也是 url),我正尝试将其作为 CKAsset 发送到 CloudKit,但出现此错误:Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Non-file URL'
.这是代码:
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)
}
})
}
我有 URL,我可以打印它,复制并粘贴到我的导航器上,它会显示我的图像!所以,我不知道这里发生了什么......
如果我使用 UIImage 而不是 URL 会更容易吗?因为,正如我之前所说,我两者都有!非常感谢任何帮助!谢谢大家!!
根据我的经验,将上传 UIImage
保存为 CKAsset
的唯一方法是:
- 将图像临时保存到磁盘
- 创建 CKAsset
- 删除临时文件
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)") }
// ...
}
几个月前,我提交了一份错误报告,要求能够从内存
NSData
中初始化 CKAsset
,但尚未完成。
我做了一些不同的事情:我制作了一个可以在多个地方使用的 class,并且由于 Swift 具有有效的反初始化(与 C++ 不同),它可以清理自己起来:
//
// ImageAsset.swift
//
import CloudKit
import UIKit
class ImageAsset {
let image:UIImage
var url:NSURL?
var asset:CKAsset? {
get {
let data = UIImagePNGRepresentation(self.image)
self.url = NSURL(fileURLWithPath: NSTemporaryDirectory()).URLByAppendingPathComponent(NSUUID().UUIDString+".dat")
if let url = self.url {
do {
try data!.writeToURL(url, options: [])
} catch let e as NSError {
print("Error! \(e)")
}
return CKAsset(fileURL: url)
}
return nil
}
}
init(image:UIImage){
self.image = image
}
deinit {
if let url = self.url {
do {
try NSFileManager.defaultManager().removeItemAtURL(url) }
catch let e {
print("Error deleting temp file: \(e)")
}
}
}
}
下面是一个单元测试(假设测试目标中有一个名为秒表的图像):
//
// ImageExtensionTests.swift
//
import CloudKit
import XCTest
@testable import BudgetImpactEstimator
class ImageExtensionTests: XCTestCase {
let testImageName = "stopwatch" // provide the name of an image in test bundle
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testConvertingImageToAsset() {
guard let image = UIImage(named: self.testImageName) else {
XCTFail("failed to load image")
return
}
let imageAsset = ImageAsset(image: image)
XCTAssertNotNil(imageAsset)
guard let asset = imageAsset.asset else {
XCTFail("failed to get asset from image")
return
}
print("constructed asset: \(asset)")
}
}
本来打算把它作为 UIImage 的扩展来做,但后来 deinit 让我搬到了 class。
这是如何将图像保存到 Cloudkit
的 Objective C 版本由于没有太多信息可以继续,因此需要进行大量挖掘,但这是有效的
if([results count] <= 0) {
NSLog(@"this Record doesnt exist so add it ok!! %@", error);
CKRecordID *wellKnownID = [[CKRecordID alloc]
initWithRecordName:idString];
CKRecord *entitiesName = [[CKRecord alloc] initWithRecordType:@"mySavedDetails"
recordID:wellKnownID];
[entitiesName setObject:idString
forKey:@"myDetailsId"];
[entitiesName setObject:self.myName.text
forKey:@"myName"];
if (myUIImage.image != nil)
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString* path = [documentsDirectory stringByAppendingPathComponent:
@"test.png" ];
NSData* data = UIImagePNGRepresentation(myUIImage.image.image);
[data writeToFile:path atomically:YES];
//so we get the full path of the uiimage
NSLog(@"Path details %@",path);
NSURL* myImagePath = nil;
myImagePath =
[[NSBundle mainBundle] URLForResource:path
withExtension:@"png"];
//here we change the path of Image which is a string to a URL
NSURL *yourURL = [NSURL fileURLWithPath:path];
CKAsset* myImageAsset = nil;
myImageAsset =
[[CKAsset alloc] initWithFileURL:yourURL];
[entitiesName setObject: myImageAsset
forKey:@"myImage"];
[publicDatabase saveRecord: entitiesName
completionHandler:^(CKRecord *savedState, NSError *error) {
if (error) {
NSLog(@"ERROR SAVING: %@", error);
}
}];
}
}