Illust & Music 月の高いところ

今日のプリン言

謎のプリン語る。
一人書く人増えました。

【Swift4】必須でなくてもいいデリゲートメソッド

2018年06月12日

みやびプリン 140 87

500 320

【Swift4】必須でなくてもいいデリゲートメソッド - サムネイル

※この記事は1年以上前の記事です。
現在は状況が異なる可能性がありますのでご注意ください。

どうも。
すっかりどっぷりSwift浸かってるみやびです。
だいぶ慣れたが、やっぱ制約とかあって難しいわ、オブジェクト指向言語・・・。
(というか、Swiftの場合、とにかくストーリーボードとオートレイアウトがうざい。←マジで滅べ)

さて、表記の件だが、
通常、デリゲートメソッドを指定する場合、
処理譲渡先に、必ずデリゲートメソッドを記述しなくてはならないが、
今回は、必須で書かなくてもよくする方法を紹介したい。
デリゲートメソッドってなんぞやって人は下記をご参照されたし。
(めんどくさい説明は他者に任せるスタイル)

【Swift入門】難解なデリゲート(delegate)の使い方を理解しよう!

例えば、下記のような、二つのクラスがあるとする。

// デリゲート元
import UIKit

protocol AclassDelegate {
  func testFunc(_ image: UIImage?)
}

class A {
  var delegate: AclassDelegate? = nil

  init(){
  }

  func testRun(){
    let testImage = UIImage()
    self.delegate?.testFunc(testImage)
  }
}
// デリゲート先
import UIKit

class B: AclassDelegate {

  var aInstanse: A = A()

  init(){
    self.aInstanse.delegate = self
  }

  // デリゲートメソッドを記載しなければいけない
  func testFunc(_ image: UIImage?) {
    // 処理内容
  }
}

クラスBでは、Aのデリゲートを継承しているが、
この場合、クラスB内で、必ずデリゲートメソッドを全て記述しなくてはならない。

いいんだけど、めんどうというか、余計な記述しなきゃいけない時があるから、
少々不便だ。
だが、よく考えれば、例えば、UITableViewのデリゲートメソッドとか、各種既存クラスでは、
必須でないデリゲートメソッドが存在する。
例えば下記。

func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
  return 5
}

したらカスタムクラスでもできんじゃね?
ってことで調べてみたが、これが出ない出ない。
調べ方がいけなかったか、本当に出てこなかった。
ってことで、奥の手、teratailで質問した結果、
下記の方法を教えてくれた。

extension AclassDelegate {
  func testFunc(_ image: UIImage?) {}
}

つまり、プロトコルを拡張して、ダミー関数を追加するというもの。
うん、実装できた。
おそらくこれが一番いい方法。
fuzzballさん、本当にありがとうございます。大感謝。

して、実はもう一個の方法がある。
UITableViewなどと同じ方法をとる方法だ。

UITableViewのデリゲートは下記のように定義されている。

public protocol UITableViewDataSource : NSObjectProtocol {
  public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell // 必須

  optional public func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int // 非必須
}

optionalキーワードで定義すれば、非必須にできるようだ。
これを参考に、Swift4で定義すると下記になる。

@objc protocol AclassDelegate: NSObjectProtocol {
  @objc optional func testFunc(_ image: UIImage?)
}

どうやら、@objcを使って無理やりなのであまり推奨されはしないようだ。
だが、既存クラスと同じ仕様でやれるのはスマートな方法ではないだろうか。
こちらの方法は、tyobigoroさんが教えてくれた。
こちらも大変に感謝です。

やっぱ、あれだね、わかる人に聞いた方が早いね。
Google先生と対話するのもいいんだけど、
的外れな記事ばかり出ると、イライラしかしないし、時間ももったいないしね。

さて、今日もオートレイアウトとの格闘が続くか・・・。

少女とドラゴン -幻獣契約クリプトラクト- - メイン

トラックバック(0)

トラックバックURL:

コメントする