Target / Action์€ ์‚ฌ์šฉ์ž interaction์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์ฃผ์š” ๋ฐฉ๋ฒ•์œผ๋กœ ์•Œ๋ ค์ ธ์žˆ๋‹ค. ๋ฌธ์„œ๋ฅผ ์ฝ์œผ๋ฉฐ ์•Œ์•„๋ณด์ž.

Target/Action

Target/Action์€ ๋Œ€ํ‘œ์ ์ธ ๋น„๋™๊ธฐ ์ด๋ฒคํŠธ์ด๋‹ค. Action์ด ์™”์„ ๋•Œ, ์ฒ˜๋ฆฌ๋˜๋Š” ๋ฐฉ์‹์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๊ฐ„๋‹จํ•˜๊ฒŒ Target/Action์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์ž. ๊ฐ์ฒด๊ฐ„์˜ ์†Œํ†ต์„ ์œ„ํ•ด delegation, notification ๋“ฑ์ด ์žˆ์œผ๋‚˜, ์ด๊ฒƒ๋งŒ์œผ๋กœ๋Š” ํ™”๋ฉด์ƒ์— ๋ณด์ด๋Š” ๊ฒƒ๋“ค์˜ ์†Œํ†ต์—๋Š” ๋ถ€์กฑํ•จ์ด ์žˆ๋‹ค. User Interface์—์„œ ๊ฐ€์žฅ ์ „ํ˜•์ ์ธ ๊ฒƒ์€ Graphic ์š”์†Œ์ด๊ณ , ์ด๊ฒƒ๋“ค์„ ๊ตฌ์„ฑํ•˜๋Š” ๋Œ€๋ถ€๋ถ„์€ Control์ด๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ๋งˆ์ฃผํ•˜๋Š” Control์€ ๋ณดํ†ต, Button, SLider, Checkbox ๋“ฑ๋“ฑ์ด ์žˆ๋‹ค. ์ด ๋…€์„๋“ค๊ณผ์˜ ์›ํ• ํ•œ ์†Œํ†ต์„ ์œ„ํ•ด ํ•ด๋‹น ๊ตฌ์กฐ๋ฅผ ์ฑ„ํƒํ–ˆ๋‹ค.

Control์˜ ์—ญํ• ์„ ๊ต‰์žฅํžˆ ๊ฐ„๋‹จํ•œ๋ฐ, ์‚ฌ์šฉ์ž์˜ ์˜๋„๋ฅผ ํ•ด์„ํ•˜๊ณ , ๊ทธ ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค๋ฅธ ๋Œ€์ƒ์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฒƒ์ด๋‹ค. ์ฆ‰ ํŠน์ • Action์ด ์ทจํ•ด์งˆ ๊ฒฝ์šฐ, ์ด๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ์ด ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋‹ค๋ฅธ ๋…€์„์„ ๊ฐ€๋ฆฌํ‚ค๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์—ฌ๊ธฐ์„œ ์ „๋‹ฌํ•  ๋•Œ๋Š” ๋งŽ์€ ์ •๋ณด๋ฅผ ํฌํ•จํ•˜์ง€ ์•Š๊ณ , ์‚ฌ์šฉ์ž๊ฐ€ ์–ด๋–ค Action์„ ์ทจํ–ˆ๋Š”์ง€์— ๋Œ€ํ•ด์„œ๋งŒ ์•Œ๋ ค์ค€๋‹ค. ์ด๋Ÿฐ ๊ฒƒ์„ Target/Action ๋งค์ปค๋‹ˆ์ฆ˜์ด๋ผ ํ•œ๋‹ค.

Objective C ๋Ÿฐํƒ€์ž„์„ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์—, Code๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” @objc ๋ฅผ ์ ์–ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

// ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹
@objc func doSomething(_ sender: Any) {
 
}
 
// ์ธํ„ฐํŽ˜์ด์Šค ๋นŒ๋”
@IBAction func doSomething(_ sender: Any) { 
 
}

Code๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ƒ๋Œ€์ ์œผ๋กœ ์ต์ˆ™ํ•˜์ง€ ์•Š์œผ๋‹ˆ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ ์–ด๋ณด๊ฒ ๋‹ค.

class ViewController: UIViewController {
	
    private let button: UIButton = { 
    	let button = UIButton() 
    	button.setTitle("๋‚˜๋ฅผ ๋ˆŒ๋Ÿฌ์ค˜", for: .normal) 
    	button.setTitleColor(.red, for: .normal) 
    	return button 
    }()
    
    override func viewDidLoad() {
    	super.viewDidLoad()
    	self.setupConstraint()
        self.button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
    }
 
    private func setupConstraint() {
        self.view.addSubview(button)
        button.translatesAutoresizingMaskIntoConstraints = false 
        button.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true 
        button.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
    }
    
    @objc private func buttonAction(_ button: UIButton) { 
        print("๋ฒ„ํŠผ์ด ๋ˆŒ๋ ธ์Šต๋‹ˆ๋‹ค.") 
    }
 
}

UIControl

UIKit์—์„œ๋Š” UIControl ๊ฐ์ฒด๋ฅผ ์ƒ์†๋ฐ›์•„์„œ Customizing ํ•  ์ˆ˜ ์žˆ๋‹ค. Control๋“ค์˜ base class๋กœ์„œ, visual element๋“ค์ด ํŠน์ • Action ํ˜น์€ ์‚ฌ์šฉ์ž interaction์„ ์ „๋‹ฌํ•˜๋Š” ๋…€์„์ด๋‹ค. ์œ„์—์„œ ๋ณด์•˜๋˜ Button, Slider, TextField๋“ค์ด ๊ทธ ์˜ˆ๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค.

UIControl ๊ฐ์ฒด๋Š” ์ง์ ‘์ ์œผ๋กœ ์ƒ์„ฑํ•˜๋ฉด ์•ˆ๋œ๋‹ค. Subclassingํ•˜์—ฌ ๋‚˜๋งŒ์˜ Control ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค๊ณ , ๊ทธ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

์ด๋ฒคํŠธ๊ฐ€ ์ผ์–ด๋‚˜๊ฒŒ ๋˜๋ฉด, control์€ ์–ฝํžŒ Action์„ ๋ฐ”๋กœ ํ˜ธ์ถœํ•œ๋‹ค. ๊ทธ๋Ÿผ ์ด method๋ฅผ ์‹ค์ œ๋กœ ์ฐพ์•„์„œ ์‹คํ–‰ํ•ด์•ผ ํ• ํ…๋ฐ, ๊ทธ๊ฑด UIApplication์ด ์ˆ˜ํ–‰ํ•œ๋‹ค. ์ด ๊ณผ์ •์—์„œ ๋งŒ์•ฝ ํ•„์š”ํ•˜๋‹ค๋ฉด responder chain์„ ๋”ฐ๋ผ์„œ ๋ฉ”์‹œ์ง€๋ฅผ ์ „๋‹ฌํ•œ๋‹ค. Responder Chain์ด ๊ถ๊ธˆํ•˜๋‹ค๋ฉด ์ด ๊ธ€์„ ์ฐธ๊ณ ํ•˜์ž.

Customizing์€ ๊ฐ„๋‹จํ•˜๋‹ค. ๋‚ด๋ถ€ CALayer์ฒ˜๋ฆฌ๊ฐ€ ๋ณต์žกํ•ด์„œ ๊ทธ๋ ‡์ง€.

class MyCustomControls: UIControl {
     func someMethodThatChangesValue() {
          self.sendActions(for: .valueChanged)
     }
}
 
myCustomControl = MyCustomControls()
myCustomControl.addTarget(self, action: #selector(yourAction), .valueChanged)

์ด๋Ÿฐ์‹์œผ๋กœ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ฐ™์€ Control ๊ฐ์ฒด๋ผ๋„ ์–ด๋–ค Event์ด๋ƒ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ Action์„ ๋ฐ”์ธ๋”ฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฒคํŠธ์˜ ์ข…๋ฅ˜๋Š” UIControl.Event๋ฅผ ์ฐธ๊ณ ํ•˜์ž.

๋˜ํ•œ Control๊ฐ์ฒด๋Š” ์ƒํƒœ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค. ์„ ํƒ๋œ ์ƒํƒœ, ํ™œ์„ฑํ™” ์ƒํƒœ ๋“ฑ ๋‹ค์–‘ํ•œ ๊ฐ’์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค. ์ด ๊ฐ’๋„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, UIControl.State๋ฅผ ์ฐธ๊ณ ํ•˜์ž.

Reference