convenience init()은 swift에서만 사용되는 독특한 초기화방법이다. 기본적으로 초기화 메서드는 모든 저장 프로퍼티를 직접 초기화해야한다.
class Student {
let name: String
let age: Int
let grade: Int
// 기본 초기화 메서드 (Designated Initializer)
init(name: String, age: Int, grade: Int) {
self.name = name
self.age = age
self.grade = grade
}
// 편의 초기화 메서드 (Convenience Initializer)
convenience init(name: String, grade: Int) {
// 나이를 계산해서 기본 초기화 메서드 호출
let estimatedAge = grade + 6
self.init(name: name, age: estimatedAge, grade: grade)
}
}
모든 프로퍼티가 옵셔널타입이 아니므로 모든 프로퍼티에 값을 할당해줘야함. 그러나 convenience init을 사용하면 전체 프로퍼티의 일부분만 초기화하여 인스턴스를 생성할 수 있다.
// MARK: - 헥사코드 사용예시 UIColor(hex: "#000000")
extension UIColor {
convenience init(hex: String) {
var hexSanitized = hex.trimmingCharacters(in: .whitespacesAndNewlines)
hexSanitized = hexSanitized.replacingOccurrences(of: "#", with: "")
var rgb: UInt64 = 0
Scanner(string: hexSanitized).scanHexInt64(&rgb)
let r = CGFloat((rgb & 0xFF0000) >> 16) / 255.0
let g = CGFloat((rgb & 0x00FF00) >> 8) / 255.0
let b = CGFloat(rgb & 0x0000FF) / 255.0
let a = CGFloat(1.0)
self.init(red: r, green: g, blue: b, alpha: a)
}
}
설명 :
앞뒤 공백이랑 줄바꿈 날림 (trimmingCharacters)
"#" 기호도 제거 (replacingOccurrences)
16진수 → 정수로 변환:
Scanner 클래스로 UInt64로 바꿈
RGB 추출:
비트 연산으로 R, G, B 각각 뽑아냄
비트 시프트(>>)랑 AND(&) 연산 씀
255로 나눠서 0~1 사이 값으로 (CGFloat)
UIColor 만들기:
추출한 RGB 값이랑 알파값(1.0) 넣어서 UIColor 초기화
extension URL {
convenience init?(baseURL: String, path: String) {
guard let base = URL(string: baseURL) else { return nil }
self.init(string: path, relativeTo: base)
}
}
// 사용 예:
let url = URL(baseURL: "https://api.example.com", path: "/users")
baseURL 체크:
문자열로 받은 baseURL을 URL 객체로 변환
실패하면 바로 nil 리턴 (guard let 사용)
URL 생성:
path를 baseURL에 상대 경로로 붙여서 새 URL 만듦
특징:
convenience init 패턴 → 쓰기 편함
옵셔널 이니셜라이저 (init?) → 실패 가능성 있음
guard let으로 early exit → 안전성 높임
장점:
베이스 URL이랑 경로 따로 관리할 때 편함
API 호출 같은 거 할 때 코드 깔끔해짐
사용 예:
let url = URL(baseURL: "https://api.example.com", path: "/users")
주의할 점:
baseURL이 유효한 URL 형식 아니면 nil 반환함
path가 이상해도 URL 객체는 만들어질 수 있음 (상대 경로라)
응용한다면?
쿼리 파라미터도 쉽게 추가할 수 있게 하면 더 좋을 듯
path 유효성 검사 추가하면 더 안전할 것 같음
extension UIImage {
convenience init?(named name: String, size: CGSize) {
guard let original = UIImage(named: name) else { return nil }
let renderer = UIGraphicsImageRenderer(size: size)
let resized = renderer.image { _ in
original.draw(in: CGRect(origin: .zero, size: size))
}
guard let cgImage = resized.cgImage else { return nil }
self.init(cgImage: cgImage, scale: UIScreen.main.scale, orientation: .up)
}
}
// 사용 예:
let resizedImage = UIImage(named: "profile", size: CGSize(width: 100, height: 100))
extension NSManagedObject {
convenience init(context: NSManagedObjectContext) {
let name = String(describing: type(of: self))
let entity = NSEntityDescription.entity(forEntityName: name, in: context)!
self.init(entity: entity, insertInto: context)
}
}
// 사용 예:
let context = persistentContainer.viewContext
let user = User(context: context)