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

How to manipulate together structs with a generic type

Forums > Swift

Hi everyone,

I have a model Person (actually an entity from CoreData) with more than 25 properties. I'm scratching my head for many weeks now, trying to understand conceptually how to create a dynamic filter. The idea is to be able to chose one or more of these attributes and filter dynamically a list of persons accordingly.

  1. some properties are of type String (name == some text)
  2. some are ClosedRange (lowerBound <= height && height <= upperBound)
  3. some are Bool (isThere == true)
  4. some of them are to pick in a list of options (enum) (hair == .darkBrown)
  5. most of them are arrays of different enums (pets, vehicles, hobbies), such as: pets.contains(.cat, .dog, .snake) (The 4th and 5th cases, all the enums are conforming to an "Optionable" protocol)

I need to have all of them grouped in an array in order for the user to pick some criteria. The selected criteria are inserted in and removed from a set to manage the applied criteria. My problem is that I need (I'd like to ?) start from these elements and be able to generalise the code (too many criteria to hard code that !) All these criteria have things in common:

var label: String
var iconName: String
func getPredicate() // produce dynamically the predicate related to the criteria

… More crucially, they have a value that can be of different types:

  1. if the criteria is some text to search, value: String
  2. if the criteria is a range, value: ClosedRange
  3. if the criteria is a bool, value: Bool
  4. if the criteria is an option, value should conform to Optionable
  5. if the criteria is an array of options, value should conform to [Optionable]

I can't simply create a protocol (like "Criteriable" with some generic) because I wouldn't be able to group them in a global array, as they wouldn't be the same type anymore.

var hair = Criteria<Hair>(label: "Hair", …, value: .darkHair)
var height = Criteria<ClosedRange>(label: "Height", …, value: 2…10)
var pets = Criteria<Pet>(label: "Pets", …, value: .snake)
var criteria = [hair, height, pets] <-- Doesn't work.

Basically, I don't know how to make a bridge between an array of elements of the same type (Criteria) on one side, and dynamically populated functions (getPredicate() or views (TextFieldView(value: String, ...), ToggleView(value: Bool, ...), PickerView(value: Pet)) requiring the value type on the other side.

At this point, I don't really know what I'm doing wrong: Is my approach conceptually wrong ? Can the problem be solved a different way ? Is there something about protocols and generics that I miss (I do admit I'm a bit lost with associatedType and typeAlias) ?

PS: I do have an ugly way out, though, by adding a type enum to the criteria (and another OptionType enum for the Optionable cases. But it's depressing to write bad code…

    switch criteria.type {
        case .string:
            TextFieldView(value: String, ...),
        case .range:
             RangeView(value: ClosedRange, ...),
        case .bool:
              BoolView(value: Bool, ...),
        case .options(let type: OptionType):
              switch .type {
                  case .hair:
                      CellView<Hair>(value: Hair, …)
                  case .pets:
                      CellView<Pet>(value: Pet, …)
                  case .vehicles:
                      CellView<Vehicle>(value: Vehicle, …)
                      case…
            X 20 times
                }
}

I'd love some advice or point ofview... Many thanks for your help.

Jo

3      

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.