简体   繁体   English

使 Swift 数组符合协议

[英]Making a Swift Array conform to a Protocol

Let's say that certain items can appear in a Feed , so long as they implement the necessary properties defined by the Feedable protocol.假设某些项目可以出现在Feed ,只要它们实现了Feedable协议定义的必要属性。 Let's also say that the Photo object is feed-worthy:我们还说Photo对象是值得一看的:

extension Photo: Feedable { }

Is it possible to say that an Array of these photos might also be Feedable ?是否可以说这些照片的Array也可能是Feedable

extension [Photo] : Feedable

Or do I always need some kind of wrapper object, such as a PhotoAlbum , to conform to Feedable ?还是我总是需要某种形式的包装对象的,如PhotoAlbum ,以符合Feedable

Edit编辑

To re-iterate, I was curious whether I can make only arrays of Photo objects Feedable .重申Feedable ,我很好奇我是否只能制作Photo对象的数组Feedable Not making Array of any content type Feedable , not making an array of Feedable s itself Feedable (both of which are offered as solutions below if that's what you need).不将任何内容类型的Array Feedable ,也不将Feedable数组本身Feedable (如果您需要,这两种方法都在下面作为解决方案提供)。

In other words, a solution (which I doubt exists) would allow me to define a variable of type Feedable with the following outcomes:换句话说,一个解决方案(我怀疑是否存在)将允许我定义一个Feedable类型的变量,结果如下:

var feedable: Feedable

//photo is feedable, so this is fine
feedable = Photo() //ok

//arrays of photos are feedable
let photo1 = Photo()
let photo2 = Photo()
feedable = [photo1, photo2]

//arrays of other things are not
feedable = ["no", "dice"] //nope

//even if the contents of an array are themselves Feedable, that's not sufficient. E.g. Video is Feedable, but Array of Videos is not.
let video1 = Video()
let video2 = Video()
feeble = video1 //fine
feedable = [video1, video2] //nope

Perhaps this gist (which doesn't compile of course) shows the intention more clearly.也许这个要点(当然不能编译)更清楚地表明了意图。

You can achieve your goal in this way:您可以通过以下方式实现您的目标:

Swift 4:斯威夫特 4:

protocol Feedable {
    func foo()
}

extension String: Feedable {
    func foo() {    
    }
}

extension Array: Feedable where Element: Feedable {
    func foo() {    
    }
}
// or in more generic way to support Array, Set and other collection types
extension Collection: Feedable where Element: Feedable {
    func foo() {    
    }
}

If there was an array of Photo and Video ,what would you like to be?如果有一组PhotoVideo ,你想成为什么?

1.Every element performs like what they are. 1.每个元素都表现得像它们一样。

extension Array where Element : Feedable {
    func foo() {
        if Element.self == Photo.self {

        } else {

        }
    }
}

2.The whole array performs as 'Video'. 2.整个阵列表现为“视频”。

extension Array where Element : Photo {
    func foo() {

    }
}

I think this is currently not possible.我认为目前这是不可能的。 In my project I have the same issue with a ModelProducer.在我的项目中,我对 ModelProducer 有同样的问题。

protocol M: ModelType {}
protocol ModelProducerType {
    associatedtype M: ModelType
    var model: M? { get }
    func produce()
}

struct Test: ModelType {}
class TestProducer: ModelProducerType {
    var model: Test?
    func produce() {
        model = Test()
    }
}

I use ModelType as a ghost protocol.我使用ModelType作为幽灵协议。 The problem is I cannot make a model producer that produces multiple ModelType s, because of the same reason you discovered.问题是,由于与您发现的原因相同,我无法制作产生多个ModelType的模型生产者。 The solution in this case was the following:在这种情况下的解决方案如下:

protocol M: ModelType {}
protocol ModelProducerType {
    associatedtype M: ModelType
    var model: [M] { get }
    func produce()
}

struct Test: ModelType {}
class TestProducer: ModelProducerType {
    var model: [Test] = []
    func produce() {
        model = [Test()]
    }
}

This is more flexible from the start.这从一开始就更加灵活。 I get rid of the optional variable and single model producers just have one item in the array.我摆脱了可选变量,单个模型生产者在数组中只有一项。 Maybe you can use a similar approach.也许您可以使用类似的方法。

You can make an array to conform a protocol like this:您可以制作一个数组以符合这样的协议:

typealias PhotoArray = [Photo]

extension PhotoArray: Feedable {}

I didn't try in playground but maybe you can simply make an Array of Feedable:我没有在操场上尝试过,但也许您可以简单地制作一个可馈送数组:

var myPhotosArray = [Feedable]()

Then everything implementing the Feedable protocol would be allowed in the Array.然后所有实现 Feedable 协议的东西都将被允许在 Array 中。 If you want only a photo array, You can still subclass your Photo object to make a FeedablePhoto object.如果你只想要一个照片数组,你仍然可以子类化你的 Photo 对象来制作一个 FeedablePhoto 对象。

Try this in Playground instead of downvoting without even testing.在 Playground 中试试这个,而不是在没有测试的情况下投票。 Seriously 3 downvotes without any reasons and explanations...严重 3 次投票,没有任何理由和解释......

import UIKit

protocol Tree: class {
  func grow()
}

class BigTree: Tree {
  internal func grow() {
    print("Big tree growing")
  }
}

class SmallTree: Tree {
  internal func grow() {
    print("Small tree growing")
  }
}

class Car {
  //not a tree
}

var manyTrees = [Tree]()

manyTrees.append(BigTree())
manyTrees.append(SmallTree())
manyTrees.append(Car()) //This makes an error "Car doesn't conform to expected type 'Tree'"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM