How to create property from the path - swift

I need to manipulate properties of the dictionary from taking path to that property like 'a.b.c' and setting property value. I have root object 'obj' (NSObject derived) that has property named 'a' of the type of NSObject derived class. That class has property named 'b' that is dictionary var map = [String: CGFloat]() and 'c' is key name in the dictionary. If I call obj.setValue(value, forKeyPath: 'a.b.c') it works fine if property in dictionary exist. I would like to automatically create that property if it doesnt. Is there way?

setValue(_:forKeyPath:) is not a dictionary method, it is an NSObject method.
Implement setValue(_:forUndefinedKey:) and store the key-value pair yourself. Also need to implement value(forUndefinedKey:) for obtaining the value.

Related

Add New Key/Value to Dictionary

I have a dictionary of type [String: [String]] and is loaded as blank [ : ].
Is there a way I can append a value to the array associated to a new string key? (i.e. exampleDict["test"].append("test"))
When I print out the dictionary after attempting this, I am returned [ : ], which I believe is because the key does not exist and returns as nil.
Swift has a neat "default" feature for doing things exactly like this.
exampleDict["test", default: []].append("test")
If exampleDict["test"] is nil, the default is returned instead. If you modify the returned default object, that modification goes into the dictionary.
Unfortunately this only works properly for value types, since classes aren't reassigned when they're mutated. Fortunately, Array is a value type, so this will work perfectly here.
You have to use Dictionary.subscript(_:default:).
exampleDict["test", default: []].append("test")

Conditional Defining a property in model object

I have a model object and there are some properties in that object. Based on some conditions, I want a property to be defined there or not to be defined. For example, this property is my app version.
class Person {
var name: String
var address: String
var age: String
// I want some condition here like if myAppVersion > 1.0 then add isChild
// property to my model object other wise don't add that
var isChild: Bool
// Normal property again
var gender: String
}
I want this behaviour because the properties are coming from the backend and all these properties are required, so if, for some reason, the BE doesn't send the a required property which the client is expecting, then I will crash. These properties have to be mandatory and not optional.
Don't do this.
Declare your parameter as an optional and set it to nil if you don't want it to have a value. You should create two separate classes if you want to have different implementations, but that would be pretty superfluous for just one little change.
If your application crashes just because a property has a nil value, you should really take a look at optional handling in Swift and nullability in Objective-C.

Swift static property initilizers are lazy why I could declared it as a constant

As far as I known (see reference A), Static property initilizers are lazy, and I found the following description by the office documents
You must always declare a lazy property as a variable (with the var
keyword) because its initial value might not be retrieved until after
instance initialization completes. Constant properties must always
have a value before initialization completes, and therefore cannot be
declared as lazy.
From the above information, I think I couldn't define the static property as a constant variable and I made a tryout, it turns out I can do that without triggering any error from the compiler.
Example:
class Person {
static let firstNaID = "First Name"
static let lastNaID = "Last Name"
}
Question: Is this a bug of the Swift 3.0.1 or I was wrong.
Reference A: Neuburg. M.2016. IOS 10 Programming Fundamental with Swift. P127
Thanks for your time and help
Neuburg M. is drawing a distinction between static properties and instance properties. You are pretending to ignore that distinction. But you cannot ignore it; they are totally different things, used for different purposes.
In this code:
class Person { // let's declare a static property
static let firstNaID = "First Name"
}
... firstNaID is already lazy. But now try to do this:
class Person { // let's declare an instance property
lazy let firstNaID : String = "First Name" // error
}
You can't; as things stand (up thru Swift 3.1), you have to say lazy var instead — and when you do, you get a lazy instance property.
Your static let declaration thus doesn't accomplish what lazy let wanted to accomplish, because a static property is not an instance property.
You are talking about type properties
Form the same chapter of the documentation
Type Properties
... Type properties are useful for defining values that are universal to all instances of a particular type, such as a constant property that all instances can use ...
Stored type properties can be variables or constants. Computed type properties are always declared as variable properties, in the same way as computed instance properties.
NOTE
...
Stored type properties are lazily initialized on their first access. They are guaranteed to be initialized only once, even when accessed by multiple threads simultaneously, and they do not need to be marked with the lazy modifier.

What is the syntax to store a Class as a value in a Dictionary in Swift?

Lets say I want to do this:
class foobar : NSObject {
//method declarations, etc.
}
Then later:
let myDictionary:Dictionary = ["returnMeAnAwesomeClass":foobar]
Does not work.
If I put in foobar.Type, it also doesn't work.
If I put in foobar.class as foobar.Type, it also doesn't work.
The reason I want this is because there's a method in a system API that takes a class as the argument, e.g.:
func enterState(_ stateClass: AnyClass) -> Bool
(in GKStateMachine)
I'd find it acceptable to be able to get a string and turn that into a class.
You can use foobar.self if you need to obtain the class type. And also you should add type safety to your dictionary:
let myDictionary: [String:AnyClass] = ["returnMeAnAwesomeClass": foobar.self]
If you're initializing the dictionary at the same place where you're declaring it, you can skip the type declaration, as the compiler will infer it:
let myDictionary = ["returnMeAnAwesomeClass": foobar.self]

Swift Spritekit setvalue

In swift with spritekit I want to set a variable of a sprite so I tried to say
p.setValue(value: (String(c)), forKey: "co")
But this gives an error.
So the main question is:
How can i set a key value pair in a sprite to a string
as a key and an int/string as a value?
setValue(_:forKey:) and related methods aren't for associating arbitrary key/value data with an object. They're part of Key-Value Coding, a Cocoa feature that does all sorts of handy things — but unless a class does something special with KVC, all setValue(_:forKey:) does is let you set one of that class's declared properties using a string instead of by directly accessing a property. In other words, the two lines below are equivalent:
node.name = "foo"
node.setValue("foo", forKey: "name")
If you want to associate arbitrary key-value pairs with your sprites—which can be a great way to keep track of entities in your game—use the userData property.
To use setValue:forKey: you need to have (a) a valid key, and (b) a value of the correct type for that key. For example:
mySprite.setValue(UIColor.redColor(), forKey: "co") // error, "co" isn't a valid key
mySprite.setValue("red", forKey: "color") // error, "color" needs a UIColor value
mySprite.setValue(UIColor.redColor(), forKey: "color") // works!
What value and key are you actually using?