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