简体   繁体   中英

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. Let's also say that the Photo object is feed-worthy:

extension Photo: Feedable { }

Is it possible to say that an Array of these photos might also be Feedable ?

extension [Photo] : Feedable

Or do I always need some kind of wrapper object, such as a PhotoAlbum , to conform to Feedable ?

Edit

To re-iterate, I was curious whether I can make only arrays of Photo objects 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).

In other words, a solution (which I doubt exists) would allow me to define a variable of type Feedable with the following outcomes:

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:

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?

1.Every element performs like what they are.

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

        } else {

        }
    }
}

2.The whole array performs as 'Video'.

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.

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. The problem is I cannot make a model producer that produces multiple ModelType s, because of the same reason you discovered. 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. If you want only a photo array, You can still subclass your Photo object to make a FeedablePhoto object.

Try this in Playground instead of downvoting without even testing. Seriously 3 downvotes without any reasons and explanations...

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'"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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