Swift keyPath vs protocol - swift

I understand the basic idea of keyPaths but I do not understand its use cases. If you already know the type of the instance, you can access their properties easily. If you don’t, protocol already supports read-only, read-write properties. Can someone explain me what I am missing? Anything that we can’t do with protocols but keyPaths or when keypaths are better than protocols?

If you already know the type of the instance, you can access their properties easily. If you don’t, protocol already supports read-only, read-write properties. Can someone explain me what I am missing?
What you're missing is a sense of what's unknown.
In both your sentences you speak of knowing what the instance's properties are. That's not the problem key paths solve. Key paths have nothing to do with knowing the type; they are not in any kind of opposition to types or protocols. On the contrary, before you can use a key path, you have to know exactly what the instance's properties are.
Key paths are for when what is unknown is which property to access. They provide a way to pass a property reference so that someone else can be told to access that property.
For example, here's a Person type:
struct Person {
let firstName : String
let lastName : String
}
And here is a function that sorts an array of Persons by either the firstName or the lastName, without knowing which one to sort by:
func sortArrayOfPersons(_ arr:[Person], by prop: KeyPath<Person, String>) -> [Person] {
return arr.sorted { $0[keyPath:prop] < $1[keyPath:prop] }
}
A key path is how you tell this function what property to use as a basis for sorting.

Related

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.

Advantage of Key-Value Coding in Swift 4

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.

When should I use optionals and when should I use non-optionals with default values?

I know the recommended way in Swift is to use:
class Address {
var firstLine : String?
var secondLine : String?
}
but sometimes I see other developers write their code this way:
class Address {
var firstLine : String = ""
var secondLine : String = ""
}
Is this the unrecommended way because whenever you have nil you will just crash and there's no outlet for your to recover. Is that right? Or there are some use cases where using non-optionals with default can be good. If so then where?
I saw this other question which is asking about efficiency rather than which better suits your needs. I'm looking for an answer where it says "This is a good place to use non-optionals and this is a good place to use optionals". Sometimes I see folks just dump optionals everywhere and it makes me think do we not ever need non-optionals? Sometimes I see people trying to avoid optionals as much as possible and just code in an Objective-C kind of style.
The above question's answer doesn't represent a valid case for where non-optionals are good. It's mute about that. As for choosing optionals: I'm guessing for models which get populated by network calls, optionals are the right choice, because you don't know whether it's nil or not.
The choice depends on what you model.
If a property of the object that you model may be absent completely, e.g. a middle name, a name suffix, an alternative phone number, etc., it should be modeled with an optional. A nil optional tells you that the property is not there - i.e. a person does not have a middle name or an alternative phone number. You should also use optional when you must distinguish between an empty object and a missing object.
If a property of the object must be set, and has a meaningful default, use an non-optional with a default:
class AddressList {
var addresses : [Address]
var separator : String = ";"
...
}
If users of your class need to change the separator, they have a way to do that. However, if they do not care about the separator, they can continue using the default without mentioning it in their own code.
Well you should use optionals if you think that the variable might not have a value. But if you're really sure that it's gonna have a value then you don't need to use them.
So only use non-optionals if you're sure that the variable will have a value else use optionals.

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" // 😱

How to share a Dictionary instance in Swift?

According to the Swift Programming Language reference, Dictionary instances are copied whenever they are passed to a function/method or assigned to a constant or variable. This seems inefficient. Is there a way to efficiently share the contents of a dictionary between two methods without copying?
It's true the documentation says that but there are also various notes saying it won't affect the performance. The copying will be performed lazily - only when needed.
The descriptions below refer to the “copying” of arrays, dictionaries, strings, and other values. Where copying is mentioned, the behavior you see in your code will always be as if a copy took place. However, Swift only performs an actual copy behind the scenes when it is absolutely necessary to do so. Swift manages all value copying to ensure optimal performance, and you should not avoid assignment to try to preempt this optimization.
Source: Classes & Collections
Meaning - don't try to optimize before you actually encounter performance problems!
Also, don't forget that dictionaries are structures. When you pass them into a function, they are implicitly immutable, so no need for copying. To actually pass a mutable dictionary into a function, you can use an inout parameter and the dictionary won't be copied (passed by reference). The only case when a mutable dictionary passed as a parameter will be copied is when you declare the parameter as var.
You always have the option to define a custom, generic class with a Dictionary attribute:
class SharedDictionary<K, V> {
var dict : Dictionary<K, V>
// add the methods you need, including overloading operators
}
Instances of your SharedDictionary will be passed-by-reference (not copied).
I actually talked to someone on the Swift team today about "pass by reference" in Swift. Here is what I got:
As we all know, struct are pass by copy, classes are pass by
reference
I quote "It is extremely easy to wrap a struct in a class.
Pointing to GoZoner's answer.
Even though though a struct is copied, any classes defined in
the struct will still be passed by reference.
If you want to do traditional pass by reference on a struct, use
inout. However he specifically mentioned to "consider adding in
another return value instead of using inout" when saying this.
Since Dictionary defines KeyType and ValueType as generics:
struct Dictionary<KeyType : Hashable, ValueType>
I believe this means that if your KeyType and ValueType are class objects they will not be copied when the Dictionary itself is copied, and you shouldn't need to worry about it too much.
Also, the NSDictionary class is still available to use!
As other said "Swift only performs an actual copy behind the scenes when it is absolutely necessary to do so." so performance should not be a big problem here. However you might still want to have a dictionary passed by reference for some other reasons. In that case you can create a custom class like below and use it just like you would use a normal dictionary object:
class SharedDictionary<K : Hashable, V> {
var dict : Dictionary<K, V> = Dictionary()
subscript(key : K) -> V? {
get {
return dict[key]
}
set(newValue) {
dict[key] = newValue
}
}
}
Trust the language designers: the compiler is usually smarter than you think in optimizing copies.
You can hack around this, but I don't frankly see a need before proving it's inefficient.