Swiftのプロトコル(以下、Protocol)はObjective-Cのそれと同等の位置づけです。実際、SwiftでUITableViewDelegateなどSDKのDelegateはProtocolで宣言されています。

Swiftから入る人にProtocolについて簡潔に述べると、

  • 実装を持たないクラスのようなもの
  • クラスから継承し、実装はクラスでするもの
  • 主にDelegateとして使うもの

ということです。

Protocolの宣言

protocol MyDelegate {
    func method1()
}

のように宣言します。classではなくprotocolで宣言すること、実装を書かないこと以外は、クラスの宣言とあまり変わりがありません。

クラスで継承し実装する場合は以下のようにします。

class MyClass: MyDelegate {
   //
   // MARK: MyDelegate
   //
   // overrideキーワードは不要
   func method1() {
      println("mehtod1")
   }
}

overrideキーワードは不要なので、MARK:というコメントをつけて、何のDelegateか示しておくと良いと思います。

@objcでProtocolを宣言したほうが無難な理由

iOSアプリの開発ではProtocolの宣言に@objcをつけるほうが無難だと思います。

@objc protocol MyDelegate {
    func method1()
}

理由は以下のとおりです。

  • weak var宣言が使える
  • メソッドにoptionalキーワードが使える
  • Objective-Cのコードからも参照できるようになる

weak var宣言が使える

DelegateとしてProtocolを使う場合、当然、以下のようにweak varとして使います。

weak var delegate: MyDelegate?

@objcキーワードで宣言するか、以下のようにclassを継承するかしないと、

protocol MyDelegate: class {

‘weak’ cannot be applied to non-class type

というコンパイルエラーが出ます。

optionalキーワードが使える

実装してもしなくても良いメソッドはoptionalで宣言するとそのようになります。

@objc protocol MyDelegate {
    optional func method1()
}

@objcキーワードをつけずにoptionalキーワードを使うと以下の様なコンパイルエラーになります。

‘optional’ can only be applied to members of an @objc protocol

Objective-Cのコードからも参照できる

@objcキーワードは、その名の通りObjective-Cと互換性のあるProtocolとして宣言するためのキーワードです。

Objective-Cから参照しなくとも、上記のことを総合するとProtocolには@objcキーワードをつけるのが無難だと思います。

多重継承

Protocolはクラスと違って複数継承が可能です。

class MyClass: UITableViewDelegate, UITableViewDataSource {
}

SDKでお馴染みのUITableViewDelegate、UITableViewDataSourceもProtocolです。Objective-C同様に複数継承して実装できます。

プロパティの宣言

Objective-CのProtocol同様、プロパティの宣言もできます。

@objc protocol MyDataSource {
    // 継承先でgetのみ(readonly)なプロパティを実装する
    var name: String { get }
    // 継承先でget/set両方可能なプロパティを実装する
    var vintage: Int { get set }
}

継承先のクラスで実装する場合は以下のようにします。

class MyClass: MyDataSource {
    // private(set)でsetはクラス内でのみ行う。つまりreadonly
    private(set) var name: String
    // get/set両方可能なので単にプロパティ宣言するだけでいい
    var vintage: Int
    
    init(name: String, vintage: Int) {
        self.name = name
        self.vintage = vintage
    }
}

もちろん変数型プロパティではなく実装型にしてもよいです。

class MyClass: MyDataSource {
    var name: String {
        get { return "name1" }
    }
    private var year: Int
    var vintage: Int {
        get { return year } 
        set(vintage) { year = vintage }
    }

initの宣言

あまり使う機会はないかもしれませんが、initメソッドもProtocolで宣言できます。

@objc protocol MyClassDelegate {
    init(name: String)
}

class MyClass: MyClassDelegate {
    var name: String
    // initは実装するときrequiredキーワードが必要
    required init(name: String) {
       self.name = name
    }
}