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さんに教えていただきました。