How is the init () value applicable in the Swift protocol?

Protocols in Swift can declare the init() method in their definition. However, I cannot come up with any precedent when this solves any problem, except that the forced classes define init() , as in the protocol. We can call the declared methods for the protocol type, but the init for the protocol cannot be used to instantiate its object, which is its only purpose.

What problem does the init() method declare in the protocol?

+5
source share
3 answers

It forces the class to have init(data: data) from some data, for example:

 protocol JSONable { init(data: JSON) } 

forces all classes that JSONable have an initializer from JSON , so you are always sure that you can create an instance from JSON .

+2
source

I think that real utility arises when it is used as a limitation in a universal function of class o. This is the real code from one of my projects.

I declare the protocol with init :

 protocol JSONCreatable { init(fromJson json: JSON) } 

Then in the generic function, where I return a class that matches this protocol:

 import SwiftyJSON extension JSON { func asObject<T>() -> T? where T: JSONCreatable { if isEmpty { return nil } return T(fromJson: self) } func asArray<T>() -> [T] where T: JSONCreatable { return array?.map{ json in T(fromJson: json) } ?? [] } } 

This allows me to do things like this:

 let user: User = json["user"].asObject() let results: [Element] = json["elements"].asArray() 
+2
source

It is commonly used to allow protocol extensions and common placeholders restricted by protocols to invoke an initializer of this particular type that corresponds to the protocol. For example, consider the default RangeReplaceableCollection init<S : Sequence>(_ elements: S) :

 extension RangeReplaceableCollection { // ... /// Creates a new instance of a collection containing the elements of a /// sequence. /// /// - Parameter elements: The sequence of elements for the new collection. public init<S : Sequence>(_ elements: S) where S.Iterator.Element == Iterator.Element { self.init() append(contentsOf: elements) } // ... } 

Without init() is defined as a requirement of the RangeReplaceableCollection protocol, there is no way for the extension to know that we can call init() to create a new instance of the appropriate type.

But it can also be used directly outside of pedigrees and extensions - for example, it can be used to build a new instance represented by this existential metatype (a metatype of "a specific specific type that conforms to the protocol"):

 protocol P { init() } struct S : P { init() {} } let s: P = S() let s1 = type(of: s).init() // creates a new instance of S, statically typed as P. 

In this example:

  • type(of: s) returns the dynamic type of s as P.Type (existential metatype), since s statically injected as P Remember that type(of:) is an operation (T) -> T.Type .

  • init() builds a new instance of the base concrete type, in this case s .

  • A new instance is statically injected as P (insertion into an existential container).

+1
source

Source: https://habr.com/ru/post/1265231/


All Articles