WWDC22 SALE: Save 50% on all my Swift books and bundles! >>

SOLVED: SwiftUI and CloudKit and Images

Forums > SwiftUI

I'm really stumped by something I think that should be relatively easy, so i need a little bump in the right direction. I've search in a lot of places and I get either the wrong information, or outdated information (a lot!).

I am working with Core Data and CloudKit to sync data between the user's devices. Images I save as CKAsset attached to a CKRecord. That works well. The problem is with retrieving the images. I need the images for each unique enitity (Game) in a list. So I wrote a method on my viewModel that retrieves the record with the CKAsset. This works (verified), but I have no idea how to get the image out and assign that to a SwiftUI Image() View. My current method returns a closure with a UIImage, how do I set that image to an Image() within a foreach. Or any other solution is appreciated. Musn't be that hard to get the image?

    /// Returns the saved UIImage from CloudKit for the game or the default Image!
    func getGameImageFromCloud(for game: Game, completion: @escaping (UIImage) -> Void ) {
        // Every game should always have an id (uuid)!
        if let imageURL = game.iconImageURL {
            let recordID = CKRecord.ID(recordName: imageURL)
            var assetURL = ""

            CKContainer.default().privateCloudDatabase.fetch(withRecordID: recordID) { record, error in
                if let error = error {
                    print(error.getCloudKitError())
                    return
                } else {
                    if let record = record {
                        if let asset = record["iconimage"] as? CKAsset {
                            assetURL = asset.fileURL?.path ?? ""
                            DispatchQueue.main.async {
                                completion(UIImage(contentsOfFile: assetURL) ?? AppImages.gameDefaultImage)
                            }
                        }
                    }
                }
            }
        } else {
            completion(AppImages.gameDefaultImage)
        }
    }

Edit: So basically, how can I run getGameImageFromCloud eacht iteration of the ForEach() and assign the the UIImage in the closure to the Image() View in my View?

Edit 2: The user can save several images per game (my main Entity)(Core Data). This must be synced between the user's devices. Perhaps I choose the wrong approach and I should save the images as Data (binary field) to Core Data ?

TIA!

   

I got a working solution, having a custom Image View!

/// Will show an Image for the game from CloudKit
struct GameImage: View {

    var game: Game
    @EnvironmentObject var gamesViewModel: GamesView.ViewModel

    @State private var gameImage: UIImage?

    var body: some View {
        Group {
            if let gameImage = gameImage {
                Image(uiImage: gameImage)
                    .resizable()
                    .aspectRatio(contentMode: .fill)
            } else {
                ZStack(alignment: .center) {
                    Image(uiImage: AppImages.gameDefaultImage)
                        .resizable()
                        .aspectRatio(contentMode: .fill)

                    ProgressView()
                        .foregroundColor(.orange)
                        .font(.title)
                }
            }
        }.onAppear {
            gamesViewModel.getGameImageFromCloud(for: game) { image in
                self.gameImage = image
            }
        }
    }
}

This works. I'm just wondering, what is better performance and memory wise, using the current CKAssets way of storing the images in Core data as Binary? Any opnions? (I thought it was bad practise to store images in Core Data)

   

Hacking with Swift is sponsored by Emerge

SPONSORED Optimize your app’s startup time, binary size, and overall performance using Emerge’s advanced app optimization and monitoring tools. Reliably measure app size, speed up your app's startup time with Emerge's Launch Booster, and much more. Emerge is actively used by many of the top mobile development teams in the world.

Find out more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.