I'm trying to define some protocols in a Swift file, however I've noticed that if the protocols have crossed references XCode becomes buggy and it's impossible to work with the project. The example of used protocols might be the one used below:
protocol VIPERPresenterProtocol
{
var view: VIPERViewProtocol? { get set }
var interactor: VIPERInteractorInputProtocol? { get set }
var wireFrame: VIPERWireFrame? { get set }
// /* Add your extra communication methods here */
// /* Presenter -> ViewController */
}
protocol VIPERViewProtocol
{
var presenter: VIPERPresenterProtocol? { get set }
}
Where the VIPERPresenterProtocol has a reference to the VIPERViewProtocol and this last has a reference to the VIPERPresenterProtocol.
This is something that works in Objective-C but that Swift doesn't like. My question is, is this something Apple doesn't expect to support in Swift, if it might be a bug of the Swift language or if I should implement this in any other way.
Your question has a form of:
protocol A
{
var b: B? { get set }
}
protocol B
{
var a: A? { get set }
}
However, while the two protocol declarations compile, any attempt to implement them as such does not:
protocol A {
var b: B? { get set }
}
protocol B {
var a: A? { get set }
}
// on their own, the two protocol declerations compile
class Ca: A { // Does not compile: --> Segmentation fault 11
var b: B?
}
This does not happen if we break the cycle:
protocol A {}
protocol B {
var a: A? { get set }
}
class Ca: A {}
class Cb: B {
var a: A?
}
let cb = Cb() // --> {nil}
cb.a = Ca() // --> {{Ca}}
cb.a // --> {Ca}
Or if we define the two protocols in terms of concrete types:
protocol A {
var b: Cb? { get set }
}
protocol B {
var a: Ca? { get set }
}
class Ca: A {
var b: Cb?
let i = "A"
}
class Cb: B {
var a: Ca?
let i = "B"
}
let cb = Cb() // --> {nil "B"}
cb.a = Ca() // --> {{{...}} "B"}
cb.a // --> {{nil "A"}}
cb.a!.b = Cb() // --> {{{...} "A"}}
My impression is that the type checker cannot yet deal with recursive type declarations. Whether it ever will, may be an open question even to Apple at this point, though, because of the clear intention to facilitate functional idioms, this must at least be a possibility.
I have answered a similar question before, though, as I eventually realised with the help of #newacct, not identical.
EDIT
I have just upgraded to Xcode 6.1 GM Seed and things have changed! The following snippet now compiles and appears to run fine!
protocol A {
var b: B? { get set }
}
protocol B {
var a: A? { get set }
}
class Ca: A {
var b: B?
}
class Cb: B {
var a: A?
}
let a = Ca() // --> {nil}
let b = Cb() // --> {nil}
a.b = b // --> {{{...}}}
b.a = a // --> {{{...}}}
(This improvement, however, does not extend to recursively defined associated types.)
I was trying to build something similar too for VIPER, and I encountered the same problems.
I add something to the good answer of milos: I succeeded to break the cycle even when using associated types, using a couple of supporting protocols.
protocol _VIPERViewProtocol {
}
protocol VIPERViewProtocol : _VIPERViewProtocol {
typealias P:_VIPERPresenterProtocol
var presenter: P! {get set}
}
protocol _VIPERPresenterProtocol {
}
protocol VIPERPresenterProtocol : _VIPERPresenterProtocol {
typealias W:_VIPERViewProtocol
var view: W! {get set}
}
This has the advantage of letting the compiler infer the right type of the associated presenter and view, for example:
class BasePresenter : VIPERPresenterProtocol {
var view : BaseView!
}
class BaseView : VIPERViewProtocol {
var presenter: BasePresenter!
}
var p = BasePresenter()
// p.view is correctly recognized as BaseView!
This is valid as long as you use an associated type. Since there is no covariance for properties in Swift, the above code would not compile if you change it like this:
protocol VIPERViewProtocol : _VIPERViewProtocol {
var presenter: _VIPERPresenterProtocol! {get set}
}
Anyway, stepping back to the VIPER architecture, this helps only for giving the concrete classes a template that they must implement.
It would be much more useful if we could define a "builder" method that takes the generic objects conforming to the protocols (wireframe, presenter..), and that wires up all the components.
Unfortunately, something like this doesn't work:
func builder(p:VIPERPresenterProtocol, v:VIPERViewProtocol) {
p.view = v
v.presenter = p
}
compiler complains about Protocol 'VIPERViewProtocol' can only be used as a generic constraint because it has Self or associated type requirements.
Maybe one solution to explore is generics, but I still have to think about it.
Related
Is there a point to declaring a static function on a protocol? The client using the protocol has to call the function on a type conforming to the protocol anyway right? That breaks the idea of not having to know the type conforming to the protocol IMO. Is there a way to call the static function on the protocol in a way where I don't have to know the actual type conforming to my protocol?
Nice question. Here is my humble point of view:
Is there a point to declaring a static function on a protocol?
Pretty much the same as having instance methods declared in a protocol.
The client using the protocol has to call the function on a type conforming to the protocol anyway right?
Yes, exactly like instance functions.
That breaks the idea of not having to know the type conforming to the protocol IMO.
Nope. Look at the following code:
protocol Feline {
var name: String { get }
static func createRandomFeline() -> Feline
init()
}
extension Feline {
static func createRandomFeline() -> Feline {
return arc4random_uniform(2) > 0 ? Tiger() : Leopard()
}
}
class Tiger: Feline {
let name = "Tiger"
required init() {}
}
class Leopard: Feline {
let name = "Leopard"
required init() {}
}
let feline: Feline = arc4random_uniform(2) > 0 ? Tiger() : Leopard()
let anotherFeline = feline.dynamicType.createRandomFeline()
I don't know the real type inside the variable feline. I just know that it does conform to Feline. However I am invoking a static protocol method.
Is there a better way to do this?
I see, you would like to call a static method/function declared in a protocol without creating a value that conforms to the protocol.
Something like this:
Feline.createRandomFeline() // DANGER: compiler is not happy now
Honestly I don't know the reason why this is not possible.
yes this is possible:
Swift 3
protocol Thing {
static func genericFunction()
}
//... in another file
var things:[Thing] = []
for thing in things {
type(of: thing).genericFunction()
}
Thank you #appzYourLife for the help! Your answer inspired my answer.
#appzYourLife answered my question. I had an underlying issue I was trying to resolve and the following code resolves my issue, so I'll post this here, maybe it helps someone with my same underlying question:
protocol MyProtocol {
static func aStaticFunc()
}
class SomeClassThatUsesMyProtocolButDoesntConformToIt {
var myProtocolType: MyProtocol.Type
init(protocolType: MyProtocol.Type) {
myProtocolType = protocolType
}
func aFunction() {
myProtocolType.aStaticFunc()
}
}
I created another solution for this case. IMHO this is quite clean and simple.
First, create a protocol for accessing instance type.
protocol TypeAccessible {
func type() -> Self.Type
}
extension TypeAccessible {
func type() -> Self.Type {
return Swift.type(of: self)
}
}
then create your concrete class as here. The point is your protocol should conform to TypeAccessible protocol.
protocol FooProtocol: TypeAccessible {
static func bar()
}
class Foo: FooProtocol {
static func bar() { }
}
On call site use it as
let instance: FooProtocol = Foo()
instance.type().bar()
For further use cases, just make sure your protocols conform to TypeAccessible and that's all.
A little late to the party on this one.
Here's my solution for "adding" static properties/functions/types to a protocol using typealias.
For example:
enum PropertyScope {
case all
case none
}
struct PropertyNotifications {
static var propertyDidChange =
Notification.Name("propertyDidChangeNotification")
}
protocol Property {
typealias Scope = PropertyScope
typealias Notifications = PropertyNotifications
var scope: Scope { get set }
}
Then you can do this anywhere in your code:
func postNotification() {
let scope: Property.Scope = .all
NotificationCenter.post(name: Property.Notifications.propertyDidChange,
object: scope)
}
Using protocols like Java interfaces is rarely a good idea. They are meta types, meant for defining contracts, which is an entirely different kind of thing.
That being said, just for the point of understanding, I find the most simple and effective way for creating the equivalent of a static factory method of a protocol to write a free function.
It should contain the protocol's name, hoping that that will prevent name clashes, and improve discoverability.
In other languages, createP would be a static member of P, named create and be called as P.create(...), which would drastically improve discoverability and guarantee to prevent name clashes.
In swift, though, this is not an option for protocols, so if protocols are for some reason really actually used as a replacement for interfaces, at least including the protocol's name in the function's name is an ugly workaround that's still slightly better than nothing.
P.S. in case the goal is actually to achieve something like an inheritance hierarchy with structs, union style enums are the tool that's meant to serve that purpose :)
protocol P
{
var x: Int { get }
}
func createP() -> P
{
if (todayIsMonday())
{
return A()
}
else
{
return B()
}
}
class A: P
{
var x = 5
}
class B: P
{
var x = 7
}
This isn't an answer so much as it is an extension to the question. Say I have:
#objc public protocol InteractivelyNameable: Nameable {
static func alertViewForNaming(completion:#escaping((_ success: Bool, _ didCancel: Bool, _ error: Error?) -> Void)) -> UIAlertController?
}
And I have a generic view controller that manages various types (generic type is .fetchableObjectType... basically NSFetchResult). I need to check if a specific object type conforms to the protocol, and if so, invoke it.
something like:
// valid swift code
if self.dataSource.fetchableObjectType is InteractivelyNameable {
// not valid swift code
if let alert = (self.dataSource.fetchableObjectType as InteractivelyNameable).alertViewForNaming(....)
}
I had a situation where I need to create same DomainModel object from 2 different response. so this (static method in protocol helped me) approach helped me.
protocol BaseResponseKeyList: CodingKey {
static func getNameKey()->Self
}
enum FirstResponseKeyList: String, BaseResponseKeyList {
case name
func getNameKey()->FirstResponseKeyList {
return .name
}
}
enum SecondResponseKeyList: String, BaseResponseKeyList {
case userName
func getNameKey()->SecondResponseKeyList {
return .userName
}
}
struct MyDomainModel<T:BaseResponseKeyList> : Decodable {
var name:String?
required init(from d:Decoder) {
do {
let container = try d.container(keyedBy:T.self)
name = try container.decode(String.self, forKey:T.getNameKey())
}catch(_) {
print("error")
}
}
}
let myDomainModel = try JSONDecoder().decode(MyDomainModel <FirstResponseKeyList>.self, from: data)
let myDomainModel2 = try JSONDecoder().decode(MyDomainModel <SecondResponseKeyList>.self, from: data2)
Is something like
protocol A {
var intCollection: CollectionType<Int> { get }
}
or
protocol A {
typealias T: CollectionType where T.Generator.Element == Int
var intCollection: T
}
possible in Swift 2.1?
Update for Swift 4
Swift 4 now support this feature! read more in here
Not as a nested protocol, but it's fairly straightforward using the type erasers (the "Any" structs).
protocol A {
var intCollection: AnyRandomAccessCollection<Int> { get }
}
This is actually often quite convenient for return values because the caller usually doesn't care so much about the actual type. You just have to throw a return AnyRandomAccessCollection(resultArray) at the end of your function and it all just works. Lots of stdlib now returns Any erasers. For the return value problem, it's almost always the way I recommend. It has the nice side effect of making A concrete, so it's much easier to work with.
If you want to keep the CollectionType, then you need to restrict it at the point that you create a function that needs it. For example:
protocol A {
typealias IntCollection: CollectionType
var intCollection: IntCollection { get }
}
extension A where IntCollection.Generator.Element == Int {
func sum() -> Int {
return intCollection.reduce(0, combine: +)
}
}
This isn't ideal, since it means you can have A with the wrong kind of collection type. They just won't have a sum method. You also will find yourself repeating that "where IntCollection.Generator.Element == Int" in a surprising number of places.
In my experience, it is seldom worth this effort, and you quickly come back to Arrays (which are the dominant CollectionType anyway). But when you need it, these are the two major approaches. That's the best we have today.
You can't do this upright as in your question, and there exists several thread here on SO on the subject of using protocols as type definitions, with content that itself contains Self or associated type requirements (result: this is not allowed). See e.g. the link provided by Christik, or thread Error using associated types and generics.
Now, for you example above, you could do the following workaround, however, perhaps mimicing the behaviour you're looking for
protocol A {
typealias MyCollectionType
typealias MyElementType
func getMyCollection() -> MyCollectionType
func printMyCollectionType()
func largestValue() -> MyElementType?
}
struct B<U: Comparable, T: CollectionType where T.Generator.Element == U>: A {
typealias MyCollectionType = T
typealias MyElementType = U
var myCollection : MyCollectionType
init(coll: MyCollectionType) {
myCollection = coll
}
func getMyCollection() -> MyCollectionType {
return myCollection
}
func printMyCollectionType() {
print(myCollection.dynamicType)
}
func largestValue() -> MyElementType? {
guard var largestSoFar = myCollection.first else {
return nil
}
for item in myCollection {
if item > largestSoFar {
largestSoFar = item
}
}
return largestSoFar
}
}
So you can implement blueprints for your generic collection types in you protocol A, and implement these blueprints in the "interface type" B, which also contain the actual collection as a member property. I have taken the largestValue() method above from here.
Example usage:
/* Examples */
var myArr = B<Int, Array<Int>>(coll: [1, 2, 3])
var mySet = B<Int, Set<Int>>(coll: [10, 20, 30])
var myRange = B<Int, Range<Int>>(coll: 5...10)
var myStrArr = B<String, Array<String>>(coll: ["a", "c", "b"])
myArr.printMyCollectionType() // Array<Int>
mySet.printMyCollectionType() // Set<Int>
myRange.printMyCollectionType() // Range<Int>
myStrArr.printMyCollectionType() // Array<String>
/* generic T type constrained to protocol 'A' */
func printLargestValue<T: A>(coll: T) {
print(coll.largestValue() ?? "Empty collection")
}
printLargestValue(myArr) // 3
printLargestValue(mySet) // 30
printLargestValue(myRange) // 10
printLargestValue(myStrArr) // c
I would like to add an extension to the Set struct, but only if the element of Set is an Array of NSOperations. Is it possible?
I want to write something like this, but it's not a valid code:
extension Set where Element : Array<NSOperation> { }
because type 'Element' constrained to non-protocol type 'Array<NSOperation>. So I wanted to create a protocol and extend Array of NSOperations with this protocol:
protocol ArrayOfOperations { }
extension Array : ArrayOfOperations where Element : NSOperation { }
It doesn't work either because Extension of type 'Array' with constraints cannot have an inheritance clause.
So I'm kinda lost here. Do you have some idea, how to solve this?
Since you cannot make Array<NSOperation> conform to Hashable you'll have to make a small wrapper-struct.
E.g.
struct NSOperationList {
var operations = [NSOperation]()
}
and then build all functionality you need on top of NSOperationList.
So if you want to add support for Set:
extension NSOperationList: Hashable {
var hashValue: Int {
return operations.reduce(0) { $0 ^ $1.hashValue }
}
}
func == (a: NSOperationList, b: NSOperationList) -> Bool {
return a.operations == b.operations
}
import Foundation
let op = NSOperation()
var arr: Array<NSOperation> = []
arr.append(op)
let set = Set(arr)
i don't know what is your trouble, but above snippet compiles without any trouble
I am trying to learn more about protocols and got stuck without understanding what is going on on the following piece of code. Mostly seeking some light and direction for good articles and pieces of explanation basically.
In one of the examples from Apple's Library protocols are doing a bit more than making sure the classes conform to it.
They are allowing objects from one class to access methods within other classes without using the traditional class inheritance definition.
This line of code let generator: RandomNumberGenerator on the Dice class is allowing the var d6 that is of type Dice to access a function func random() -> Double that is outside of Dice scope and inside LinearCongruentialGenerator scope and is using the RandomNumberGenerator to make this bridge.
Also allowing to do the following call d6.generator.random() when again .ramdom() is not on Dices scope.
protocol RandomNumberGenerator {
func random() -> Double
}
class LinearCongruentialGenerator: RandomNumberGenerator {
var lastRandom = 42.0
let m = 139968.0
let a = 3877.0
let c = 29573.0
func random() -> Double {
lastRandom = ((lastRandom * a + c) % m)
return lastRandom/m
}
}
class Dice {
let sides: Int
let generator: RandomNumberGenerator
init(sides: Int, generator: RandomNumberGenerator) {
println(generator.random())
self.sides = sides
self.generator = generator
}
func roll() -> Int {
return Int(generator.random() * Double(sides)) + 1
}
}
var d6 = Dice(sides: 6, generator: LinearCongruentialGenerator())
Update to question
Thanks for the answers! By doing some research I think I just touched composition. So I wrote the code bellow to exemplify composition a bit better, without using protocols or delegates. Just pure composition. Please let me know if I got it right as it may help other people trying to understand composition.
class A {
var a1: String
init (valueToA: String){
self.a1 = valueToA
}
func aFunc1() -> A {
return self
}
}
class B {
var b1: A
init (valueToB: A ) {
self.b1 = valueToB
}
func bFunc1(){
println("I am bFunc and I am calling aFunc \(b1.aFunc1())")
}
}
var myA = A(valueToA: "Initiated myA with this string")
//myA.aFunc1()
var myB = B(valueToB: myA)
myB.b1 = A(valueToA: "a value to B")
myB.b1.aFunc1()
The same code but now with protocols
protocol myProtocol {
func protocolFunc(value: String) -> String
}
class A: myProtocol {
var a1: String
init (valueToA: String){
self.a1 = valueToA
}
func aFunc1() -> A {
return self
}
func protocolFunc(value: String) -> String {
return value
}
}
class B {
var b1: A
var b2: myProtocol
init (valueToB1: A, valueToB2: myProtocol ) {
self.b1 = valueToB1
self.b2 = valueToB2
}
func bFunc1(){
println("I am bFunc and I am calling aFunc \(b1.aFunc1())")
}
func callProtocolFuncOnA (value: String) {
b1.protocolFunc(value)
}
}
var myA1 = A(valueToA: "my A 1 created")
var myA2 = A(valueToA: "my A 2 created")
var myB = B(valueToB1: myA1, valueToB2: A(valueToA: "my A 3 created"))
myB.callProtocolFuncOnA("calling other function")
As #DevAndArtist says in his comment it allows encapsulation (abstraction) when a type of RandomNumberGenerator is passed in the initializer of the Dice class and so only that part of your implementation is visible to you.
In my humble opinion it could be better if the constant generator was not visible outside the Dice class scope as you say in your question, for example making his access modifier private, but remember that in your example all is set in the same swift file and this implies that the private access modifier isn't like the other programming languages like C#, Java, etc.
Even doing private you can access d6.generator.random() in your call because it exist in the same Swift file, the only way you can hide the property if you create a new Swift file for the Dice class and then this call when the property is private of course :
var d6 = Dice(sides: 6, generator: LinearCongruentialGenerator())
println(d6.generator.random())
gave you the following error:
'Dice' does not have a member named 'generator'
And you can hide the property outside of its scope. It's only a point of view.
I hope this help you.
The following code produces a compile error of "Generic parameter "T" cannot be bound to non-#objc protocol type 'AAA' on the fail line. When I use a class instead of a protocol, it works ok. Also, if I add an #objc to the protocol it also works, but only in 6.4 beta. Any suggestions would be helpful.
protocol AAA {
var id: String { get set }
}
class BBB: AAA {
var id: String = ""
}
class BBBService {
func getAll<T:AAA>() -> [T] {
var returnArray:[T] = [T]()
return returnArray
}
}
class TestIt
{
func myTest() {
var service = BBBService()
var fail:[AAA] = service.getAll() // fails with Generic parameter "T" cannot be bound to non-#objc protocol type AAA
var succeed:[BBB] = service.getAll()
}
}
this also fails:
<T where T:AAA>
Update - from a practical perspective, adding the #objc causes other problems in my app. So, that is not an option at this point and time.
The trouble is with this line:
getAll<T: AAA>() -> [T]
you are declaring that T must be a concrete type that implements the protocol AAA. It’s important to distinguish between the protocol AAA, i.e. code like this:
func getAll() -> [AAA] {
var returnArray: [AAA] = [BBB()]
return returnArray
}
which works fine (returns an array of references to AAA-conforming objects, which could be of type BBB, or type CCC), and this:
func getAll<T: AAA>() -> [T] {
var returnArray: [T] = [] // what is T? No idea.
return returnArray
}
in which you are saying to the compiler “write me a version of getAll, in which T can be replaced by any specific type that implements AAA”.
This is why your second version compiles - you’re fixing T to be the actual type BBB.
Bear in mind, T might be a struct. In which case the array returned must be sized specifically for whatever struct is being held, right there as a value within the array. As opposed to if the protocol was #objc in which case it would at least be known to only be a class reference of a fixed size.
If what you actually want is an array of protocols, you should remove the generic placeholder and just return an array of protocols:
func getAll() -> [AAA] {
var returnArray: [AAA] = []
return returnArray
}