Насколько я понимаю, случай 1 говорит, что элементы - это массив любого типа, который реализует протокол Item, а случай 2 - это то же самое, что и сами протоколы не могут быть инициированы. Таким образом, элементы в случае, если снова массив объектов, реализующих протокол Item.
Давайте назовем ваши протоколы более точными названиями, чтобы продемонстрировать, как эти два случая различны. Давайте переименуем SomeProtocol
в ItemStorage
. Также, скажем, есть два класса, которые соответствуют Item
, FooItem
и BarItem
.
Теперь я хочу создать два класса, которые реализуют ItemStorage
с именами FooItemStorage
и BarItemStorage
. Я хочу, чтобы они могли хранить только свой соответствующий тип Item
. Если бы это был случай 1, я мог бы сделать это очень легко:
class FooItemStorage: ItemStorage {
typealias ItemType = FooItem
var items: [FooItem] = []
...
}
class BarItemStorage: ItemStorage {
typealias ItemType = BarItem
var items: [BarItem] = []
...
}
Однако в случае 2 массивы должны иметь тип [Item]
, поэтому приведенный выше код не будет компилироваться. Я должен сделать что-то вроде этого:
class FooItemStorage: ItemStorage {
typealias ItemType = FooItem
var items: [Item] {
get { return myItems }
set {
myItems = newValue as? [FooItem] ?? myItems
}
}
var myItems: [FooItem] = []
...
}
Я должен объявить дополнительное свойство с именем myItems
, которое имеет желаемый тип [FooItem]
, и делегировать метод получения и установки items
myItems
. Кроме того, с точки зрения клиентского кода это выглядит так, как будто FooItemStorage
теперь может хранить любые элементы.
Обратите внимание, это не означает, что протоколы со связанными типами всегда лучше. Протоколы со связанными типами не могут использоваться в качестве типа переменной. Так что если вам не нужно что-то вроде FooItemStorage
и BarItemStorage
, где соответствующие классы нуждаются в разных типах, и вы хотите использовать протокол в качестве типа переменной, вам не следует использовать связанные типы.