Swiftにおけるセレクタ(Selector)について調べてみた

公開日: : iPhoneアプリ開発

20160212-000722.jpg

NSTimerなどを使う際、引数に「Selector」という型があるのですが、これがSwiftではどのような扱いになっているのかを少し調べてみました。

    

スポンサード リンク

Selectorの使用例 : タイマーの初期化処理

例えばタイマー処理を行う場合、例えば以下のようなコードを書いて初期化を行います。

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        NSTimer.scheduledTimerWithTimeInterval(
            1, target: self, selector: "update:", userInfo: nil, repeats: true)
    }

    func update(timer:NSTimer) {
        print(timer)
    }
}

    

scheduledTimerWithTimeIntervalメソッドの宣言は以下のようになっています。

public class func scheduledTimerWithTimeInterval(ti: NSTimeInterval, target aTarget: AnyObject, selector aSelector: Selector, userInfo: AnyObject?, repeats yesOrNo: Bool) -> NSTimer

引数targetと引数selectorを使って、定期的にどのメソッドを呼ばせるのかを指定します。

    

引数targetの型はAnyObjectなので、任意のクラスインスタンスを渡すことができます。

では、引数selectorの型「Selector」とは、一体何なのでしょうか?

    

Selectorの宣言

Swiftにおいて、Selectorは以下のように宣言されています。

/// The Objective-C SEL type.
///
/// The Objective-C SEL type is typically an opaque pointer. Swift
/// treats it as a distinct struct type, with operations to
/// convert between C strings and selectors.
///
/// The compiler has special knowledge of this type.
public struct Selector : StringLiteralConvertible, NilLiteralConvertible {
    /// Create a selector from a string.
    public init(_ str: String)
    /// Create an instance initialized to `value`.
    public init(unicodeScalarLiteral value: String)
    /// Construct a selector from `value`.
    public init(extendedGraphemeClusterLiteral value: String)
    /// Create an instance initialized to `value`.
    public init(stringLiteral value: String)
    public init()
    /// Create an instance initialized with `nil`.
    public init(nilLiteral: ())
}

また、Selectorが適合している「StringLiteralConvertible」と「NilLiteralConvertible」の宣言は以下の通りです。

/// Conforming types can be initialized with arbitrary string literals.
public protocol StringLiteralConvertible : ExtendedGraphemeClusterLiteralConvertible {
    typealias StringLiteralType
    /// Create an instance initialized to `value`.
    public init(stringLiteral value: Self.StringLiteralType)
}
/// Conforming types can be initialized with `nil`.
public protocol NilLiteralConvertible {
    /// Create an instance initialized with `nil`.
    public init(nilLiteral: ())
}

よって、Selectorとして文字列で指定することもできるし、nilで指定することもできるようになっています。

Selector型は構造体で、文字列を引数とするイニシャライザを持ちます。インスタンスobjに対し、引数のないメソッドsay()をセレクタを使って呼び出すには次のようにします。ここでperformSelector(_:)はNSObjectのメソッドです。

let sel = Selector(“say”)
obj.performSelector(sel)

Selector型はプロトコルStringLiteralConvertibleを採用しているため、セレクタの代わりに文字列リテラルを記述することもできます。自動的にイニシャライザが呼び出されます。

obj.performSelector(“say”)

引用元 : 詳解 Swift 改訂版

    

Selectorの実装

なお、「swift/ObjectiveC.swift at 4d0c060e2189571b0103fa5473ed8d8145d0e231 · apple/swift」をチェックしてみると、Selectorの実装は以下のようになっていました。

/// The Objective-C SEL type.
///
/// The Objective-C SEL type is typically an opaque pointer. Swift
/// treats it as a distinct struct type, with operations to
/// convert between C strings and selectors.
///
/// The compiler has special knowledge of this type.
public struct Selector : StringLiteralConvertible, NilLiteralConvertible {
  var ptr : COpaquePointer

  /// Create a selector from a string.
  public init(_ str : String) {
    ptr = str.withCString { sel_registerName($0).ptr }
  }

  /// Create an instance initialized to `value`.
  public init(unicodeScalarLiteral value: String) {
    self.init(value)
  }

  /// Construct a selector from `value`.
  public init(extendedGraphemeClusterLiteral value: String) {
    self.init(value)
  }

  // FIXME: Fast-path this in the compiler, so we don't end up with
  // the sel_registerName call at compile time.
  /// Create an instance initialized to `value`.
  public init(stringLiteral value: String) {
    self = sel_registerName(value)
  }

  public init() {
    ptr = nil
  }
  
  /// Create an instance initialized with `nil`.
  @_transparent public
  init(nilLiteral: ()) {
    ptr = nil
  }
}

@warn_unused_result
public func ==(lhs: Selector, rhs: Selector) -> Bool {
  return sel_isEqual(lhs, rhs)
}

extension Selector : Equatable, Hashable {
  /// The hash value.
  ///
  /// **Axiom:** `x == y` implies `x.hashValue == y.hashValue`
  ///
  /// - Note: the hash value is not guaranteed to be stable across
  ///   different invocations of the same program.  Do not persist the
  ///   hash value across program runs.
  public var hashValue: Int {
    return ptr.hashValue
  }
}

extension Selector : CustomStringConvertible {
  /// A textual representation of `self`.
  public var description: String {
    if let s = String.fromCStringRepairingIllFormedUTF8(sel_getName(self)).0 {
      return s
    }
    return "<NULL>"
  }
}

extension String {
  /// Construct the C string representation of an Objective-C selector.
  public init(_sel: Selector) {
    // FIXME: This misses the ASCII optimization.
    self = String.fromCString(sel_getName(_sel))!
  }
}

extension Selector : CustomReflectable {
  /// Returns a mirror that reflects `self`.
  public func customMirror() -> Mirror {
    return Mirror(reflecting: String(_sel: self))
  }
}
  • Equatableプロトコルに適合しているので==演算子で比較することができる
  • Hashableプロトコルに適合しているのでSetなどに入れられる
  • CustomStringConvertibleプロトコルに適合しているのでprintなどでログ出力したりできる

ということが分かります。

    

@akio0911はこう思った。

「Selector型って書いてあるのに、なんでStringを渡せるんだろう?」って思ってたんですが、StringLiteralConvertibleプロトコルに適合していたんですね。

Swiftにおけるプロトコルの活用方法が少し分かった気がしました。

    

この記事が気に入ったら「いいね!」しよう

follow us in feedly

Feedlyで最新記事を購読

Twitterで更新情報をゲット!

LINEでご感想・ご要望お送りください!
(スマホでLINEを起動 > 友だち追加 > QRコード)

関連記事

Auto LayoutやStoryboardの仕組みをしっかり理解できる!「UIKit徹底解説」

インプレスジャパン様より献本御礼。UIKit周りを中心に、「Auto Layout」「Story

記事を読む

20141222-120336.jpg

【Swift】PlaygroundでUIImageに画像を読み込む方法

SwiftのPlayground内にて、UIImageに画像ファイルを読み込む方法を紹介しま

記事を読む

20140721-170305.jpg

プロトタイピングのツールや手法を学べる「プロトタイピング実践ガイド」

株式会社インプレスさまより献本御礼。 プロトタイピング実践ガイド スマホアプリの効率的なデザイ

記事を読む

I20160210-140020.jpg

【Xcode】モーダル表示で遷移先へ値を渡す時のハマりポイント

モーダル表示で遷移先の画面へ値を渡す際、最初はハマりやすいポイントについて解説したいと思いま

記事を読む

I20150722-185359.jpg

【書籍】12のパターンで学ぶ本「iOSアプリ開発 AutoLayout徹底攻略」

     Auto Layoutの使い方について解説されている本「iOSアプリ開発 A

記事を読む

20160420-180135.jpg

【RxSwift】2つのUITextFieldに入力された数値の合計をUILabelに表示する

そろそろRxSwiftについて学び始めよう!ということで、まずは2つのUITex

記事を読む

I20150714-010114.jpg

【Swift】Objective-Cで書いたクラスをメソッド単位で少しずつSwiftへ移行する方法

Objective-Cで作った既存のアプリをSwiftで書き直したいと思っているのですが、一

記事を読む

I20160125-104438.jpg

iPhoneアプリの開発に必要なものをまとめてみた

僕はアプリ開発講座を開催していますが、その関係もあって「iPhoneアプリを開発するには、ど

記事を読む

20150104-120413.jpg

【おすすめ本】Swiftではじめる iPhoneアプリ開発の教科書【iOS 8&Xcode 6対応】

     入門者にオススメな、Swift&Xcode 6の入門書「Swiftではじめる

記事を読む

I20160228-162014.jpg

詳解 Swift 改訂版のKindle版が発売。リフローに対応!

今日気付いたんですが、「詳解 Swift 改訂版」のKindle版がいつの間にか発売されていまし

記事を読む

I20170521-225453.jpg
東京駅八重洲口の「羊肉酒場 悟大」で網焼きジンギスカンを頂きました!

ゆうせいさんと株式会社 大庄さんからご招待頂き、悟大withサッポ

I20170514-165235.jpg
iPhoneと連携できる体重体組成計「Withings Body Cardio」を使ってます

ジムに通い始めて体脂肪率が落ち始めたのをキッカケに、iPhoneと

I20170507-155440.jpg
【派手髪】ハーレイクイン風の髪色に染めてもらいました

2016年10月20日、ハーレイクイン風の髪色に染めてもらいました

I20170504-173110.jpg
【メンズネイル】東京・新宿のネイルサロンでターコイズのホログラムネイルしてもらった

ネイルネタが1年分くらい溜まっているので、ちょっとずつ書いていこう

I20170502-010117.jpg
SNUGGのライトニングケーブルが耐久性高し。8ヶ月使ってますが断線の気配なし!

iPhoneの充電&転送ケーブルであるLightningケーブルっ

→もっと見る

PAGE TOP ↑