Dynamically Set Properties from Dictionary<String, Any> in Swift

Dynamically set properties from DictionaryString, Any? in Swift

This is possible with the NSKeyValueCoding method
setValuesForKeysWithDictionary which calls setValue:forKey: for each key-value pair in the
dictionary:

let config: [String : AnyObject] = [
"frame": NSValue(CGRect: CGRectZero),
"hidden" : true,
"backgroundColor": UIColor.whiteColor(),
"autoresizingMask" : UIViewAutoresizing.FlexibleHeight.rawValue
]
self.view.setValuesForKeysWithDictionary(config)

But note that all values must be Objective-C objects, which is why the frame
is wrapped into an NSValue object.
More about struct and scalar support in Key-Value Coding can be found
here.

Some types (such as Bool, Int) are automatically bridged to NSNumber, therefore
the true value for the hidden attribute needs not to be wrapped.
"options" such as UIViewAutoresizing must be converted to the underlying
integer value (which is then bridged to NSNumber automatically).

Swift dynamic property setting based on array keys

I want to expand on the example given by @Okapi. If your class is a subclass of NSObject, then the setValue:forKey: and valueForKey: method are present by default. So, you could simply set your properties using the following code,

class Foo: NSObject {
var x:String=""
var y:String=""
var z:String=""
init(data: Dictionary<String,String>) {
super.init()
for (key,value) in data {
self.setValue(value, forKey: key)
}
}
}

Dynamically create objects and set attributes in swift

I think that this is what you want:

@objc(MyClass)
class MyClass : NSObject {
var someProperty = 0
}

let type = NSClassFromString("MyClass") as! NSObject.Type
let instance = type()
instance.setValue(12, forKey: "someProperty")

Swift iOS - How to dynamically add properties to an existing class then access them

Using the suggestion from @DonMag in the comments he gave me a great alternative. He suggested I create a dictionary as a property on the class then add the key,value pairs to it.

class Order {

var orderId: String?

var dynamicDict = [String: Any]()

convenience init(dict: [String: Any]) {
self.init()

orderId = dict["orderId"] as? String

createDynamicKeyValues(dict: dict)
}

func createDynamicKeyValues(dict: [String: Any]) {

for (key, value) in dict {

if key.contains("+") {

dynamicDict.updateValue(value, forKey: key)
}
}
}
}

To use it:

let dict = ["orderId":"abc", "postId+0":"zero", "postId+1":"one", "postId+2":"two"] // postIds can go on

let order = Order(dict: dict)

for (key, value) in order.dynamicDict {
print(key)
print(value)
}

Get instance attributes dynamically Swift 3

This is Key-Value Coding:

user.setValue("user_name@domain.com", forKey:"email")
print(user.value(forKey:"email"))

Dynamically defining class properties in Swift

I think there is some confusion about what static means, and it probably stems from class Member being nested in class Population. All nesting types do is enclose the nested type in a namespace, which helps a) avoid name collision on types in global scope, and b) enables you to hide it as an implementation detail of the type in which it is nested, if you choose to make it a private type.

A nested type does not belong to an instance of the enclosing type. So if you define language as a static property of Member, then it has one value for class Member, regardless of how many instances of Population you have with different languages.

What you want is for each instance of Member to have the language of the Population to which it belongs. You can accomplish that a couple of different ways, but they all involve storing something in Member.

Option 1. Make language an instance property of Member, and set it in Member.init(language: String).

Option 2. Store a reference to the Population to which the Member belongs (I'll assume it's let population: Population), and make language a computed property which returns population.language.

Option 2 is more flexible, because you can leverage having the population to fetch other Member values that it gets from its Population, but it requires some careful consideration. Does it make sense in your app for a Member to exist outside of a Population? If yes, then you probably want to define it like weak var population: Population?. If no, a Member cannot exist outside of a Population, then unowned let population: Population could be preferred (though the weak version could be used too). The point here is to avoid reference cycles that would cause a memory leak.

So maybe something like this:

class Population {
var language: String
var members: [Member] = []

init(language: String) {
self.language = language
for _ in 1...10 {members.append(Member(population: self))}
}

class Member {
unowned let population: Population
var language: String { population.language }

init(population: Population) { self.population = population }

func speak() {
switch self.language {
case "english": print("speak some English")
case "german" : print("spreche ein Bißchen deutsch")
// other cases go here
default: print("mmmm mmmm mmm mmm") // I'm a mute
}
}

func write() {
switch self.language {
case "english": print("write some English")
case "german" : print("schreibe ein Bißchen deutsch")
// other cases go here
default: print("h8hta;lushgaih9732 8@#Y"); // Can't write
}
}
}
}

Though off-topic, I would recommend making language an enum, Then you can remove the default cases from the switch statements, and the compiler will helpfully, though not tactfully, show you all of the switch statements that need to be updated when you add a new language. If you like you can even make the enum based on String so you can still access the String value wherever that might be useful:

    enum Language: String
{
case arabic = "arabic"
case chinese = "chinese"
case english = "english"
case french = "french"
case german = "german"
case japanese = "japanese"
case portuguese = "portuguese"
case spanish = "spanish"
// etc...
}

Then if you want the string value you can refer to language.rawValue

Swift Observe dynamic dictionary

Here is a possible approach - make PlayerScore as a observable class, so PlayersScore will be updated only when new player added, and due to observed specific PlayerScore explicitly only corresponding view will be updated on value changes.

class PlayerScore: ObservableObject {
var id: String // say back ref to user

@Published var value: Int
// ... other published properties
}

struct PlayerView: View {
var player: Player
@ObservedObject private var scores = Api.shared.scores

var body: some View {
HStack {
Text(player.name)
if let score = scores.scores[player.id] {
PlayerScoreView(playerScore: score)
} else {
Text("No scores")
}
}
}
}

struct PlayerScoreView: View {
@ObservedObject var playerScore: PlayerScore

var body: some View {
Text("Latest score: \(playerScore.value)")
}
}

Note: this is just a sketch coded here, so might be typo



Related Topics



Leave a reply



Submit