Sunday, January 28, 2024
HomeiOS Developmentios - SwiftData Predicate altering at person enter?

ios – SwiftData Predicate altering at person enter?


I have been combating with SwiftData for the previous few days with out reaching an understanding. I’ve to say I am only a newbie so I’ll have made errors some place else too, however nonetheless I do not perceive.

So, what I am attempting to do is to have an inventory of Phrases (a category of mine), that are saved in SwiftData, filtered relying on the class the person chooses. It seems SwiftData has different concepts although.

For organizing the code I took inspiration from Apple’s pattern code.

Class mannequin

Let’s begin with the Class mannequin (which represents the class a phrase could belong to). ColorComponents is a quite simple Codable struct I wrote to retailer a coloration, not necessary.

import Basis
import SwiftData

@Mannequin
class Class: Codable, Equatable {
    enum CodingKeys: CodingKey {
        case title, primaryColor, secondaryColor
    }
    
    @Attribute(.distinctive) let title: String
    let primaryColor: ColorComponents
    let secondaryColor: ColorComponents
    
    init(title: String, primaryColor: ColorComponents, secondaryColor: ColorComponents) {
        self.title = title
        self.primaryColor = primaryColor
        self.secondaryColor = secondaryColor
    }
    
    required init(from decoder: Decoder) throws {
        let container = attempt decoder.container(keyedBy: CodingKeys.self)
        self.title = attempt container.decode(String.self, forKey: .title)
        self.primaryColor = attempt container.decode(ColorComponents.self, forKey: .primaryColor)
        self.secondaryColor = attempt container.decode(ColorComponents.self, forKey: .secondaryColor)
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        attempt container.encode(self.title, forKey: .title)
        attempt container.encode(self.primaryColor, forKey: .primaryColor)
        attempt container.encode(self.secondaryColor, forKey: .secondaryColor)
    }
    
    static func ==(lhs: Class, rhs: Class) -> Bool {
        lhs.title == rhs.title
    }
    
    static let instance = Class(title: "Normal", primaryColor: ColorComponents(coloration: .mint), secondaryColor: ColorComponents(coloration: .blue))
}

Phrase mannequin

Then, the Phrase mannequin. Now, this incorporates a static methodology to return a predicate. Apple’s pattern code suggests this and is maybe the one approach to have a predicate altering along with its enter knowledge.

import Basis
import SwiftData

@Mannequin
class Phrase {
    let time period: String
    let learntOn: Date
    var notes: String
    @Relationship var class: Class?
    
    var categoryName: String {
        class?.title ?? "No class"
    }
    
    init(time period: String, learntOn: Date, notes: String = "", class: Class? = nil) {
        self.time period = time period
        self.learntOn = learntOn
        self.notes = notes
        self.class = class
    }
    
    static func predicate(class: Class?) -> Predicate<Phrase> {
        return #Predicate<Phrase> 
    }
    
    static let instance = Phrase(time period: "Swift", learntOn: .now, notes: "A swift testing phrase.")
}

These are the 2 fashions I’ve. In the principle view I create the mannequin container utilizing .modelContainer(for: Phrase.self).

SwiftUI View

I then have the view the place the question is being made. Based on Apple, on condition that the class is handed to the initializer itself, this fashion of doing issues ensures that the question is up to date at each class change (that ideally I would like for the person to have the ability to choose at any time).

import SwiftData
import SwiftUI

struct WordsCardsListView: View {
    let class: Class?
    @Question personal var phrases: [Word]
    
    init(class: Class? = .instance) {
        self.class = class
        
        let predicate = Phrase.predicate(class: class!)    // drive unwrapping only for testing, after all
        let sortDescriptors = [
            SortDescriptor(Word.learntOn, order: .reverse)
        ]
        _words = Question(filter: predicate, type: sortDescriptors)
    }
    
    var physique: some View {
        Checklist {
            // different views
            
            ForEach(phrases) { phrase in
                WordCardView(phrase: phrase)
                    .listRowSeparator(.hidden)
            }
        }
        .listStyle(.plain)
    }
}

The errors I get

I did attempt each mixture attainable, I imagine, however I all the time get a SwiftData.SwiftDataError._Error.unsupportedPredicate error at runtime (or typically the predicate will not even compile). From what I can collect the predicate doesn’t assist evaluating objects (maybe, it fails each time I attempt to examine a Class or perhaps a Phrase) and it additionally fails when attempting to entry phrase.class?.title, both with non-compulsory chaining or drive unwrapping (on condition that the class’s title is exclusive I might have been pleased with that too). I do know that predicates are considerably restricted in what they will settle for as expressions, however I do not perceive why Apple implementation works and mine doesn’t, since I imagine there aren’t vital variations.

I do know that the best resolution can be to simply question for all phrases after which filter them afterwards (and it is most likely what I’ll find yourself doing), nevertheless it puzzles me that such a easy concept (a filter that updates reside) will not be really easy to acquire with SwiftData.

Anyway, I thank anybody that learn up thus far and that can take the time to reply.



Supply hyperlink

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments