SwiftにおけるSelector(SEL)の比較


OS XにおいてObjective-CのコードをSwiftに書き換えています。

[code]

    - (BOOL)validateMenuItem:(NSMenuItem *)menuItem
    {
        SEL action = menuItem.action;
    
        if(action == @selector(reloadContent:)) {
            return YES;
        }
        return NO;
    }
    
[/code]

上記の-validateMenuItem:を書き換えようと思ったのですがSELの比較をSwiftでどのように書けばよいのか分かりません。  
Swiftではどのように書けばよいのでしょうか？




Swiftでは、

[code]

    "reloadContent:"
    
[/code]

のような文字列リテラルが`SEL`として扱われます。

このことから、「文字列＝セレクタ」と誤解する向きがありますが、これはコンパイラによる特別扱いで、実際には文字列リテラルから`Selector`構造体が作られています。

`Selector`構造体の定義を読めば分かりますが、`StringLiteralConvertible`プロトコルに準拠しています。ですので、文字列リテラルと比較することは可能です。

ただし、

[code]

    if menuItem.action == "reloadContent:" {
        return true
    }
    
[/code]

のような処理で、`StringLiteralConvertible`としての比較が優先されるのか、`"reloadContent:"`がコンパイラに特別扱いされ`Selector`型同士で同値比較されているのかは、実装次第なので外部から判断が付かない気がします。

その他、移植されたObjective-Cランタイム関数を用いて、

[code]

    sel_isEqual(menuItem.action, "reloadContent:" )
    
[/code]

で比較することもできます。

* * *

**EDIT:**

本題から外れますが、@Harawo
さんの回答の「文字列定数は、自動でSelectorに変換される」という解釈は誤りですので、それを説明するPlayground上で実行できる、簡単なコードを掲載しておきます。（実行環境はXCode
6.3beta、Swift1.2です）

[code]

    let aSelector : Selector = "action:"    //型宣言したセレクタ
    let aConstant : String = "action:"      //文字列定数
    var aString = "action:"                 //型推論させる
    
    
    aSelector == "action:"  // true
    aConstant == "action:"  // true
    
    aSelector == aConstant  // compilation error
    aSelector == aString    // compilation error!!
    
[/code]

文字列定数、というと一般には`let`で宣言した`String`をイメージしますので、その前提で話をしますが、
**Swiftには型の暗黙変換が一切存在しない** ので、文字列定数と`Selector`構造体を比較した場合、`Binary operator '=='
cannot be applied to operands of type 'Selector' and
'String'`というコンパイルエラーになります。

あくまで比較できるのは **文字列リテラル** （リテラルとは、ソースコード中に直接記述されているもの）だけです。文字列、文字列定数とは比較できません。

余談として、型推論させた場合でも`String`として解釈されてエラーになります。

一方で、「Swiftには型の暗黙変換が存在しない」という前言と矛盾しますが、Objective-
Cとの互換のために、`Selector`構造体はC文字列（オペイクポインタである`SEL`の実体）との間で相互に変換することができます。




Swiftでは、

[code]

    "reloadContent:"
    
[/code]

のような文字列リテラルが`SEL`として扱われます。

このことから、「文字列＝セレクタ」と誤解する向きがありますが、これはコンパイラによる特別扱いで、実際には文字列リテラルから`Selector`構造体が作られています。

`Selector`構造体の定義を読めば分かりますが、`StringLiteralConvertible`プロトコルに準拠しています。ですので、文字列リテラルと比較することは可能です。

ただし、

[code]

    if menuItem.action == "reloadContent:" {
        return true
    }
    
[/code]

のような処理で、`StringLiteralConvertible`としての比較が優先されるのか、`"reloadContent:"`がコンパイラに特別扱いされ`Selector`型同士で同値比較されているのかは、実装次第なので外部から判断が付かない気がします。

その他、移植されたObjective-Cランタイム関数を用いて、

[code]

    sel_isEqual(menuItem.action, "reloadContent:" )
    
[/code]

で比較することもできます。

* * *

**EDIT:**

本題から外れますが、@Harawo
さんの回答の「文字列定数は、自動でSelectorに変換される」という解釈は誤りですので、それを説明するPlayground上で実行できる、簡単なコードを掲載しておきます。（実行環境はXCode
6.3beta、Swift1.2です）

[code]

    let aSelector : Selector = "action:"    //型宣言したセレクタ
    let aConstant : String = "action:"      //文字列定数
    var aString = "action:"                 //型推論させる
    
    
    aSelector == "action:"  // true
    aConstant == "action:"  // true
    
    aSelector == aConstant  // compilation error
    aSelector == aString    // compilation error!!
    
[/code]

文字列定数、というと一般には`let`で宣言した`String`をイメージしますので、その前提で話をしますが、
**Swiftには型の暗黙変換が一切存在しない** ので、文字列定数と`Selector`構造体を比較した場合、`Binary operator '=='
cannot be applied to operands of type 'Selector' and
'String'`というコンパイルエラーになります。

あくまで比較できるのは **文字列リテラル** （リテラルとは、ソースコード中に直接記述されているもの）だけです。文字列、文字列定数とは比較できません。

余談として、型推論させた場合でも`String`として解釈されてエラーになります。

一方で、「Swiftには型の暗黙変換が存在しない」という前言と矛盾しますが、Objective-
Cとの互換のために、`Selector`構造体はC文字列（オペイクポインタである`SEL`の実体）との間で相互に変換することができます。

