์ด์ ํฌ์คํ ์์ ์์กด์ฑ(Dependency)์ด ๋ฌด์์ธ์ง, ์์กด์ฑ ์ฃผ์ (Dependency Injection)์ด ๋ฌด์์ธ์ง ์์ ๋ดค์ต๋๋ค!
์ค๋์ ์์กด์ฑ ์ฃผ์ ํ๋ ์ฌ๋ฌ ๋ฐฉ๋ฒ์ ํฌ์คํ ํ๋ ค๊ณ ํด์.
๊ฐ๋ฐํ ๋ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ , ๊ทธ ๊ฐ์ฒด๊ฐ ํ์๋ก ํ๋ ๋ฐ์ดํฐ๋ ๊ฐ์ฒด๋ฅผ ๋๊ฒจ ์ฃผ๋ ๊ฒ์ ๋ํด์๋ ๋ค๋ค ๊ฒฝํํ์ จ์ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ์ฝ์ด ๋ณด์๋ฉด ๊ฐ์ด ์กํ ํ ์ง๋ง ๊ทธ๋๋ DI๋ฅผ ๋ณด๊ณ ์ค์๋ฉด ์ดํด๊ฐ ๋ ์ฝ๊ฒ ์ ๋ ๊ฑฐ์์! DI์ ๋ํด ์์๋ณด๋ ค๋ฉด ์ด ๊ธ์ ์ฐธ๊ณ ํด ์ฃผ์ธ์!
iOS ์ฑ์ ๋ง๋ค๋ ์ฐ์ ๊ฐ๋ฐ ์ผ์ ์ ๋ง์ถ์ด ์๋์ด ๋๋๋ก ๊ตฌํํ๋ ๊ฒ๋ ์ค์ํ๊ฒ ์ง๋ง, ํ๋ก์ ํธ๊ฐ ์ปค์ง๊ณ ๊ทธ์ ๋ฐ๋ผ ํ๋ฉด์ด ๋ง์์ง๋ฉด์ ์ฒ๋ฆฌํด์ผ ํ ๋ฐ์ดํฐ์ ์์กด๊ด๊ณ๋ ๋ง์์ง๋๋ค. ์ด๋ ์ด๋ป๊ฒ ํ๋ฉด ์ข๋ ํจ๊ณผ์ ์ผ๋ก ์์กด๊ด๊ณ๋ฅผ ์ ์ํ๊ณ ์ ์ง๋ณด์ ์ธก๋ฉด์์ ์ ๋ฆฌํ๊ฒ ๋ง๋ค ์ ์์๊น์? ๊ธด๋ฐํ๊ฒ ์ฐ๊ฒฐ๋์ด ์๋ ํ๋ฉด์ด๋ ๊ฐ์ฒด๋ ์ด์ ์ผ๊น์? ๋จ์ ์ผ๊น์?
์์กด์ฑ์ ์ฃผ์ ํ๋ ๋ค์ํ ๋ฐฉ๋ฒ์ ๋ณด๋ฉด์ ์ด๋ค ํน์ง์ด ์๊ณ ์ด๋ค ์ผ์ด ์ผ์ด ๋ ์ ์๋์ง ์์๋ด ์๋ค!
1. Constructor Injection
์ฐ์ ์ฒซ ๋ฒ์งธ "Constructor Injection" ์ ๋๋ค! ์ฉ์ด๊ฐ ์ด๋ ค์ ๋ณด์ด์ง๋ง ๋ง๊ทธ๋๋ก ์์ฑ์๋ฅผ ์ด์ฉํ ์์กด์ฑ ์ฃผ์ ์ด์์
ํญ์ ์ฌ์ฉ๋๋ ๋ฐฉ์์ ์๋์ง๋ง, ์์ฃผ ์ฌ์ฉ๋๋ ๋ฐฉ์์ด๋ฉด์๋ ์์ฑ์ ๊ผญ ํ์ํ ๋ฐ์ดํฐ๊ฐ ์์ ๋ ๋ง์ด ์ฌ์ฉ๋๋ ๋ฐฉ๋ฒ์ ๋๋ค!
struct AViewModel { }
struct BViewModel { }
class BViewController: UIViewController {
let viewModel: BViewModel
init(viewModel: BViewModel) {
self.viewModel = viewModel
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
์์ ์ฝ๋์์ BViewController๋ BViewModel์ ํ์๋ก ํฉ๋๋ค. ๋ฐ๋ผ์ ์ด ๊ฐ์ฒด๋ฅผ init์์ ์ฃผ์ ๋ฐ์ ์ค์ ํด ์ฃผ๋ ๊ฒ์ ์ ์ ์์ต๋๋ค. ์์ฑ์๋ฅผ ์ฌ์ฉํด์ ์ธ๋ถ๋ก ๋ถํฐ ํ์ํ ์์กด์ฑ์ ์ฃผ์ ๋ฐ๋ ๋ฐฉ๋ฒ์ด Constructor Injection์ ๋๋ค.
iOS ํ๋ก๊ทธ๋๋ฐ์์๋ view Life cycle๊ณผ ๊ด๋ จ๋ ๋ฉ์๋ ์ด์ ์ ์คํ๋์ด ๋ทฐ๋ฅผ ๊ทธ๋ฆฌ๊ธฐ ์ด์ ์ ๋ฏธ๋ฆฌ ํ์ํ ์ค์ ์ ํด์ค ์ ์์ผ๋ฏ๋ก ์ด๊ธฐ์ ๊ผญ ํ์ํ ๋ฐ์ดํฐ๋ ๊ฐ์ฒด๊ฐ ์์ ๋ ์ฌ์ฉ๋ฉ๋๋ค.
init(viewModel: BViewModel, content: String?) {
self.viewModel = viewModel
self.content = content ?? ""
super.init(nibName: nil, bundle: nil)
}
๊ทธ๋ฌ๋ ๋ง์ฝ default๊ฐ ์๋ ๊ฐ์ด๋ nil ๋ฑ์ ์ ํ ์ฌํญ์ ๊ฒฝ์ฐ๋ ์ด ์์ ์ฝ๋์ฒ๋ผ ์ฌ์ฉํ๊ธฐ ๋ณด๋ค๋ Property Injection์ ์ฌ์ฉํฉ๋๋ค. ์์ฑ์ ๊ตณ์ด ํ์ํ ๋ฐ์ดํฐ๊ฐ ์๋๊ธฐ ๋๋ฌธ์ ๋ชจ๋ ์์กด์ฑ์ init์๊ฒ ๋ถ์ฌํ ํ์๋ ์๋ ๊ฒ์ด์ฃ !
๋ํ ์ํ์ฐธ์กฐ์ ๊ฒฝ์ฐ Constructor Injection์ ์ฌ์ฉํ๊ธฐ ํ๋ญ๋๋ค
class A {
let b: B
init(b: B) {
self.b = b
}
}
class B {
let a: A
init(a: A) {
self.a = a
}
}
์ด๋ฐ ๊ฒฝ์ฐ B๋ฅผ ์์ฑํ๋ ค๋ฉด A๊ฐ ํ์ํ๊ณ A๋ฅผ ์์ฑํ๋ ค๋ฉด B๊ฐ ํ์ํ ๊ฒฝ์ฐ์๋ init ์ ์์ ์ํด ์์ฑ ์์ฒด๊ฐ ์ด๋ ค์ฐ๋ ์ด ๋ฐฉ๋ฒ์ผ๋ก ์์กด์ฑ์ ์ฃผ์ ํ์ง ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ iOS ํ๋ก๊ทธ๋๋ฐ ๊ฐ์ ๊ฒฝ์ฐ์๋ ์ํ์ฐธ์กฐ๊ฐ ๋ฐ์ํ์ง ์๊ฒ ์ฃผ์ํด์ผ ํ๊ณ , ์ฌ๋ฌ ๋ฐฉ๋ฒ๋ค์ด ๊ณต์ ๋์ด ์์ฃ !
2. Property Injection
Property Injection์ ํ๋กํผํฐ๋ฅผ ํตํด์ ์์กด์ฑ์ ์ฃผ์ ํ๋ ๋ฐฉ์์ ๋๋ค.
struct Lecture { }
class TimeTableViewController: UIViewController {
var lecture: Lecture?
override func viewDidLoad() {
super.viewDidLoad()
}
}
class MainViewController: UIViewController {
func moveToTiemTable() {
let timeTableViewController = TimeTableViewController()
timeTableViewController.lecture = Lecture()
// ์๋ต
}
}
์์๋ก ์์ฑ๋ ์ฝ๋๋ฅผ ๋ณด์๋ฉด init์ด ์๋ property๋ฅผ ํตํด์ ์์กด์ฑ์ ์ฃผ์ ๋ฐ๋ ๊ฒ์ ์ ์ ์์ด์! ์ property Injection์ ์ฌ์ฉํ ๊น์? ์ฐ์ ๊ฐ์ฒด์ ์์กด์ฑ ์์ฑ ์์ ์ ์๊ฐํด ๋ณด๋ฉด ์ฌ์์!
๊ฐ์ฒด๋ฅผ ๋จผ์ ์์ฑํ๊ณ ๋์ค์ ์์กด์ฑ์ด ์์ฑ๋๋ ์ํฉ์์ Constructor Injection ์ ์ด์ฉํ๊ฒ ๋๋ฉด ๊ฐ์ฒด๋ฅผ ๋จผ์ ์์ฑํ ์๊ฐ ์๊ฒ ๋์ฃ ! ์์กด์ฑ ๊น์ง ํจ๊ป ๋๊ฒจ ์ฃผ์ด์ผ ํ๋ ์์กด์ฑ ๊ฐ์ฒด๊ฐ ์์ฑ๋๊ธฐ ์ ๊น์ง ๊ฐ์ฒด๋ฅผ ์์ฑํ ์ ์๊ฒ ๋ฉ๋๋ค ๐ฅฒ
๋ํ ์ ํ์ฌํญ์ ์์กด์ฑ์ธ ๊ฒฝ์ฐ init์์ ์์ฑํ๋ ๊ฒ ๋ณด๋ค ์ด๋ ๊ฒ ์ธ๋ถ์์ ํ๋กํผํฐ๋ฅผ ํตํด ๋ฐ๋ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ์ ์์ด์.
@objc func fetchLecture() {
tiemTableViewController.lecture = Lecture()
}
ํ์ง๋ง ํ๋์ ๊ฐ์ฒด์์ ํ์๋ก ํ๋ ๋ฐ์ดํฐ๋ ์ค์ ์ public ์ผ๋ก ๊ณต์ ๋๋ property๊ฐ ์๋ค๋ ์ ์์ ์บก์ํ๊ฐ ๊นจ์ง๊ธฐ ๋๋ฌธ์ ๋จ์ ์ด ์กด์ฌํฉ๋๋ค. ์ฐ์ ์ธ๋ถ์์ ์ผ๋ง๋ ์ง ๊ทธ ๊ฐ์ ๋ฐ๊ฟ ์ ์๊ณ ์ด๋ ๊ฒ ๋๋ฉด ํจ๊ป ์ผํ๋ ๋๋ฃ๊ฐ ์์น ์๊ฒ ์ฐธ์กฐํ์ฌ ๊ทธ ๊ฐ์ ์์ ํด์ ๊ผฌ์ฌ๋ฒ๋ฆฌ๋ ์ผ์ด ์๊ธธ ์๋ ์์ต๋๋ค.
3. Method Injection
์ ๊ฐ UITableViewCell์ ์์ฑ๋ค์ ๋๊ฒจ์ ํ๋ฒ์ UI๋ฅผ ์ ๋ฐ์ดํธ ํ ๋ ๋ง์ด ์ฐ๋ ๋ฐฉ๋ฒ์ด์์. public method ์ฆ, ์ธ๋ถ์์ ์ ๊ทผํ ์ ์๋ ๋ฉ์๋๋ฅผ ๊ฐ์ง๊ณ dependency ๋ฅผ ์ฃผ์ ํ๋ ๋ฐฉ๋ฒ์ ๋๋ค.
class TableViewCell: UITableViewCell {
@IBOutlet weak var titleLabel: UILabel!
// MARK: -
override func awakeFromNib() {
super.awakeFromNib()
selectionStyle = .none
}
func configuration(title: String) {
self.titleLabel.text = title
}
}
๊ฐ๋จํ ์์๋ก UITableViewCell์ ์์๋ฐ๋ TableViewCell์ ์์ฑํด ์ฃผ๊ณ method๋ฅผ ์ฌ์ฉํด์ ํ์ํ ์์กด์ฑ์ ์ค์ ํด ์ค๋๋ค.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as? TableViewCell else {
return UITableViewCell()
}
cell.configuration(title: "\(Cell(rawValue: indexPath.row) ?? .total)")
return cell
}
cell์ dequeueํ ๋ configuration ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ์์กด์ฑ์ ์ฃผ์ ํด ์ค๋๋ค. ์ด๋ฌํ ๋ฐฉ๋ฒ์ ์์์ ์ดํด ๋ดค๋ property injection๊ณผ ๋์ผํ ๋จ์ ์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ์ธ๋ถ์์ ์ผ๋ง๋ ์ง ์ ๊ทผํ์ฌ ๋ณ๊ฒฝ ๊ฐ๋ฅํฉ๋๋ค.
4. Interface Injection
๊ทธ ๋ค์์ผ๋ก๋ interface๋ฅผ ์ด์ฉํ์ฌ ์์กด์ฑ์ ์ฃผ์ ํ๋ ๋ฐฉ๋ฒ์ ๋๋ค. ์ถํ ํฌ์คํ ์์ ์๊ฐํด ๋๋ฆด ํ๋ ์์ํฌ์ ์ฑ ์ํคํ ์ฒ์์๋ ์ฌ์ฉ๋๋ ๋ฐฉ๋ฒ์ด๋ ๋์ฌ๊ฒจ ๋ด์ฃผ์ธ์!!
๊ฐ์ฒด์งํฅ ํ๋ก๊ทธ๋๋ฐ์์ ์ถ์ํ๋ผ๋ ๊ฐ๋ ์ด ์์ต๋๋ค. Swift ์์๋ ํด๋์ค๋ฅผ ์ ์ํ๋ ์ถ์ํ ๋ฐฉ๋ฒ์ Protocol์ด ์์ต๋๋ค.
Interface๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋ฉด ๊ธด๋ฐํ๊ฒ ์ฐ๊ฒฐ๋์ด ์๋ ์์กด์ฑ์ด ์ฝํด์ ธ ๋ชจ๋๊ณผ ๋ชจ๋ ์ฌ์ด์ ๊ฒฐํฉ์ด ์ค์ด ๋ญ๋๋ค.
์ฐ์ ๊ฐ๋จํ ์์๋ฅผ ํ๋ ๋ณด๊ฒ ์ต๋๋ค~
protocol Networking {
func fetchData()
}
class UserNetworkManager: Networking {
func fetchData() {
print("user data fetched")
}
}
class PostNetworkManager: Networking {
func fetchData() {
print("post data fetched")
}
}
Networking ํ๋กํ ์ฝ์ ๋ฐ๋ฅด๋ ๊ฐ์ฒด๋ fetchData์ ๊ฐ์ ํ์ํ ํจ์์ ํ๋กํผํฐ๋ฅผ ๊ตฌํํฉ๋๋ค. ๊ฐ ํด๋์ค๋ ์์ ์ ์ฉ๋์ ๋ง๊ฒ ํด๋น ํจ์๋ฅผ ๊ตฌํํ๊ณ ์์ด์! ์ฌ๊ธฐ ์ฝ๋๋ฅผ ๋ ์ถ๊ฐํ๊ฒ ์ต๋๋ค!
class MainViewController {
let networkManager: Networking
init(networkManaer: Networking) {
self.networkManager = networkManaer
}
}
MainViewController๋ ๋ฐ์ดํฐ๋ฅผ ์ป๊ธฐ ์ํด ๋คํธ์ํน์ด ํ์ํ ํด๋์ค ์ ๋๋ค. (์ ์ฝ๋์์๋ UIViewController ์์์ ์๋ตํ์ต๋๋ค)
์ด๋ NetworkManager๋ฅผ ์ง์ ์ ์ผ๋ก ๋ฐ์ง ์๊ณ Networking ์ธํฐํ์ด์ค๋ก ์ ์ํ ๋ค Constructor Injection ์ ์ด์ฉํ์ฌ ์ฃผ์ ๋ฐ์ ์ ์์ต๋๋ค. ์ ์ฝ๋๋ฅผ ์ฌ์ฉํด๋ ๋์ง๋ง ํ๋ฒ ๋ ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํ์ฌ ์์ ํ๋ฉด ์๋์ ๊ฐ์ต๋๋ค.
protocol Service {
func setNetworkManager(networkManager: Networking)
}
class MainViewController: Service {
var networkManager: Networking?
func setNetworkManager(networkManager: Networking) {
self.networkManager = networkManager
}
}
Service ํ๋กํ ์ฝ์ ๋ฐ๋ฅด๋ ํด๋์ค๋ ๋คํธ์ํน์ ํ์๋กํ๋ ํด๋์ค์ด๊ณ Service์์ ์ ์ํ ํจ์์ธ setNetworkManager๋ฅผ ๊ตฌํํ๊ฒ ๋ฉ๋๋ค. ์ธ๋ถ์์ Service๋ฅผ ๋ฐ๋ฅด๋ MainViewController๋ฅผ ๊ตฌํํ๊ณ ์ด ๊ฐ์ฒด์ networkManager๋ฅผ ์ค์ ํด ์ฃผ๊ธฐ ์ํด ์ธํฐํ์ด์ค์์ ์ ์๋ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ์์กด์ฑ์ ์ค์ ํด ์ค๋๋ค. ์ด๋ networkManager ๋ํ ํ๋กํ ์ฝ์ธ Networking์ผ๋ก ์ค์ ํ์ฌ
ํ์ํ ๊ธฐ๋ฅ๊ณผ ๋ฐ์ดํฐ๋ฅผ ๋ช ์ํ๊ณ ์ธ๋ถ๋ก ๋ถํฐ ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ์ฒด๋ฅผ ์ฃผ์ ๋ฐ๊ฒ ๋ฉ๋๋ค
์ง๊ธ์ ๊ฐ๋จํ์ง๋ง ์ธํฐํ์ด์ค๋ก ์์กด์ฑ์ ์ฃผ์ ํ๊ธฐ ์ํด์ ๋ง์ ํ๋กํ ์ฝ์ด ์์ฑ๋์ด์ผ ํ๊ณ ์ด๋ฅผ ์ํ ์ฝ๋ ์์ฑ๋ ํ์ํฉ๋๋ค. ํ์ง๋ง ์ธํฐํ์ด์ค์ ์ํด ๊ฐ ์์กด๊ด๊ณ๋ฅผ ์ ์ฐํ๊ฒ ๋ง๋ค ์ ์๊ณ ๊ฒฐํฉ๋ ์ค์ผ ์ ์์ผ๋ฉฐ ์ฌ์ฌ์ฉ๊ณผ ํ ์คํธ ์ธก๋ฉด์๋ ์ฉ์ดํฉ๋๋ค.
์ฝ๋๋ฅผ ์์ฑํ๋ค ๋ณด๋ฉด ํ๋์ ๋ฐฉ๋ฒ์ผ๋ก ์์กด์ฑ์ ์ ์ํ๊ธฐ ๋ณด๋ค๋ ๊ฐ ์ํฉ์ ๋ง๋ ์์กด์ฑ ์ฃผ์ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๊ฒ ๋ฉ๋๋ค. ์ด๋ฒ ํฌ์คํ ์์ ์์๋ณธ ์ฌ๋ฌ ๋ฐฉ๋ฒ์ ์ ์ ํ๊ฒ ์ฌ์ฉํด์ ์์กด์ฑ ์ค์ ํด ์ฃผ์๋ฉด ๋ ๊ฑฐ ๊ฐ์ต๋๋ค~
๋ง์ง๋ง์ Interface Injection์ ๋ํด ์์ ๋ณด์๋๋ฐ์ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ด๋ผ๋ฉด ์์ฑํด ์ฃผ์ง ์์์ด๋ ๋ฌ์ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํด์ผ ํ๊ณ ์ด๋ฅผ ์ฃผ์ ํด์ผ ํ๋ ์ฝ๋๋ฅผ ์์ฑํ๋ ๊ฒ์ ๊ท์ฐฎ์ ์ผ์ด ๋ ์๋ ์์ต๋๋ค ๋ฐ๋ผ์!
๐ ๋ค์ ๊ธ์์๋ IoC์ ์ด์ ๊ด๋ จ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์์๋ณด๊ฒ ์ต๋๋ค!
์ฐธ๊ณ ์ฌ์ดํธ ๋ฐ ๋์
๋ฌธ์ ์ ๋๊ธ๋ก ์๋ ค์ฃผ์๋ฉด ๊ฐ์ฌํ๊ฒ ์ต๋๋ค!
'๐ iOS' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[iOS/Swift] UICollectionView paging ๋์ปฅ ๊ฑฐ๋ฆฌ๋ ์ด์ ์์ ํ๊ธฐ (0) | 2022.06.01 |
---|---|
[iOS/Swift] Carousel Effect - UIEdgeInset์ด ์๋ UICollectionView ํ์ด์ง ํ๊ธฐ (0) | 2022.05.31 |
[Swift] ์์กด์ฑ ์ฃผ์ ์ ํ์ํ ๊น? DI ์์๋ณด๊ธฐ (0) | 2022.04.29 |
[Swift] insetBy ์์๋ณด๊ธฐ (0) | 2022.04.23 |
[iOS/Swift] xib๋ฅผ ์ด์ฉํ Custom UIView ๋ง๋ค๊ธฐ (0) | 2022.04.10 |
๋๊ธ