In SwiftUI, what's the different ForEach without Identifier and with Identifier? - swift

In SwiftUI, in the ViewBuilder, we have to use ForEach instead of for.
However, there are two ways of doing i.e.
ForEach(1...count, id:\.self)
and
ForEach(1..<(count+1))
Other than the syntax being different, is there any different use case for them?

Joakim has answered your question in the comments.
The second listed alternative can be used as long as the datatype being referenced is Identifiable. That means it is a class or has been declared as conforming to the Identifiable protocol. You can get Identifiable almost for free on your own objects by declaring conformance. The compiler will help you if you say you conform but don't, so that's a good place to start.
From Apple's Online Documentation:
Identifiable provides a default implementation for class types (using ObjectIdentifier), which is only guaranteed to remain unique for the lifetime of an object. If an object has a stronger notion of identity, it may be appropriate to provide a custom implementation.
The first alternative exists for cases when it doesn't conform to Identifiable.

Related

Relation between Existential Container and struct instance which conform protocol

I'm trying to understand how to find protocol method's implementation.
I know that Swift uses an Existential Container for fixed-size storage in Stack memory which manages how to describe an instance of a struct in memory. and it has a Value Witness Table (VWT) and Protocol Witness Table (PWT)
VWTs know how to manage real value in instance of struct (their lifecycle) and PWTs know the implementation of protocol's method.
But I want know the relation between the instance of a struct and the "existential container".
Does an instance of struct have a pointer which refers to an existential container?
How does an instance of a struct know its existential container?
Preface: I don't know how much background knowledge you have, so I might over-explain to make sure my answer is clear.
Also, I'm doing this to the best of my ability, off by memory. I might mix up some details, but hopefully this answer could at least point you towards further reading.
See also:
https://stackoverflow.com/a/41490551/3141234
https://github.com/apple/swift/blob/main/docs/SIL.rst#id201
In Swift, protocols can be used "as a type", or as a generic constraint. The latter case looks like so:
protocol SomeProtocol {}
struct SomeConformerSmall: SomeProtocol {
// No ivars
}
struct SomeConformerBig: SomeProtocol {
let a, b, c, d, e, f, g: Int // Lots of ivars
}
func fooUsingGenerics<T: SomeProtocol>(_: T) {}
let smallObject = SomeConformerSmall()
let bigObject = SomeConformerBig()
fooUsingGenerics(smallObject)
fooUsingGenerics(bigObject)
The protocol is used as a constraint for type-checking at compile time, but nothing particularly special happens at runtime (for the most part). Most of the time, the compiler will produced monomorphized variants of the foo function, as if you had defined fooUsingGenerics(_: SomeConformerSmall) or fooUsingGenerics(_: SomeConformerBig) to begin with.
When a protocol is "used like a type", it would look like this:
func fooUsingProtcolExistential(_: SomeProtocol) {}
fooUsingGenerics(smallObject)
fooUsingGenerics(bigObject)
As you see, this function can be called using both smallObject and bigObject. The problem is that these two objects have different sizes. This is a problem: how will the compiler know how much stack space is necessary to allocate for the arguments of this function, if the arguments can be different sizes? It must do something to help fooUsingProtcolExistential accommodate that.
Existential containers are the solution. When you pass a value where a protocol type is expected, the Swift compiler will generate code that automagically boxes that value into an "existential container" for you. As currently defined, an existential container is 4 words in size:
The first word is a pointer to the Protocol Witness Table (more on this later)
The next three words are inline storage for the value.
When the value being stored is less than 3 words in size (e.g. SomeConformerSmall), the value is packed directly inline into that 3 word buffer. If the value is more than 3 words in size (e.g. SomeConformerSmall), a ARC-managed box is allocated on the heap, and the value is copied into there. A pointer to this box is then copied into the first word of the existential container (the last 2 words are unused, IIRC).
This introduces a new issue: suppose that fooUsingProtcolExistential wanted to forward along its parameter to another function. How should it pass the EC? fooUsingProtcolExistential doesn't know whether the EC contains a value-inline (in which case, passing the EC just entails copying its 4 words of memory), or heap-allocated (in which case, passing the EC also requires an ARC retain on that heap-allocated buffer).
To remedy this, the Protocol Witness Table contains a pointer to a Value Witness Table (VWT). Each VWT defines the a standard set of function pointers, that define how the EC can be allocated, copied, deleted, etc. Whenever a protocol existential needs to be manipulated in someway, the VWT defines exactly how to do so.
So now we have a constant-size container (which solves our heterogeneously-sized parameter passing problem), and a way to move the container around. What can we actually do with it?
Well at a minimum, values of this protocol type must at least define the required members (initializers, properties (stored or computed), functions and subscripts) that the protocol defines.
But each conforming type might implement these members in a different way. E.g. some struct might satisfy a method requirement by defining the method directly, but another class might satisfy it by inheriting the method from a superclass. Some might implement a property as a stored property, others as a computed property, etc.
Handling these incompatibilities is the primary purpose of the Protocol Witness Table. There's one of these tables per protocol conformance (e.g. one for SomeConformerSmall and one for SomeConformerBig). They contain a set of function pointers with point to the implementations of the protocols' requirements. While the pointed-to functions might be in different places, the PWT's layout is consistent for the protocol is conforms to. As a result, fooUsingProtcolExistential is able to look at the PWT of an EC, and use it to find the implementation of a protocol method, and call it.
So in short:
An EC contains a PWT and a value (inline or indirect)
A PWT points to a VWT
My understanding:
Struct doesn't know where existential container/value witness table/protocol witness table is, the compiler knows. If needed somewhere, compiler pass them to there.

What is the use of hashable protocol in swift4?

please explain the use of hashable protocol with implementation in swift.
Apple defines hashable as “a type that provides an integer a hash value.” Okay, but what’s a hash value?
To make an object conform to Hashable we need to provide a hashValue property that will return a unique, consistent number for each instance.
The Hashable protocol inherits from Equatable, so you may also need to implement an == function.
Note: If two objects compare as equal using == they should also generate the same hash value, but the reverse isn’t true – hash collisions can happen.
Before Swift 4.1, conforming to Hashable was complex because you needed to calculate a hashValue property by hand.
In Swift 4.1 this improved so that hashValue could be synthesized on your behalf if all the properties conform to Hashable .
Swift 4.2 introduces a new Hasher struct that provides a randomly seeded, universal hash function to make all our lives easier. Refer for more
Quick answer:
We use hash integer into object to be able to quickly identify object that are equals by getting the object instance in front of the index that we are looking for.
Not quick answer:
When you are dealing with list in order to find an object you need to iterate over all your array and compare property to find the one you are looking for, this can slowdown your app as the list get bigger.
When you use SET, the mechanism under the hood use hash indexes to find an object so it take you only the time to calculate once the index you are looking for then you can access straight forward to your object, THIS IS SO COOL ISN'T.
In order to use SET the object need to conform to Hashable protocol since Swift 4.1, if your class or struct and all properties conform to Hashable then the conformity with Hashable and Equatable protocol is automatically done for you under the hood.
If you do not meet those requirments then you will have to make sure that you conform to Equatable and Hashable protocol.
Equatable protocol need to overide static func ==(..) in order to compare you object.
Hashable protocol need to provide as far as you can a unique integer value hashValue which need to be the same within two object when they are equals.
Hope this help
If an object conforms to the hashable protocol, it needs to have a hashValue, as you mentioned. The hashValue can be used to compare objects / uniquely identify the object.
You can compare objects in two ways:
=== function. This checks object references (can only be used with classes). It checks if the left object has the same reference to the right object. Even if both objects have exactly the same property values BUT they do have a different reference, it returns false.
== function (Equatable protocol). It checks if the objects are equal to eachother based on the static func ==. You can return the hashValue of the object. In that way, you can say objects are equal to eachtoher based on the properties, rather than reference.
If you provide your own hashValue, you can say objects are equal to eachother in a way you say objects are equal to eachother, regardless of the reference to the object. You can use objects in a Set that conform to the hashable protocol, because a Set checks if objects are equal to eachother based on the hashValue.
The Hashable documentation give one concrete example of what it's for:
You can use any type that conforms to the Hashable protocol in a set or as a dictionary key.
You can think of a hash value as a quick approximation of equality. Two elements that are equal will have the same hash value but two elements with the same hash value are not guaranteed to actually be equal.

Binary operator '==' cannot be applied to two 'Equatable' operands... what?

You can see in the image below that I was trying to extend the Collection protocol to include a method called removingDuplicates, which is supposed to do exactly what it says. The error that the compiler is displaying seems to directly contradict the definition of the Equatable protocol. Is this a bug or am I misunderstanding something?
Replace Element == Equatable with Element: Equatable.
The == function (all operators are actually functions in Swift) is a requirement of the Equatable protocol, which means it must be used with some concrete implementations of the protocol.
Another aspect is that Collection is a generic type, and its Element associated type will need to eventually be also filled with a concrete type, and == Equatable doesn't help here.
Actually it's not even possible to have a collection of generic Equatable values, as Equatable is a protocol with Self requirements, thus it can be directly referenced in a lot of places, e.g. [Equatable], one reason being the fact that that declaration can't satisfy the "collections are homogenous" requirement as you'd be able ot place two completely unrelated types in the array that way.
What you need to do is to transform the equality where clause to a conformance one: extension Collection where Element: Equatable. This moves the burden of providing an actual implementation on the user of the extension. And allows you to use the support brought by the Equatable type.

Are type-erased Any... structs necessary for non-generic protocols?

When defining a generic Swift protocol (that is, a protocol with at least one associatedtype) for a framework, it's common practice to also provide an Any... struct, e.g. SomethingType and AnySomething. For example, the standard library does this with AnySequence.
Is this necessary for a non-generic protocol? In that case, you can refer to the protocol type directly, so it seems that the protocol itself is already a type-erased version?
A protocol that does not have an associated type can easily be used as a Type in its own right. This is often done to allow diverse concrete types to be stored in collections identifying them only by a common protocol that all the concrete types implement.
Or to put it another way "type erasing" is a technique for dealing with protocols that have associated types. If your protocol does not have associated types, there is no need to employ the technique.

Use of a Structure instead of a Class in Swift [duplicate]

This question already has answers here:
Why Choose Struct Over Class?
(17 answers)
Closed 7 years ago.
I learn Swift from some time, I know the differences between structure and class. The main difference is structure is of value type and class is of reference type but didn't understand when to use structure instead of a class. Please explain it.
For example, In case of Protocols:
First, We have just a protocol of struct type:
protocol SomeProtocol{
func doSomeStuff()
}
Second, We make protocol of class type like this:
protocol SomeProtocol: class{
func doSomeStuff()
}
So, Please explain me, when we have to use protocol of struct type or of class type.
Firstly structs are passed by value (copied), and a class is passed by reference (copied just the memory address to the object).You may want to use structs for simpler types, because you get a free init for all the properties your struct has.And with protocols, the first one you can use it on class,struct and enum, the second you say that you only use that on classes,and you may want to put class if your protocol is a delegate or a data source,because you want the property(of the type of your protocol) weak to avoid the memory cycle. IMHO use classes for multi-scene apps because you don't need to take care to update value when you edited something in an another scene.
The protocol is not "of struct type" or "of class type", that is wrong terminology.
If you write SomeProtocol: class you make sure only classes can conform to that protocol, structs cannot. If you don't include the class both classes and structs can conform.
The docs (scroll down to "Class-Only Protocols") tell you that
You can limit protocol adoption to class types (and not structures or enumerations) by adding the class keyword to a protocol’s inheritance list. The class keyword must always appear first in a protocol’s inheritance list, before any inherited protocols.
Use a class-only protocol when the behavior defined by that protocol’s requirements assumes or requires that a conforming type has reference semantics rather than value semantics. For more on reference and value semantics, see Structures and Enumerations Are Value Types and Classes Are Reference Types.