0

I have decided after several years of development to restart my project using SwiftUI to future proof as much as I can.

In my current project I have my data in several .CSV's which I then process into dictionaries and then create a list of entries on screen using an Array of keys which are generated programmatically from user input.

All examples I've seen for SwiftUI use JSON. However the structure of these files are identical to an Array of Dictionaries. My question is; is it possible to create a Struct of a dictionary entry to pass in a forEach watching an Array of Keys (data inside the dictionary will never change and I am not looking to iterate or watch the dictionary).

My main goal is to reuse as much as possible but am willing to change what I have to get full benefit of SwiftUI. Obviously if I change the way I store my data almost everything will be useless. If there's a real benefit to converting my data to JSON or even start using something like CoreData I will.

3
  • Do you intend to use ‘ForEach’ in SwiftUI? Commented Jun 14, 2020 at 0:37
  • Yes. Either ForEach or List. I believe they work in similar ways. My intended implementation is to pass an Array of Keys to watch that then retrieves the Dictionary Entry for that Key and finally (hopefully) using a Struct to process the information in the Dictionary Entry creating an entry for my List. I worry I haven't quite got a grip of the full process I'm explaining above. Hence my question. Commented Jun 14, 2020 at 1:52
  • You can make your struct in the array conform to ‘Identifiable’. Then ‘ForEach’ can automatically handle the reuse stuff. Commented Jun 14, 2020 at 2:00

1 Answer 1

1

If I'm understanding correctly, you are looking to

  1. Take some user input
  2. Transform that into keys that correspond to your data dictionary
  3. Extract the data for the matching keys into some struct
  4. Display a list of those structs using SwiftUI

Here is a simple implementation of those steps.

import SwiftUI

// A dictionary containing your data
let data: [String: Int] = [
    "apples": 5,
    "bananas": 3,
    "cherries": 12
]

// A struct representing a match from your data
struct Item {
    var name: String
    var quantity: Int
}

// A view that displays the contents of your struct
struct RowView: View {
    var item: Item

    var body: some View {
        Text("\(item.quantity) \(item.name)")
    }
}

struct ContentView: View {
    @State private var searchText: String = ""

    func items(matching search: String) -> [Item] {
        // 2 - split the user input into individual keys
        let split = search.split(separator: " ", omittingEmptySubsequences: true).map { $0.lowercased() }
        // 3 - turn any matching keys/values in your dictionary to a view model
        return split.compactMap { name in
            guard let quantity = data[name] else { return nil }
            return Item(name: name, quantity: quantity)
        }
    }

    var body: some View {
        VStack {
            // 1 - get user input
            TextField("Search", text: $searchText)
                .padding()
            // 4 - display the matching values using ForEach (note that the id: \.name is important)
            List {
                ForEach(items(matching: searchText), id: \.name) { item in
                    RowView(item: item)
                }
            }
        }
    }
}

You'll see that as you type in the text field, if you enter any of the strings "apples", "bananas", or "cherries", a corresponding row will pop into your list.

Depending on the size of your list, and what kind of validation you are performing on your users search queries, you might need to be a little more careful about doing the filtering/searching in an efficient way (e.g. using Combine to only split and search after the user stops typing).

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.