How to properly send an image to CloudKit as CKAsset?

后端 未结 3 1867
你的背包
你的背包 2020-12-10 06:00

I have an image (UIImage and it\'s url too) and I\'m trying to send it to CloudKit as a CKAsset but I\'m having this error: Terminating app due to uncaught exception \

相关标签:
3条回答
  • 2020-12-10 06:36

    This is Objective C version of how to save an image to Cloudkit

    This took quite a bit of digging as there is not much info to go on, but this works

      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);
                                  }
    
    
                              }];
    
    
    
                     }
    
    
    
    
                }
    
    0 讨论(0)
  • 2020-12-10 06:39

    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.

    0 讨论(0)
  • 2020-12-10 06:43

    I did something a tad different: I made a class that you can use in multiple places, and thanks to the fact that Swift has reinitialization that works (unlike C++), it cleans up after itself:

    //
    //  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)")
                }
            }
        }
    
    
    }
    

    Here's a unit test that exercises it (presumes there is an image named stopwatch in the test target):

    //
    //  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)")
        }
    
    
    }
    

    Was originally going to do it as an extension on UIImage but then the deist made me move to a class.

    0 讨论(0)
提交回复
热议问题