12
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【UIButton】addTargetのSelector経由でString型パラメタを渡す【Swift3.0】

Last updated at Posted at 2017-01-05

UIButtonのaddTargetメソッドに指定するファンクションに固有のパラメタを設定するときの話です。数値であればtagプロパティが使えますが、場合によっては文字列を渡したいこともあります。

1. もともと持っているプロパティを流用する

accessibilityValueを利用している例。本来の用途と違う使われ方をしちゃうと可読性が落ちますね...


//
//  ViewController.swift
//

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

    
        let button = UIButton(frame: CGRect(x:0,y:0,width:120,height:30))
        button.center = view.center
        button.layer.backgroundColor = UIColor.red.cgColor
        button.setTitle("私はボタン", for: .normal)
        button.accessibilityValue = "AAAAAAAAAAAAA"
        button.addTarget(self, action: #selector(ViewController.pushButton), for: .touchUpInside)
        
        view.addSubview(button)
    
    }

    func pushButton(_ sender:UIButton) {
        
        print(sender.accessibilityValue) // AAAAAAAAAAAAA
    }
    
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

2. UIButtonを継承したサブクラスを作成

一番ポピュラーな方法でしょう。例は固有のプロパティ(stringValue)を追加したMyButtonクラスを作成。

//
//  ViewController.swift
//

import UIKit

// UIBUttonを継承したクラスを作成
class MyButton:UIButton {
    var stringValue:String?
}

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

    
        let button = MyButton(frame: CGRect(x:0,y:0,width:120,height:30))
        button.center = view.center
        button.layer.backgroundColor = UIColor.red.cgColor
        button.setTitle("私はボタン", for: .normal)
        button.stringValue = "AAAAAAAAAAAAA"
        button.addTarget(self, action: #selector(ViewController.pushButton), for: .touchUpInside)
        
        view.addSubview(button)
    
    }

    func pushButton(_ sender:MyButton) {
        
        print(sender.stringValue) // AAAAAAAAAAAAA
    }
    
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

3. UIButtonを拡張する

Protocol Extensionを利用して強引にUIButtonに保存型プロパティを追加する方法です。冗長ですが、場合によっては既存のプロジェクトの改修などでは修正量が減らせるかも。

参考:Swiftのextensionでstored Propertyを追加する?(黒魔術は閉じ込める)

//
//  ViewController.swift
//

import UIKit

protocol HasAssociatedObjects {
    var associatedObjects: AssociatedObjects { get }
}

private var AssociatedObjectsKey: UInt8 = 0

extension HasAssociatedObjects where Self: AnyObject {
    
    var associatedObjects: AssociatedObjects {
        guard let associatedObjects = objc_getAssociatedObject(self, &AssociatedObjectsKey) as? AssociatedObjects else {
            let associatedObjects = AssociatedObjects()
            objc_setAssociatedObject(self, &AssociatedObjectsKey, associatedObjects, .OBJC_ASSOCIATION_RETAIN)
            return associatedObjects
        }
        return associatedObjects
    }
    
}

// UIButtonにstoredPropertyを追加!
extension UIButton: HasAssociatedObjects {
    var storedProperty: String? {
        get {
            return self.associatedObjects["HOGE"] as? String
        }
        set {
            self.associatedObjects["HOGE"] = newValue
        }
    }
}

class AssociatedObjects: NSObject {
    
    var dictionary: [String: Any] = [:]
    
    subscript(key: String) -> Any? {
        get {
            return self.dictionary[key]
        }
        set {
            self.dictionary[key] = newValue
        }
    }
    
}

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

    
        let button = UIButton(frame: CGRect(x:0,y:0,width:120,height:30))
        button.center = view.center
        button.layer.backgroundColor = UIColor.red.cgColor
        button.setTitle("私はボタン", for: .normal)
        button.storedProperty = "AAAAAAAAAAAAA"
        button.addTarget(self, action: #selector(ViewController.pushButton), for: .touchUpInside)
        
        view.addSubview(button)
    
    }

    func pushButton(_ sender:UIButton) {
        
        print(sender.storedProperty) // AAAAAAAAAAAAA
    }
    
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

おまけ

UIButtonのメソッドに、setValue(_ value: Any?, forKey key: String)ってのとvalue(forKey key: String) -> Any?ってのを見つけて、「おっ、これキー指定で保存できんのかな?」と思って試してみたらビルドは出来るものの、ランタイム時にアベンドしました。どうやら内部にて使われるものらしく任意に呼び出してはいけないっぽいです。

追記 2017/1/6

setValue(_ value: Any?, forKey key: String)value(forKey key: String) -> Any?の件ですが、

Key-Value Coding用のメソッドです。UIButtonのメソッドではなくNSObjectのメソッドになります。例えばUIButtonのtagに数値を入れる時に以下のように使えます。


let button = UIButton()
//通常はこう
button.tag = 10

//KVCだとこう
button.setValue(10, forKey: "tag")

furuyanさんに教えていただきました。

12
11
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?