Cloudkit saving error

Hello,

I recently started learning Swift and now I'm using Cloudkit to store user information.

I kinda have no idea what I'm doing but I watched this youtube tutorial to save user data and display it in UI instantly with DispatchQueue.main.async but it keeps throwing me an error, saying "No exact matches in call to instance method 'save'"

What I want to do is I want users to save a new record and I want this record to be updated instantly and be displayed on the screen.

How could I fix this?

import Foundation
import CloudKit

enum RecordType:String {
    
    case movie = "Movie"
    
}

class SavingMovieViewModel : ObservableObject{
    
    private var database :CKDatabase
    private var container : CKContainer
    
    @Published var movies: [SavingMovieModel] = []
    
    init(container: CKContainer){
        self.container = container
        self.database = container.publicCloudDatabase
    }
    
    func saveMovie(title:String, director: String, stars:String, review: String){
        
        let record = CKRecord(recordType: RecordType.movie.rawValue)
        let movie = Movie(theTitle: title, theDirector: director, theStars: stars, theReview: review)
        
        record.setValuesForKeys(movie.toDictionary())
        
        // saving
        
    self.database.save(record) { newRecord, error in.  //<-- here is where the error is :(
            
            if let error = error{
                print(error)
            }
            else{
                
                if let newRecord = newRecord{  //<-- this bit is the problem. i need the new record added to be displayed instantly 
                    
                    if let movie = Movie.fromRecord(newRecord){
                        DispatchQueue.main.async {
                            self.movies.append(SavingMovieModel(Movie: movie))
                            
                        }
                    }
                    
                }
            }
        }
        
        
    }
    
    
    func whatMovies(){
        
        //creating an array of movies
        var movies: [Movie] = []
        
        let query = CKQuery(recordType: RecordType.movie.rawValue, predicate: NSPredicate(value: true))
        
        database.fetch(withQuery: query) { result in
            switch result{
            case.success(let result):
                result.matchResults.compactMap{$0.1}
                    .forEach{
                        switch $0 {
                        case.success(let record):
                            if let movie = Movie.fromRecord(record){
                                movies.append(movie)
                            }
                        case.failure(let error):
                            print(error)
                        }
                    }
                
                DispatchQueue.main.async {
                    
                    self.movies = movies.map(SavingMovieModel.init)
                    
                }
                
            case.failure(let error):
                print(error)
            }
            
        }
        
    }
    
    
}

struct SavingMovieModel{

    let movie: Movie
    
    var movieId :CKRecord.ID?{
        
        movie.movieId
    }
    
    
    var title:String{
        movie.title
    }
    
    var director:String{
        movie.director
    }
    
    var stars:String{
        movie.stars
    }
    
    var review:String{
        
        movie.review
    }
}

This is the Movie struct for Movie objects

import Foundation
import CloudKit

struct Movie{
    
    var movieId: CKRecord.ID?
    var title:String
    var director:String
    var stars:String
    var review:String
    
    init(movieId: CKRecord.ID? = nil, theTitle:String, theDirector:String, theStars:String, theReview:String){
        
        self.title = theTitle
        self.director = theDirector
        self.stars = theStars
        self.review = theReview
        self.movieId = movieId
    }
    
    func toDictionary() -> [String:Any]{
        return ["title": title, "director" :director, "stars":stars, "review": review]
    }
    
    static func fromRecord(_ record :CKRecord) -> Movie? {
        
        guard let title = record.value(forKey:"title") as? String, let director = record.value(forKey:"director") as? String, let stars = record.value(forKey:"stars") as? String, let review = record.value(forKey:"review") as? String
        else{
            return nil
        }
        
        return Movie(movieId: record.recordID, theTitle: title, theDirector: director, theStars: stars, theReview: review)
    }
    
}

Accepted Reply

This may work, moving the SavingMovieModel(movie: movie) call outside of the main queue dispatch.

                if let newRecord = newRecord {
                    if let movie = Movie.fromRecord(newRecord) {
                        let savingMovieModel = SavingMovieModel(movie: movie)
                        DispatchQueue.main.async {
                            self.movies.append(savingMovieModel)
                        }
                    }
                }
  • Yes it works! Thank you!

  • !!!

Add a Comment

Replies

The line where you indicate the error message has a period after "in", is that period in the code? newRecord, error in.

This may work, moving the SavingMovieModel(movie: movie) call outside of the main queue dispatch.

                if let newRecord = newRecord {
                    if let movie = Movie.fromRecord(newRecord) {
                        let savingMovieModel = SavingMovieModel(movie: movie)
                        DispatchQueue.main.async {
                            self.movies.append(savingMovieModel)
                        }
                    }
                }
  • Yes it works! Thank you!

  • !!!

Add a Comment

Nvm

Post not yet marked as solved Up vote reply of yh29 Down vote reply of yh29