web-dev-qa-db-ja.com

Swiftでセレクタにパラメータを渡す

大学のコースの読書課題を追跡するためのアプリを作成しています。各ReadingAssignmentには、リーダーが課題の読み取りを完了したかどうかを示すブール値が含まれています。 ReadingAssignmentは、WeeklyAssignment配列に収集されます。ユーザーがラベルに触れてチェックマークを表示し、割り当てが完了したことを表示できるようにしたい。このタッチで.checkedプロパティもtrueに更新して、データを永続化できるようにします。それで、私はジェスチャーレコグナイザーにlabelTicked()メソッドを呼び出させようとしています。これは機能し、コンソールに出力されます。ただし、割り当てパラメーターを渡そうとすると、コンパイルは行われますが、「認識できないセレクター」エラーが発生してクラッシュします。私はここで見つけることができるすべてのトピックを読みましたが、解決策を見つけていません。 「:」はパラメータ付きのセレクタであることを意味しますが、実行できません。私が間違っていることを理解できますか?

func configureCheckmark(cell: UITableViewCell, withWeeklyAssignment assignment: WeeklyAssignment) {

    let checkLabel = cell.viewWithTag(1002) as! UILabel
    checkLabel.userInteractionEnabled = true
    let gestureRecognizer = UITapGestureRecognizer(target: self, action: Selector("labelTicked:assignment"))
    checkLabel.addGestureRecognizer(gestureRecognizer)

}

@objc func labelTicked(assignment: WeeklyAssignment) {

    assignment.toggleCheckmark()

        if assignment.checked {
            label.text = "✔︎"
        } else {
            label.text = ""
        }
}

LabelTicked()メソッドで更新できるように、UILabel checkLabelも渡したいと思います。ご協力いただきありがとうございます。

9
Cyrus Price

ここには2つの明確な問題があります。

  1. セレクタの構文が間違っています。 _:_は、パラメーター部分の始まりを示しません。単に、この関数がパラメーターを取ることを示すだけです。したがって、タップ認識機能はUITapGestureRecognizer(target: self, action: "labelTicked:")として初期化する必要があります。簡単な修正。それは朗報です。

  2. 悪いニュース:完全な構文を使用しても、ここで設定した方法では機能しません。タップ認識機能は、WeeklyAssignmentオブジェクトをパラメーターとして渡すことができません。実際、カスタムパラメータを渡すことはできません。少なくとも、そうではありません。

ただし、渡すことができるのはそのsender(通常、ジェスチャレコグナイザがアタッチされているビュー)です。メソッドを次のように変更して取得できます

_func labelTicked(sender: AnyObject) {
_

(何を期待するかが正確にわかっている場合は、AnyObjectをより具体的な型として宣言できることに注意してください。)

送信者を通過すると、理論的には、どのラベルがタップされたのか、どのデータエンティティがラベルに対応しているのか、そのエンティティのcheckedプロパティがどの状態にあるのかを理論的に推測できます。非常にすばやく複雑になりました。

一見単純なものが複雑になることは、通常、一歩下がってより良い解決策を探すべきであるという良い兆候です。

この時点でGestureRecognizerアプローチ全体を削除することをお勧めします。代わりに、テーブルビューの各セルに、独自の「タップ再認識」機能がすでに備わっているという事実を利用します:_didSelectRowAtIndexPath:_テーブルビューのデリゲートのメソッド。そこでは、提供されているNSIndexPathを使用して、対応するモデルエンティティをデータソースから簡単に取得し、必要に応じてパラメーターを読み取って変更できます。 _cellForRowAtIndexPath:_を使用して、正しいセルへの参照を取得し、それに応じてその内容を変更できます。


Swift 3の更新:

Swift言語が進化し、文字列ベースのセレクターの使用(たとえば、_"labelTicked:"_)が非推奨としてフラグが立てられたので、答えに小さな更新を提供することが適切だと思います。

より最新の構文を使用すると、次のように関数を宣言できます。

_@objc func labelTicked(withSender sender: AnyObject) {
_

_#selector_を使用して、次のようにジェスチャーレコグナイザーを初期化します。

_UITapGestureRecognizer(target: self, action: #selector(labelTicked(withSender:)))
_
22
Gamma

その関数の正しいセレクタは_labelTicked:_です。さらに、文字列をセレクタとして直接使用できます。したがって:

_let gestureRecognizer = UITapGestureRecognizer(target: self, action: "labelTicked:")
_

ただし、認識エンジンが起動したときに、メソッドに任意のオブジェクトを渡すように調整することはできません。これを行うためのより良い方法は、UITableViewCellのサブクラスを作成することです。 AssignmentCellとしましょう。サブクラスにassignmentプロパティを指定し、_labelTicked:_メソッドをAssignmentCellに移動します。

ストーリーボードでセルを設計した場合は、タップ認識機能をストーリーボードの右側のラベルに追加し、認識機能をストーリーボードのセルの_labelTicked:_メソッドに配線できます。

テーブルビューデータソースのtableView(_:cellForRowAtIndexPath:)で、セルをデキューした後、そのassignmentプロパティをその行の割り当てに設定します。

4
rob mayoff