Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to create a generic function with textfield inputs in Swift

I’m trying to create a button with a generic function that chooses random elements from an array , checks if the textfield input matches the correct words associated with a particular element from the array then returns true if it does. Please see my code to understand this better

my head is burning trying to make this a generic approach please advise guys.

I just want a button that i can add more cards to the view. Lets say i don’t want just variables i want to create another set of instructions with constants or integers

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

//MARK: LOGIC

import Foundation
import Observation


@Observable
class VariablesViewModel {
    var textField = ""
    private var words = ["\"Hello\"","\"Hello \"" ,"\"hello\"", "\" Hello\"", "\"      hello\""]
    
    func wordMatch() -> Bool {
        words.contains(where: textField.contains)
    }
}



//MARK: VIEW 


import SwiftUI

struct Variables: View {
    @State var viewModel = VariablesViewModel()
    var body: some View {
        VStack(alignment: .leading, spacing: 40) {
          Text("Create a variable called \"greeting\" and assign the value     \"Hello\".")
                .font(.title2)
                .fontWeight(.semibold)
            HStack {
                Text("1")
                    .font(.title2)
                    .foregroundStyle(.gray)
                Text("var")
                    .font(.title2)
                    .foregroundStyle(.pink)
                Text("greeting =")
                    .font(.title2)
                TextField(text: $viewModel.textField ) {
                    Text("Tap to assign \"Hello\"")
                        .font(.title2)
                }
                .font(.title2)
                .foregroundStyle(.orange)
                if viewModel.wordMatch() {
                    Image(systemName: "checkmark.circle.fill")
                        .imageScale(.large)
                        .foregroundStyle(.green)
                }
            }
        }
        .alignment(.topLeading)
    }
}
#Preview {
    Variables()
}


extension View {
    @ViewBuilder func alignment(_ alignment: Alignment) -> some View {
        self.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: alignment)
    }
}

>Solution :

Here is one way to make the view model generic where you pass both the array values and a matching logic closure at init

class VariablesViewModel<Value> {
    var input: Value?
    var matcher: (Value, [Value]) -> Bool
    private var values: [Value]

    init(values: [Value], matcher: @escaping (Value, [Value]) -> Bool) {
        self.matcher = matcher
        self.values = values
    }

    func valueMatch() -> Bool {
        guard let input else { return false }
        return matcher(input, values)
    }
}

Examples

let viewModel = VariablesViewModel(values: ["Hello","Hello " ,"hello", " Hello", "      hello"]) {
    $1.contains(where: $0.contains)
}

let viewModel2 = VariablesViewModel(values: [1,3,5,7,9]) {
    $1.contains($0)
}

Personally I would prefer to pass the value to match rather than having it as a property, in your view it would then be a @State property instead than a view model property

class VariablesMatcher<Value> {
    var matcher: ([Value], Value) -> Bool
    private var values: [Value]

    init(values: [Value], matcher: @escaping ([Value], Value) -> Bool) {
        self.matcher = matcher
        self.values = values
    }
    func valueMatch(input: Value) -> Bool {
        return matcher(values, input)
    }
}

Examples

let matcher1 = VariablesMatcher(values: ["Hello","Hello " ,"hello", " Hello", "      hello"]) {
    $0.contains(where: $1.contains)
}
matcher1.valueMatch(input: "Hello")

let matcher2 = VariablesMatcher(values: [1,3,5,7,9]) {
    $0.contains($1)
}
matcher2.valueMatch(input: 3)

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading