UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

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!

1      

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)

1      

Have you learned anything since posting this about the performance of CKAsset? I haven't heard that storing images in Core Data was a bad practice. If so, what is the recommended approach?

I'm relying on it heavily in my project, as I don't have my own backend.

1      

I switched to Core Data and the Binairy Data type to store my images. CD will only save the image data in de DB itself for small images, otherwise it will place them on 'disk'. It does all handling automatically, so it is very easy to use and no need to handle cases like removing old images when updating one. etc, Cloud syncing works really nice as well!

1      

Hacking with Swift is sponsored by Essential Developer

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until April 28th.

Click to save your free spot now

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

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

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.