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
Siblings Relationship Between Same Models in Vapor
Tvos Button Inside Navigationlink Is Not Working
Swift: Guard Let and Where - The Priority
Flattened Objects in JSON File to Nested Object Structure in Swift
Is There an Firebase Realtime Database Equivalent to The Increment Method Available in Firestore
Swiftui New App Lifecycle How to Connect The Facebook Sdk
Calculate Range of String from Word to End of String in Swift
How to Resize an Image That Is Being Printed
Cannot Convert Value of Type 'Foo!' to Expected Argument Type 'Foo!'
Swift Video to Document Directory
What Is The Reason to Store Subscription into a Subscriptions Set
Swiftui Go Back Programmatically from Representable to View
Urlcomponents Queryitems Losing Percent Encoding When Mutated
How to Draw an Image in an Nsopenglview with Swift
Aws Cognito Credentialsprovider.Login Always Shows Nil (Swift)