2
votes

I'd like to know if there's something simple that I'm missing here in this code or if it's just a mix of Swift trickeries that are preventing me from doing what I want.

I'm allowing types implementing the Foo protocol to contain an entity property of any type, as long as it conforms to StringIdentifiable:

protocol StringIdentifiable {
  var id: String? { get }
}

protocol Foo: class {
  associatedtype AnyStringIdentifiable: StringIdentifiable
  var entity: AnyStringIdentifiable? { get set }
}

As of Swift 3.1, this "any type" part wouldn't be possible if not using the associatedtype. Going ahead, let's say I have another protocol that requires a Foo property. However, Foo is generic, so as you may know we can't do that because "generic protocols can only be used as a generic constraint". Trying to avoid the type erasure mess, I decided to use another associatedtype in my second protocol and the compiler doesn't complain:

protocol Bar {
  //var foo: Foo { get set } // can't do because Foo is generic
  associatedtype AnyFoo: Foo
  var foo: AnyFoo { get set }
}

But now, if I try to set something in foo, the compiler will complain:

extension Bar {
  func setEntity(_ entity: StringIdentifiable) {
    foo.entity = entity
  }
}

The error is Cannot assign value of type 'StringIdentifiable' to type '_?'

Note: this question's code is testable in a playground.

1

1 Answers

3
votes

You can do it like this

//: Playground - noun: a place where people can play

import Cocoa

protocol StringIdentifiable {
    var id: String? { get }
}

protocol Foo: class {
    associatedtype AnyStringIdentifiable: StringIdentifiable
    var entity: AnyStringIdentifiable? { get set }
}

protocol Bar {
    //var foo: Foo { get set } // can't do because Foo is generic
    associatedtype AnyFoo: Foo
    var foo: AnyFoo { get set }
}

extension Bar {
    func setEntity(_ entity: AnyFoo.AnyStringIdentifiable) {
        foo.entity = entity
    }
}

Within Bar you can use AnyFoo.AnyStringIdentifiable to make sure the types are correct when setting foo.entity, because foo.entity is of the type AnyFoo.AnyStringIdentifiable.