2

I have a protocol that I am using to define what makes up the content of a note. A note can have many different content types, so a protocol seemed like the best way to go.

public protocol Content {
    var contentType: String { get }
}

I then have an implementation of that protocol

public class PlainTextContent: Content {
    public var contentType: String {
        return "Plain Text"
    }

    public var text: String = String()

    public init(content: String) {
        self.text = content
    }
}

This is a simplified example of the two objects. Next I have a Note class that holds an Array of Content protocol implementations.

public class Note {
    public private(set) var noteContent: [Content] = []
    public var title: String = String()
    public var date: NSDate

    public init() {
        self.date = NSDate()
    }

    func insertContent(content: Content) -> Bool {
        if contains(self.noteContent, content) {
            return false
        }

        self.noteContent.append(content)
        return true
    }

    func deleteContent(content: Content) -> Bool {
        return false
    }
}

The problem that I have is that when I do

if contains(self.noteContent, content) {}

the compiler tells me

Note.swift:21:12: Cannot find an overload for 'contains' that accepts an argument list of type '([Content], Content)'

I have looked a few examples on Stackoverflow and I'm doing as they show. Is there an issue with how I am defining my protocol in order for me to use it as an array and the associated global functions?

Edit

I have also tried to make the protocol inherit from Equatable, at which point I get the following compiler error

Protocol 'Content' can only be used as a generic constraint because it has Self or associated type requirements

I'm a little confused as to how I can perform equality checks against the array of protocols. Is that something that Swift doesn't support? I'm coming from a C# background, so not sure how Swift handles protocols fully.

Community
  • 1
  • 1
Johnathon Sullinger
  • 7,097
  • 5
  • 37
  • 102
  • Please have a look at [Find index of object in an array of type SomeProtocol](http://stackoverflow.com/questions/30344222/find-index-of-object-in-an-array-of-type-someprotocol), that might be what you are looking for. – Martin R Jun 11 '15 at 04:43
  • @MartinR That worked perfectly, thanks. – Johnathon Sullinger Jun 11 '15 at 04:58

1 Answers1

1

You might use map in order to unbox your equatable value:

func insertContent(content: Content) -> Bool {
        if contains(self.noteContent.map({$0.contentType}), content.contentType) {
            return false
        }

        self.noteContent.append(content)
        return true
    }

Hope this helps.

Matteo Piombo
  • 6,688
  • 2
  • 25
  • 25
  • Thanks, that worked like a charm. Is this just doing a type check? Since I can have multiple instances of the same Type in there, that might not quiet work out. – Johnathon Sullinger Jun 11 '15 at 04:16
  • 1
    This will limit your `noteContent` array to one `Content` of each type, which I don't think you want. – Aaron Brager Jun 11 '15 at 04:24
  • Yeah, I need to support multiple instance of the same type. From what I've seen, this is a variance issue with Swift and protocols. I haven't seen anything that solves this anywhere. – Johnathon Sullinger Jun 11 '15 at 04:48
  • @JohnathonSullinger It isn't a type check. `map` _builds_ the array of all your contentType values, then `contains` will check if that array contains your `content.contentType`. Your protocol defines `contentType` to be a `String`. The code above ends up just checking if an array of strings contains a particular string. Thus `insertContent` should work with any content conforming to `Content` protocol. – Matteo Piombo Jun 11 '15 at 05:11
  • Oh thanks for clarifying. I saw contentType and instantly thought `GetType()` in C#. This makes sense, it's nothing more than a transformation method which I get now. I could add a method to the protocol that objects implement that is for hashing the object. Then use that instead of `contentType` – Johnathon Sullinger Jun 11 '15 at 14:47