iOS 개발을 하다 보면 SwiftUI와 UIKit의 초기화(Initialization) 방식이 크게 다르다는 것을 알게 됩니다. 오늘은 이 차이점과 그 이유에 대해 자세히 알아보겠습니다.
SwiftUI에서 View를 만들 때 init을 작성하지 않아도 되는데, UIKit에서는 반드시 작성해야 합니다. 왜 이런 차이가 있을까요?
struct PartAddView: View {
let project: Project
let viewModel: PartListViewModel
@Binding var isPresented: Bool
// ✅ init 자동 생성! 작성할 필요 없음
var body: some View {
Text("Hello, SwiftUI!")
}
}
// 사용할 때
PartAddView(
project: myProject,
viewModel: myViewModel,
isPresented: $showModal
)
class PartAddViewController: UIViewController {
let project: Project
let viewModel: PartListViewModel
// ❌ 반드시 init을 직접 작성해야 함!
init(project: Project, viewModel: PartListViewModel) {
self.project = project
self.viewModel = viewModel
super.init(nibName: nil, bundle: nil)
}
// 스토리보드 지원을 위한 필수 구현
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
구분 | UIKit (Class) | SwiftUI (Struct) |
---|---|---|
타입 | 참조 타입 (Reference Type) | 값 타입 (Value Type) |
상속 | 가능 ✅ | 불가능 ❌ |
초기화 | 복잡 (상속 체인 고려) | 단순 (독립적) |
메모리 | Heap 할당 | Stack 할당 |
Swift는 struct에 한해서 다음 조건을 만족하면 자동으로 initializer를 생성합니다:
// 자동 생성 예시
struct Person {
let name: String
var age: Int
}
// Swift가 자동으로 생성하는 init
// init(name: String, age: Int)
let person = Person(name: "김철수", age: 30) // ✅ 작동!
UIViewController는 복잡한 생명주기와 초기화 과정을 가집니다:
class CustomViewController: UIViewController {
let data: String
init(data: String) {
self.data = data
// 1️⃣ 반드시 super.init 호출 필요
super.init(nibName: nil, bundle: nil)
// 2️⃣ super.init 이후에 추가 설정 가능
setupUI()
}
// 3️⃣ 스토리보드/XIB 지원을 위한 필수 구현
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// 4️⃣ 생명주기 메서드들
override func viewDidLoad() {
super.viewDidLoad()
}
}
// View 정의
struct ProfileView: View {
let user: User
let isEditable: Bool
@Binding var isPresented: Bool
var body: some View {
// UI 구현
}
}
// 사용 - 매우 간단!
ProfileView(
user: currentUser,
isEditable: true,
isPresented: $showProfile
)
// ViewController 정의
class ProfileViewController: UIViewController {
let user: User
let isEditable: Bool
weak var delegate: ProfileDelegate?
init(user: User, isEditable: Bool) {
self.user = user
self.isEditable = isEditable
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
// 사용 - 더 많은 코드 필요
let profileVC = ProfileViewController(
user: currentUser,
isEditable: true
)
profileVC.delegate = self
navigationController?.pushViewController(profileVC, animated: true)
protocol StoryboardInstantiable {
static var storyboardName: String { get }
}
extension StoryboardInstantiable where Self: UIViewController {
static func instantiate() -> Self {
let storyboard = UIStoryboard(name: storyboardName, bundle: nil)
return storyboard.instantiateViewController(withIdentifier: String(describing: self)) as! Self
}
}
extension UIViewController {
static func create<T: UIViewController>(
configure: (T) -> Void = { _ in }
) -> T {
let viewController = T()
configure(viewController)
return viewController
}
}
// 사용
let vc = ProfileViewController.create { vc in
vc.user = currentUser
vc.isEditable = true
}
특징 | SwiftUI | UIKit |
---|---|---|
초기화 코드 | 자동 생성 | 수동 작성 |
코드량 | 적음 | 많음 |
유연성 | 제한적 | 높음 |
학습 곡선 | 낮음 | 높음 |
커스터마이징 | 제한적 | 자유로움 |
레거시 지원 | iOS 13+ | iOS 2.0+ |
SwiftUI의 자동 memberwise initializer는 개발자의 생산성을 크게 향상시킵니다. 하지만 이것은 struct의 단순함 덕분에 가능한 것이며, UIKit의 class 기반 아키텍처에서는 더 복잡한 초기화 과정이 필요합니다.
각 프레임워크는 서로 다른 철학과 목적을 가지고 설계되었습니다:
프로젝트의 요구사항과 타겟 iOS 버전에 따라 적절한 프레임워크를 선택하는 것이 중요합니다.
이 글이 도움이 되셨다면 좋아요와 공유 부탁드립니다! 질문이나 의견은 댓글로 남겨주세요.