Advantage of Key-Value Coding in Swift 4 - swift

I just want to know the benefits of Key-Value Coding in Swift 4. As I am well aware of key-value coding (hold reference to properties without actually accessing the underlying data held by the property).
For Example:
struct Student {
var name: String?
var rollNo: String?
}
let student = Student(name: "aman", rollNo: "12121")
let nameKey = \Student.name
let name = student[keyPath: nameKey]
Here we created the the instance of Student and access the value by subscript (keyPath) but I can easily access the value by simply writing the code student.name.
In Objective-C, we use string as a key like given below and we could take some benefits from it
[object valueForKey:#"name"]
My question is that is there any benefits related to coding level or memory level?

Two key advantages are:
Keys are validated: Xcode will warn you, at compile time, if you try to use a key that is not valid.
Results are strongly typed: With the following, the compiler will know that the resulting name is a String:
let name = student[keyPath: nameKey]
This eliminates the need to do any casting.
The result is that it's much easier to write safe code.

Related

Storing CoreData attributes as (Codable) Data rather than (NSCoding) Transformables

I have arrays of simple structs that I would like to pack into a Core Data attribute. I don't need Core Data to handle each object independently, so packing into an array on one attribute seems fine and less overhead.
A complete solution might be to roll my own NSValueTransformer. I'd get full control over the process and storage. However, putting more work aside, since Swift 4 we now effectively have another approach to out-of-the-box serialization - storing objects as Data attributes, serialized by Swift 4's Codable protocol and (say) the JSONEncoder/JSONDecoder implementations. This would be an alternative to the more typical approach using a Transformable attribute serialized via the default NSValueTransformer under NSCoding.
An immediate advantage is not having to inherit from NSObject and conform to NSCoding, for what in my case are simple value types. This alone makes me want to start using Codable as my default approach. Clearly, using the JSON encoder would mean conversion and representation of data under utf8, even if Core Data/sqlite see this as Data/BLOBs. However from what I gather the default transformer to the (binary) plist format isn't exactly the most efficient, either.
Has anyone else taken this approach or otherwise know whether there may be any significant drawbacks or implications involved I’ve not considered? In short, could this be a reasonable approach?
I don't know if you still are looking for a solution to this issue, but here is an overview of a solution that I use. Assuming that aStruct: Codable, you can use this strategy.
In the core data model, I create a property such as encodedStructArray of type data for the desired entity.
Then in a swift extension for that entity, I create a computed read-write var with normal swift type:
var structArray: [aStruct] {
get {
guard let data = encodedStructArray else { return [] }
guard let result = try? JSONDecoder().decode([aStruct].self, from: data) else { return [] }
return result
}
set {
encodedStructArray = try? JSONEncoder().encode(newValue)
}
}
Now you can use the var just like you would anywhere but for performance reasons, pull it out and use that rather than using the var directly in multiple places since this example does not cache the value.
If you wish to cache the result, you would need to add a transient to the data model with the name structArray of undefined type and hold the cache value in its primitive. See the Core Data docs for an example.

Is it better to use dictionary instead of create a class

I used to do things like below:
class A {
var param1:String?
var param2:[B]?
}
class B {
var param1:String?
var param2:String?
var param3:[C]?
}
class C {
var param1:String?
var param2:String?
}
But recently I found that dictionaries are more flexible. Class A can be replaced by the following dictionary.
[
"param1":"some string",
"param2":[
"param1":"some string",
"param2":"some string",
"param3":[
"param1":"some string",
"param2":"some string"
],
[
...
...
]
],
[
...
...
],
...
]
If we want to add "param3" into class C, we need to modify a lot of associated code if using class. But if we use dictionaries, we can just use "param3" as if it already exists.
A dictionary is just like a runtime defined class. I am wondering should we use dictionaries to replace data storing classes (i.e. models in MVC pattern) in all situations.
It depends on the use you have of your model. Making small classes enables you to give each class a specific additional behavior (for example more specific isolated accessory methods or helpers).
You can also test the model more easily by using only the piece you want and mock the other.
In general splitting responsibility is better because of maintenance and testability and clear code.
If your dictionary grows out of control then it is going to be very difficult for a newcomer on your team to use and understand the giant blob of data, rather than handling a lot of small objects with relationships between themselves.
If you add a new parameter you might need to change a lot of initializers.
That is normal I would say.
Also it depends on how you manage the model initialization. Maybe you use a factory that hides this complexity for you inside the rest of your code.
Or maybe you will need just to change it in your dependency injection root.
It clearly depends on the approach and scope of the object you are creating.
But in my opinion isolated objects are more reusable than a big blob of data in a dictionary
I agree that dictionaries are more extensible, but classes are safer.
One big unsafe thing about dictionaries is that you don't know whether a key exist or not at compile time. You have to put guard let or if let statements all over the place whenever you want to access something. If you don't do this, the app will crash at runtime when the key does not exist. Sure, you can fix it after it crashed, but you wasted a lot of time running your app and making that erroneous line of code to run and crash.
The other unsafe thing is type-unsafety. Since your dictionary contains different types of stuff, It must be a [String: Any]. Normally you can do this with classes:
someAObject.param2!.first!.param3!.first!.param1
If you use dictionaries you need:
(((dict["param2"]! as! [[String: Any]]).first!["param3"] as! [[String: Any]]).first! as! [String: Any])["param1"]
Just look at how much more code that is! Also, when you want a method to accept a parameter, you can write A or B or C if you are using classes and the method will only accept the type you specify. If you are using dictionaries, all you can write is [String: Any]. There is no compile time check whether that dictionary is of the acceptable type.
The third thing is about typos. If you typed a property name wrong, Xcode will tell you that even before you run the app. If you typed a dictionary key wrong, Xcode will not tell you that. You have to run that bit of code to know. Sure, you can put keys into constants, but that is very troublesome and the trouble definitely overweighs what you call "benefits" of dictionaries.
The fourth point is that dictionaries are value types. You might want some of the features of reference types.
And last but not least, you cannot add methods to dictionaries! A very important feature of classes is that they allow you to add methods and you can call them on instances of the class. If you made good use of this, you can write very readable code.
If we want to add "param3" into class C, we need to modify a lot of associated code if using class
Not if you designed your model well. I can't think of a reason why adding a new property to a class would require you to change lots of associated code.

Swift 4 statically get value of model property name

When using Swift 3, I was defining my model like so
class Model: NSObject {
var prop1: String
}
When I wanted to access the static string value of the property name prop1, I would use let sad = #keyPath(Model.prop1) and it would give me "prop1" printed out. Happy days.
The problem is, that since upgrading to Swift 4, I am having trouble doing the above. I see in other posts that we can use the new \Model.prop1 syntax but that seems to be providing the value of property rather than the string representation of the name.
I am also refactoring out the need for NSObject on my Swift models, but I would have thought I can still get this functionality.
Any help here would be appreciated!
Swift properties do not necessarily retain the strings of the property names at runtime. Therefore, if the Swift key path syntax were able to give you this string value, it would only be able to be used on NSObject-derived classes. The Swift key path syntax doesn't only work with those, though; it can also be used to refer to properties of non-#objc classes and structs. Therefore, this is not possible. The #keyPath syntax remains available, however, to get the string key path of an Objective-C property.

Prefer optional or non-optional when designing domain?

While defining model for my application what properties should I declare as optional and what as non-optional? What aspects I need to consider?
E.g I want to create entity Car. What type engine should be?
struct Car {
let engine: Engine?
}
or
struct Car {
let engine: Engine
init(engine: Engine) {
self.engine = engine
}
}
or
struct Car {
let engine: Engine = Engine()
}
Introduction
Many of us (me included) were not familiar with this problem.
Infact Objective-C (and many other languages like C, Java 1...7, etc...) forced a variable with a primitive type (Int, Double, ...) to always be populated.
And they also always forced a reference/pointer variable to always be potentially nil.
Se over the years we just adapted to these constraints.
Initially many Swift developers used implicitly unwrapped optionals
var something: Something!
This is the closest thing to declaring a reference variable in a way that behave similarly to the programming languages mentioned above but this way we don't really use the power of Optionals.
When should I declare a property of my model as optional?
The question you have to ask yourself is
In my data domain, can this entity exist and have no value for this specific property?
If the answer is no, then the property should be declared as non optional.
Example
A User struct representing the user of an app will always have a username and password populated.
struct User {
let username: String
let password: String
let profileImageURL: NSURL?
}
On the other hand it could have a nil value for profileImageURL maybe because the user didn't upload a profile picture.
In this case a User value without a username just doesn't make sense, it can't happen and when dealing with a User value we should always have the guarantee (provided by the compiler) that there is username value in it.
So we make username non optional
It really depends on the domain
The "optionality" of the property of an Entity can differ from data domain to data domain.
E.g. this entity for a mailing list system
struct Person {
let name: String?
let email: String
}
makes sense because we could not know the name but we know for sure its email address.
On the other hand the same entity in another context like an Address Book could become
struct Person {
let name: String?
let email: String?
}
because maybe we created/saved an empty card.
Thumb of rule
As personal advice I suggest you to avoid optional values when you have doubts about it. If you declared a non optional property something that should actually be optional the problem will come up very soon.
On the other hand if you declared optional something that should be non optional you could never find out.
Important
And of course NEVER use a value of the domain of the property/variable to represent the absence of value
let birthyear = -1 // 😨
let name = "" // 😰
let username = "NOT_PROVIDED" // 😱

Is it possible to use optionals for members in structures or classes in Swift?

I'm having a difficulty reconciling my admittedly incomplete understanding of optionals and this from the Swift 2.1 documentation:
Classes and structures must set all of their stored properties to an
appropriate initial value by the time an instance of that class or
structure is created. Stored properties cannot be left in an
indeterminate state.
I'd like to be able to do something like:
struct Name {
var firstName = "Flintstone First"
var middleName: String?
var lastName = "Flintstone"
}
var wilmaHusband: Name
wilmaHusband.firstName = "Fred"
where middleName may be nil. However, quite understandably according to that part of the Swift documentation, I encounter the error Struct wilmaHusband must be completely initialized before a member is stored...
Is what I'm trying to do--make a member potentially nil in a structure (or class) impossible in Swift? If so, it seems one seeming advantage of optionals--that they may hold the kind of data that may or may not be present in a structured object (such as a middle name in a name construct)--is lost.
I feel like I'm missing something fundamental here in my understanding of optionals, and I apologize in advance for my naïveté.
Since all members of the struct have an initial value
(including var middleName: String? which – as an optional – is
implicitly initialized to nil), you can create a variable of that
type simply with
var wilmaHusband = Name()