parse a case from enum

I have a detailed json file, where I have the following structure:


struct legal: Hashable, Codable, Identifiable {

var name: String

var place: String

var category: Category


enum Category: String, CaseIterable, Codable, Hashable {

case categoryone = "category One"

case categorytwo = "category Two"

case categorythree = "category Three"

}

}


Now I want the list of all the names of the category one in one list. How do I extract the data from this file?

Replies

It is not clear enough how data are structured in this file.


Please show a concrete example.

If you get all the elements in an array,


var allElements : [Legal] = []     // Note that the name of Struct should better start with UpperCase

// Somewhere you load the elements from JSON

// then you can filter tha array:
let elementsOfOne = allElements.filter() { $0.category ==  .categoryone )
//    Then, put them in your list (if it is a tableView, use elementsOfOne as the dataSource


Is it what you are looking for ?

In my "Data.swift" file:


struct Legal: Hashable, Codable, Identifiable {

var name: String

var place: String

var category: Category

var isFavorite: Bool

var penalty: String


enum Category: String, CaseIterable, Codable, Hashable {

case categoryone = "category One"

case categorytwo = "category Two"

case categorythree = "category Three"

}

}


In my "legalData.json" file there a several legal provisions following this structure.


I want to sort the legal provisions of categoryone in a separate view:


Import SwiftUI


struct CategoryoneList: View {


@published var legals = legalData

var allElements: [Legal] = []

var body: some View {

NavigationView {

List {

ForEach(...) { legal in

if !self.userData.showFavoritesOnly || legal.isFavorite {

NavigationLink(destination: LegalDetail(legal: legal)

.environmentObject(self.userData)

) {

LegalRow(legal: legal

}

}

}

}

}



I want to know what I have to type in (...) to have only the legal provisions in this view.


Thanks in advance

That's SwiftUI, you should have told at the beginning. And moved the question to SwiftUI part of the forum.


I would write the following (I do not see all the code to be totally sure though)


ForEach(allElements, id: \.self) { legal in

You can write somethig like this, but it is super-suspicious if it would work as you expect.

    var body: some View {
        NavigationView {
            List {
                ForEach(allElements.filter{$0.category == .categoryone}) { legal in
                    if !self.userData.showFavoritesOnly || legal.isFavorite {
                        NavigationLink(destination: LegalDetail(legal: legal)
                            .environmentObject(self.userData)
                        ) {
                            LegalRow(legal: legal)
                        }
                    }
                }
            }
        }
    }


You do not show enough info to confirm this would work. Please show all relevant codes and data.


What is `legalData`? What is `userData`? What is the difference between `legals` and `allElements`?

And please show some example of your "legalData.json".

thanks for the answer, but it didn't do anything.


I'll try to clarify my model (work in progress 🙂).


Legal.swift file is structured as follows:


struct Legal: Hashable, Codable, Identifiable {
     var name: String
     var place: String
     var category: Category
     var isFavorite: Bool
     var penalty: String

     enum Category: String, CaseIterable, Codable, Hashable {
          case categoryone = "category One"
          case categorytwo = "category Two"
          case categorythree = "category Three"
     }
}



UserData.swift file is structured as follows:


import Combine
import SwiftUI

final class UserData: ObservableObject {
    @Published var showFavoritesOnly = false
    @Published var legals = legalData
}



A few examples from my legal.json file:


[
    {
        "name": "infringement 1",
        "category": "Category 1",
        "place": "UK",
        "id": 7004,
        "isFavorite": false,
        "penalty": "473 EUR",
    },
    {
        "name": "infringement 2",
        "category": "Category 2",
        "place": "France",
        "id": 1046,
        "isFavorite": false,
        "penalty": "116 EUR"
     }
]



Home.swift file = home view is structured as follows:


import SwiftUI

struct Home: View {
    @EnvironmentObject private var userData: UserData

    var body: some View {
        NavigationView {
            List {
        
                NavigationLink(destination: CategoryoneList()) {
                    Text("1. Category one")
                }
        
                NavigationLink(destination: CategorytwoList()) {
                    Text("2. Category two")
                }
        
                NavigationLink(destination: CategorythreeList()) {
                    Text("3. Category three")
                }

                NavigationLink(destination: LegalList()) {
                    Text("4. Overview").bold().underline()
                }
            }
            .navigationBarTitle("View", displayMode: .inline)
        }
    }
}


LegalList.swift file contains all the legal provisions (disregarding the categories)

This is structured as follows:


struct LegalList: View {
    @EnvironmentObject private var userData: UserData
    var body: some View {
     
        List {
         
                Toggle(isOn: $userData.showFavoritesOnly) {
                Text("Show Favorites").bold().underline()
            }
         
            ForEach(userData.legals) { legal in
                if !self.userData.showFavoritesOnly || legal.isFavorite {
                    NavigationLink(
                        destination: LegalDetail(legal: legal)
                            .environmentObject(self.userData)
                    ) {
                        LegalRow(legal: legal)
                    }
                }
            }
        }
        .navigationBarTitle("4. Overview", displayMode: .inline)
     
    }
}


LegalDetail.swift file is structured as follows:


struct LegalDetail: View {
    @EnvironmentObject var userData: UserData
    var legal: Legal
  
    var legalIndex: Int {
        userData.legals.firstIndex(where: { $0.id == legal.id })!
    }
  
    var body: some View {
      
                List {
                  
                    VStack {
                      
                        HStack(alignment: .top) {
                        Text(legal.name).bold().underline()
                            }
                            .padding()
                            .foregroundColor(Color.green)
                            Spacer()
                      
                        VStack(alignment: .leading) {
                            Text(legal.place)
                            Divider()
                            }
                                             
                        Text("Penalty").bold().underline()
                            .padding()
                            .foregroundColor(Color.orange)

                        VStack(alignment: .leading) {
                            Text(legal.penalty)
                            Divider()
                            }
                        }

                }.navigationBarTitle(legal.name)
                    .navigationBarItems(trailing:
                    Button(action: {
                        self.userData.legals[self.legalIndex]
                            .isFavorite.toggle()
                    }) {
                        if self.userData.legals[self.legalIndex]
                            .isFavorite {
                            Image(systemName: "star.fill")
                                .foregroundColor(Color.yellow)
                        } else {
                            Image(systemName: "star")
                                .foregroundColor(Color.gray)
                                }
                        }.font(.system(size: 27))
                    )
              
            }


LegalRow.swift file is structured as follows:


struct LegalRow: View {
    var legal: Legal

    var body: some View {
        HStack {
            Text(legal.name)
            Spacer()

            if legal.isFavorite {
                Image(systemName: "star.fill")
                    .imageScale(.medium)
                    .foregroundColor(.yellow)
            }
        }
    }
}


The question now is how to make a seperate view for Category one, two and three, with the list of only the legal provisions of that category.


Regarding the question of the allElements, this was a suggestion of Claude31.


My apologies for the long post and again thanks in advance

You still don't show how legalData is defined:


@Published var legals = legalData


As for allElements, don't know if it is needed. But with the very scarce information in your original post, it was necessary to guess you had an array bcontaining your data.

Is it the same as legals ? If so, replace allElements with legals of course.

Thanks for clarifying.


but it didn't do anything.


Regarding the question of the allElements, this was a suggestion of Claude31.


You should better not include codes from unconfirmed responses, that may lead another unconfirmed response, which would not do anything.


As commented in a Claud31's response, you are not showing how `legalData` (in class UserData or on struct CategoryoneList) is declared

But I guess you do not need one in struct CategoryoneList.


struct CategoryoneList: View {
    
    @EnvironmentObject var userData: UserData
    
    var body: some View {
        NavigationView {
            List {
                ForEach(userData.legals.filter{$0.category == .categoryone}) { legal in
                    if !self.userData.showFavoritesOnly || legal.isFavorite {
                        NavigationLink(destination: LegalDetail(legal: legal)
                            .environmentObject(self.userData)
                        ) {
                            LegalRow(legal: legal)
                        }
                    }
                }
            }
        }
    }
}


Assuming your `UserData` is well-defined and you have set up environmentObject properly.

But I cannot be sure as you are not showing codes around there.

Thank you for the answers. It worked for now with the revised code from OOPer.


To be complete, the code for legalData was in a different file:


import Foundation
import CoreLocation
import UIKit
import SwiftUI

let legalData: [Legal] = load("legalData.json")

func load(_ filename: String) -> T {
    let data: Data
    guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
       
    else {
        fatalError("Can't find \(filename) in main bundle")
    }
   
    do {
        data = try Data(contentsOf: file)
    } catch {
        fatalError("Can't load \(filename) from main bundleà")
       
    }
   
    do {
        let decoder = JSONDecoder()
        return try decoder.decode(T.self, from : data)
    } catch {
        fatalError("Can't parse \(filename) as \(T.self):\n\(error)")
    }
}

I have two follow up questions. If I have to open a new post for these, just let me know.


First, I have a problem with some text not being displayed completely (see legal.penalty in the LegalDetail.swift file) in the simulator. From Iphone 8s there is no problem, but on the Iphone 8 the texts are cut and end with [...]


Is there any reason why?



Second, I want to ad a searchbar on the LegalList view. I try to search on the legal name (the names are displayed in the list).

I added in the LegalList.swift:


@State privatevar searchTerm: String = ""


and under List {


SearchBar(text: $searchTerm)



in a different file (SearchBar.swift) I have the following code:


import Foundation
import SwiftUI

struct SearchBar: UIViewRepresentable {
   
    @Binding var text: String
   
    class Coordinator: NSObject, UISearchBarDelegate {
        @Binding var text: String
       
        init(text: Binding) {
            _text = text
        }
       
        func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
            text = searchText
        }
    }
   
    func makeCoordinator() -> SearchBar.Coordinator {
        return Coordinator(text: $text)
    }
   
    func makeUIView(context: UIViewRepresentableContext) -> UISearchBar {
        let searchBar = UISearchBar(frame: .zero)
        searchBar.delegate = context.coordinator
        return searchBar
    }
   
    func updateUIView(_ uiView: UISearchBar, context: UIViewRepresentableContext) {
        uiView.text = text
    }
}


I suppose that I have to change this code:


ForEach(userData.legals) { legal in  
                if !self.userData.showFavoritesOnly || legal.isFavorite {  
                    NavigationLink(  
                        destination: LegalDetail(legal: legal)  
                            .environmentObject(self.userData)  
                    ) {  
                        LegalRow(legal: legal)  

   


but I can't figure out how.


I already tried the following:


ForEach(userData.legals) {self.search.isEmpty ? true :
$0.localizedCaseInsensitiveContains(self.search)}, id:\.self {


Any help is appreciated 🙂

As always, you should better start a new thread (in the righttopic area: SwiftUI) if one issue is solved.

If you think nothing solved, you should continue this thread concentrating on the first issue.


And I have no idea about what is or how to solve your extra first issue.


Second, you need to modify your code a little, as shown in many guides found by "swiftui search bar":

            ForEach(userData.legals.filter {$0.matches(searchTerm)}) { legal in

                if !self.userData.showFavoritesOnly || legal.isFavorite {
                    NavigationLink(
                        destination: LegalDetail(legal: legal)
                            .environmentObject(self.userData)
                    ) {
                        LegalRow(legal: legal)
                    }
                }
            }

Just another example of using filter, which you should better master.


To use the code above, you need to define an extension of `Legal`:

extension Legal {
    func matches(_ searchTerm: String) -> Bool {
        return searchTerm.isEmpty
            || self.name.localizedCaseInsensitiveContains(searchTerm)
    }
}

You may need to modify this extension if you do not get the expected search results.

Thank you, this code worked.


In the future I will start a new post.