I am fairly new to the Swift programming language. I am trying to create a util function that takes a generic.
class Utils {
static func formatArtists<T: ArtistDetails>(_ artists: [T]) -> String {
return artists.map({ artist in
return artist.name
}).joined(separator: ", ")
}
}
I get two errors for this piece of code
Type 'T' constrained to non-protocol, non-class type 'ArtistDetails'
Value of type 'T' has no member 'name'
I think I need to extend a protocol
or something.
I want to be able to call the helper function like this.
Text(Utils.formatArtists(track.artists))
Text(Utils.formatArtists(mix.artists))
With both track
and mix
artists using the ArtistDetails
fragment.
Artist Details gets generated by Apollo swift library
public struct ArtistDetails: GraphQLFragment {
/// The raw GraphQL definition of this fragment.
public static let fragmentDefinition: String =
"""
fragment ArtistDetails on Artist {
__typename
id
name
}
"""
public static let possibleTypes: [String] = ["Artist"]
public static var selections: [GraphQLSelection] {
return [
GraphQLField("__typename", type: .nonNull(.scalar(String.self))),
GraphQLField("id", type: .nonNull(.scalar(GraphQLID.self))),
GraphQLField("name", type: .nonNull(.scalar(String.self))),
]
}
public private(set) var resultMap: ResultMap
public init(unsafeResultMap: ResultMap) {
self.resultMap = unsafeResultMap
}
public init(id: GraphQLID, name: String) {
self.init(unsafeResultMap: ["__typename": "Artist", "id": id, "name": name])
}
public var __typename: String {
get {
return resultMap["__typename"]! as! String
}
set {
resultMap.updateValue(newValue, forKey: "__typename")
}
}
public var id: GraphQLID {
get {
return resultMap["id"]! as! GraphQLID
}
set {
resultMap.updateValue(newValue, forKey: "id")
}
}
public var name: String {
get {
return resultMap["name"]! as! String
}
set {
resultMap.updateValue(newValue, forKey: "name")
}
}
}
protocol GraphQLFragment : GraphQLSelectionSet
Thanks
CodePudding user response:
In Swift you might prefer to write it like
extension Collection where Element == ArtistDetails {
var formatted: String {
map(\.name).joined(separator: ", ")
}
}
Text(track.artists.formatted)
You can't write a generic like <T: ArtistDetails>
because ArtistDetails is a struct so doesn't support subclassing, and isn't a protocol, so T can't be any type that implements the protocol or "is a" ArtistDetails. There's no need for a Utils class - if you ever need a namespace like that an enum (with no cases) would be preferred as a type that can't be instantiated.