Home > Enterprise >  String as Member Name in Swift
String as Member Name in Swift

Time:03-14

I have an array of strings and a CoreData object with a bunch of variables stored in it; the strings represent each stored variable. I want to show the value of each of the variables in a list. However, I cannot find a way to fetch all variables from a coredata object, and so instead I'm trying to use the following code.

ListView: View{
//I call this view from another one and pass in the object.
let object: Object
//I have a bunch of strings for each variable, this is just a few of them
let strings = ["first_name", "_last_name", "middle_initial" ...]


var body: some View{

List{

ForEach(strings){ str in
//Want to pass in string here as property name
object.str
//This doesn't work because string cannot be directly passed in as property name - this is the essence of my question.

}

}

}

}

So as you can see, I just want to pass in the string name as a member name for the CoreData object. When I try the code above, I get the following errors: Value of type 'Object' has no member 'name' and Expected member name following '.'. Please tell me how to pass in the string as a property name.

CodePudding user response:

Swift is a strongly typed language, and iterating in a python/javascript like approach is less common and less recommended. Having said that, to my best knowledge you have three ways to tackle this issue.

First, I'd suggest encoding the CoreData model into a dictionary [String: Any] or [String: String] - then you can keep the same approach you wanted - iterate over the property names array and get them as follow:

let dic = object.asDictionary()
ForEach(strings){ str in
//Want to pass in string here as property name
let propertyValue = dic[str]
//This doesn't work because string cannot be directly passed in as property name - this is the essence of my question.

}

Make sure to comply with Encodable and to have this extension

extension Encodable {
  func asDictionary() throws -> [String: Any] {
    let data = try JSONEncoder().encode(self)
    guard let dictionary = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any] else {
      throw NSError()
    }
    return dictionary
  }

Second, you can hard coded the properties and if/else/switch over them in the loop

ForEach(strings){ str in
//Want to pass in string here as property name
switch str {
  case "first_name":
   // Do what is needed

}

}

Third, and last, You can read and use a technique called reflection, which is the closest thing to what you want to achieve link1 link2

CodePudding user response:

CoreData is heavily based on KVC (Key-Value Coding) so you can use key paths which is much more reliable than string literals.

let paths : [KeyPath<Object,String>] = [\.first_name, \.last_name, \.middle_initial]

...

ForEach(paths, id: \.self){ path in
   Text(object[keyPath: path]))
}
  • Related