How can I decode these models with Realm? - swift

I want to use these models both for realm and as codable with Json. How can I do this? As I understand it, Realm doesn't accept it when I use Dictionary.
class QuestionContainer: Codable {
var questionCategories: [Question]
}
class Question: Object, Codable, Identifiable {
#objc dynamic var title: String
#objc dynamic var id: String
#objc dynamic var questions: [QuestionList]
}
class QuestionList: Object, Codable, Identifiable {
#objc dynamic var id: String
#objc dynamic var question: String
#objc dynamic var isQuestionImage, isSectionImage: Bool
#objc dynamic var imageURL: String
#objc dynamic var imageData: Data?
#objc dynamic var sections: [QuestionSections.RawValue : String]
#objc dynamic var selected: String
#objc dynamic var correct: String
}
enum QuestionSections: String, Codable {
case A = "A"
case B = "B"
case C = "C"
case D = "D"
}

Your model should look like:
class QuestionContainer: Object, Codable {
#Persisted var questionCategories: List<Question>
}
class Question: Object, Codable, Identifiable {
#Persisted var title: String
#Persisted var id: String
#Persisted var questions: List<QuestionList
}
class QuestionList: Object, Codable, Identifiable {
#Persisted var id: String
#Persisted var question: String
#Persisted var isQuestionImage: Bool
#Persisted var isSectionImage: Bool
#Persisted var imageURL: String
#Persisted var imageData: Data?
#Persisted var sections: Map<String, String>
#Persisted var selected: String
#Persisted var correct: String
}

Related

Pass Variable from Struct to Class in SwiftUI

i Have a Structure and have some variable in it
struct Home: View {
var token: String
var loginapiurl: String
var companyname: String
#StateObject var dataservice = StatAPI()
i have to pass this token and loginapiurl in the class
class StatAPI: ObservableObject {
#Published var statsdetails = [Result]()
init()
{
print("in init")
let currenDate = getCurrentDate()
let past7DaysBeforeDate = past7dayDate(date1: currenDate)
getStats(dateFrom: past7DaysBeforeDate, dateTo: currenDate)
}
i want to use that two variable in init and passed in to getStats function
I am new to Swiftui. Can anyone help me about this

Class with an Observable Object has been used by is not initializing

I've added an Observable Object to my class DetailViewModel, but I am getting an error "Class 'DetailViewModel' has no initializers". Can anyone explain why?
import Foundation
import UIKit
#MainActor
class DetailViewModel: ObservableObject{
#Published var strMeal: String = ""
#Published var strInstructions: String
#Published var strIngredient: String
#Published var strMeasure: String
#Published var strMealThumb:URL?
private func loadMealDetails(idMeal: String) async {
do {
let mealDetailResponse = try await WebServiceRequest().loadData(url: Constants.Urls.getMealByIdUrl(strMeal)) { data in
return try? JSONDecoder().decode(MealDetailModel.self, from:data )
}
} catch {
print(error)
}
}
You have defined some properties (strInstructions, strIngredient, and strMeasure) that don't have initial values specified. Unlike structs, which get synthesized initializers (eg the compiler makes a initializer for us), with a class, we have to create an initializer ourselves (or give all of the properties default values).
With default values, it may look like:
#MainActor
class DetailViewModel: ObservableObject{
#Published var strMeal: String = ""
#Published var strInstructions: String = ""
#Published var strIngredient: String = ""
#Published var strMeasure: String = ""
#Published var strMealThumb:URL?
}
Or, with an initializer, it could be something like:
#MainActor
class DetailViewModel: ObservableObject{
#Published var strMeal: String = ""
#Published var strInstructions: String
#Published var strIngredient: String
#Published var strMeasure: String
#Published var strMealThumb:URL?
init(strInstructions: String, strIngredient: String, strMeasure: String) {
self.strInstructions = strInstructions
self.strIngredient = strIngredient
self.strMeasure = strMeasure
}
}
You may also want to accept values for strMeal and strMealThumb in your initializer -- it's up to you.

Core Data, Nested List

I'm try to use my data that fetched from Core Data in nested list, but when I add the "children: .listofTasksArray" the following error is shown:
"Key path value type '[ListOfTasks]?' cannot be converted to contextual type 'FetchedResults?'"
this is the core data file
extension ListOfTasks {
#nonobjc public class func fetchRequest() -> NSFetchRequest<ListOfTasks> {
return NSFetchRequest<ListOfTasks>(entityName: "ListOfTasks")
}
#NSManaged public var addedDate: Date?
#NSManaged public var color: String?
#NSManaged public var favoriteIndex: Int16
#NSManaged public var icon: String?
#NSManaged public var id: UUID?
#NSManaged public var index: Int16
#NSManaged public var isArchived: Bool
#NSManaged public var isFavorite: Bool
#NSManaged public var isLocked: Bool
#NSManaged public var title: String?
#NSManaged public var isList: Bool
#NSManaged public var origin: ListOfTasks?
#NSManaged public var subLists: NSSet?
// The wrapped items
public var wrappedAddedDate: Date {
return addedDate ?? Date()
}
// To convert the color from "String" to "Color" type
public var wrappedColor: Color {
return Color(colorName: color ?? "blue")
}
public var wrappedIcon: String {
return icon ?? "ellipsis.circle.fill"
}
public var wrappedId: UUID {
return id ?? UUID()
}
public var wrappedTitle: String {
return title ?? "Unknown Title"
}
public var listofTasksArray: [ListOfTasks]? {
let set = subLists as? Set<ListOfTasks> ?? nil
return set?.sorted { // sort by index
$0.index > $1.index
}
}
}
and this is the list code that I used to fetch the data and use it in the list trying to make nested list using ListOfTasks property "listofTasksArray" as a child for the list.
struct ListsView: View {
#FetchRequest(entity: ListOfTasks.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \ListOfTasks.index, ascending: true)], animation: .default) private var lists: FetchedResults<ListOfTasks>
var body: some View {
List(lists, children: \.listofTasksArray, rowContent: { Text($0.wrappedTitle) })
}
}
Types of data container are expected to be the same, so try to wrap FetchedResults into an array, like (might be some tuning needed do to optionals)
var body: some View {
List(Array(lists), children: \.listofTasksArray) {
Text($0.wrappedTitle
}
}

Realm Swift: how to map different Realm Objects into one List<> conformed to same protocol

Example:
protocol Animal {
#objc dynamic var name: String {get set}
#objc dynamic var age: Int {get set}
}
class Dog: Animal {
#objc dynamic var dogBreed: DogBreed? = nil
}
class Cat: Animal {
#objc dynamic var catBreed: CatBreed? = nil
}
class Bird: Animal {
#objc dynamic var birdBreed: BirdBreed? = nil
}
class Person: Object {
#objc dynamic var name = ""
#objc dynamic var picture: NSData? = nil
let pets = List<Animal>()
}
I'm new in Realm, but I know Realm does not support polymorphism. Is there any option to solve this example?

How to model data using Combine & SwiftUI

I've been learning Swift & SwiftUI and all has been going well until very recently. I have successfully used #Published properties to keep my data & views in sync. However, I now want to display some data that is a combination of several #Published properties.
The simplified data model class:
import Foundation
final class GameAPI: ObservableObject {
struct PlayerStats: Identifiable, Codable {
var gamesPlayed: Int
var wins: Int
var losses: Int
}
struct Player: Identifiable, Codable {
var id = UUID()
var name: String
var stats: PlayerStats
}
struct Room: Identifiable, Codable {
var id = UUID()
var name: String
var players: [Player]
}
struct ServerStats {
var totalGamesPlayed: Int
var totalPlayers: Int
var totalPlayersOnline: Int
}
#Published var players: [Player] = []
#Published var rooms: [Room] = []
func addPlayer(name: String) {
players.append(Player(
name: name,
stats: PlayerStats(
gamesPlayed: 0,
wins: 0,
losses: 0
)
))
}
func removePlayer(id: UUID) { ... }
func updatePlayerStats(playerId: UUID, stats: PlayerStats) { ... }
func getLeaderboard() -> [Player] {
return players.sorted({ $0.stats.wins > $1.stats.wins }).prefix(10)
}
func getServerStats() -> ServerStats {
return ServerStats(
totalGamesPlayed: ...,
totalPlayers: ...,
totalPlayersOnline: ...,
)
}
}
View:
import SwiftUI
struct LeaderboardTabView: View {
#EnvironmentObject var gameAPI: GameAPI
var body: some View {
VStack {
Text("TOP PLAYERS")
Leaderboard(model: gameAPI.getLeaderboard())
// ^^^ How can I make the view automatically refresh when players are added/removed or any of the player stats change?
}
}
}
How can I wire up my views to leaderboard & server stats data so that the view refreshes whenever the data model changes?