イラストレーターみやびの漫画館 作品集 - 月の高いところのロゴマーク

イラスト作品集 月の高いところ

「イラストレーターみやびの漫画館 作品集 - 月の高いところ」とは、自称イラストレーターみやびプリンの、イラストを中心とし、音楽、映像など、総合的にデザイン作品を掲載しているポートフォリオサイトです。 詳しくはこちら>>

今日のプリン言 -謎のプリン語る-

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

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

どうも。
すっかりどっぷり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先生と対話するのもいいんだけど、
的外れな記事ばかり出ると、イライラしかしないし、時間ももったいないしね。

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

新着情報 NEW