제목에서도 봤겠지만 convince init은 왜 사용하는 걸까?
Convenience initializers are written in the same style, but with the convenience modifier placed before the init keyword, separated by a space
아주 간단한 정의지만 처음 봤을때 굳이 사용하나 싶었다.
class introduce {
var age: Int
var name: String
init(name: String, age: Int) {
self.age = age
self.name = name
}
convenience init(age: Int){
self.init(name: "unknown", age: age)
}
func say(){
print("Hello, my name is \(name)\n and i'm \(age)years old")
}
}
이렇게 특정파라미터를 생략하는 방법이면 굳이 위처럼 하는 것보다
class introduce {
var age: Int
var name: String
init(name: String = "unknown", age: Int) {
self.age = age
self.name = name
}
func say(){
print("Hello, my name is \(name)\n and i'm \(age)years old")
}
}
이게 더 간단해 보였다. 그래서 convenience을 만든 이유에 대해 고민을 해봤다.
나이를 세는 방법이 특이한 소수민족이 있다고 해보자, 그 소수민족은 복잡한 계산식을 통해 나이를 측정한다.
class introduce {
var age: Int
var name: String
init(name: String = "unknown", age: Int) {
self.age = age * 12498723895 / 2304798325 - 128347 + 123
self.name = name
}
func say(){
print("Hello, my name is \(name)\n and i'm \(age)years old")
}
}
근데 이 부족에게도 MZ세대는 있는 법이다. 요즘 유행하는 나이 계산법인 소수점 나이 계산을 통해서 계산을 할려고 한다. 식은 갖지만 값이 소수점인 것이다.
그럼 우리는 몇가지 방법을 통해 문제를 해결할 수 있다.
1번은 parameter로 age와 floatAge를 만들어서 그 중에 nil이 아닌 것을 사용하는 방법
하지만 이건 딱 들어도 구리고 쓸모 없는 변수가 늘어난다.
그럼 2번
class Introduce {
var age: Int
var name: String
init(name: String, age: Int) {
self.age = age * 12498723895 / 2304798325 - 128347 + 123
self.name = name
}
init(name: String, age: Float){
self.age = Int(age * 12498723895 / 2304798325 - 128347 + 123)
self.name = name
}
func say(){
print("Hello, my name is \(name)\n and i'm \(age)years old")
}
}
뭐 대충 형변환 해서 사용하는 방법인데 이는 구려보인다. 똑같은 일을 반복하는 코드가 있는 것뿐이라 문제가 생긴다.
만약 나이 계산이 더 복잡해진다면 저렇게 하기도 힘들 것이다.
그래서
class Introduce {
var age: Int
var name: String
init(name: String, age: Int) {
self.age = age * 12498723895 / 2304798325 - 128347 + 123
self.name = name
}
convenience init(age: Float){
self.init(name: "unknown", age: 수식생략(age))
}
func say(){
print("Hello, my name is \(name)\n and i'm \(age)years old")
}
}
똑같은 나이계산을 할더라도 훨씬 간편하고 디버깅도 쉬워질 것이다.
이것이 1번 이유이다. 타입이 다른 변수를 바꾸거나 추가하기 편하다는 장점이 있고, 이렇게 되면 자연스럽게 OCP도 적용할 수 있다.
UIColor의 초기화는 다음과 같다.
public init(white: CGFloat, alpha: CGFloat)
public init(hue: CGFloat, saturation: CGFloat, brightness: CGFloat, alpha: CGFloat)
public init(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat)
자 우리는 int ( 0 <= x <= 255)인 값으로도 초기화 할 수 없다 얼마나 불편해...
하지만 convenience init은 init chain을 활용하고 때문에 원본 즉 UIColor의 내부구조를 건들지 않으면서 init을 변경할 수 있다.
extension UIColor {
convenience init(red: Int, green: Int, blue: Int) {
self.init(red: CGFloat(red) / 255.0, ... )
}
}