최근 몇 년 동안 애플의 SwiftUI는 아이폰 앱 개발의 패러다임을 변화시켰습니다. SwiftUI는 선언형 프로그래밍 방식으로, UI를 구성하는 방식이 이전의 UIKit의 imperative 방식과는 다릅니다. 이 글에서는 SwiftUI의 활용 방법과 뷰 컨트롤러 기반의 앱 개발 방법을 비교하며, 실제 앱을 만드는 경험을 공유하고자 합니다.
1. SwiftUI란?
SwiftUI는 2019년 WWDC에서 처음 발표된 최신 UI 프레임워크입니다. 이 프레임워크는 다음과 같은 특징을 가지고 있습니다:
- 선언형 프로그래밍: UI를 선언적으로 작성하여 코드가 더 간단하고 직관적입니다.
 - 상태 관리: 데이터와 UI 간의 관계를 쉽게 관리할 수 있도록 도와줍니다.
 - 크로스 플랫폼: iOS, macOS, watchOS, tvOS에서 사용할 수 있습니다.
 
2. UIKit과 SwiftUI의 차이점
기존에는 UIKit 프레임워크를 통해 뷰 컨트롤러 기반으로 앱을 개발했습니다. UIKit은 다음과 같은 방식으로 앱을 구성합니다:
class MyViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        let label = UILabel()
        label.text = "Hello, UIKit!"
        label.frame = CGRect(x: 100, y: 100, width: 200, height: 50)
        view.addSubview(label)
    }
}
반면에 SwiftUI에서는 UI를 구성하는 방식이 매우 다릅니다. SwiftUI는 다음과 같이 간단합니다:
struct ContentView: View {
    var body: some View {
        Text("Hello, SwiftUI!")
            .padding()
    }
}
3. SwiftUI를 사용한 간단한 앱 만들기
이제 SwiftUI를 사용하여 간단한 앱을 만들어보겠습니다. 이 앱은 사용자가 버튼을 클릭할 때마다 카운트가 증가하는 기능을 가집니다.
3.1 프로젝트 설정
Xcode를 실행하고 새로운 SwiftUI 프로젝트를 생성합니다. 이때 ‘App’ 템플릿을 선택합니다.
3.2 메인 뷰 작성
ContentView.swift 파일을 열고 다음 코드를 입력합니다:
import SwiftUI
struct ContentView: View {
    @State private var count = 0
    
    var body: some View {
        VStack {
            Text("Button tapped \(count) times")
                .padding()
            Button(action: {
                count += 1
            }) {
                Text("Tap me!")
            }
        }
    }
}
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
이 코드에서는 상태 변수 `count`를 정의하고, 버튼이 눌릴 때마다 카운트를 증가시키는 기능을 구현했습니다.
4. UIKit을 사용한 앱 만들기
이제 UIKit을 사용하여 비슷한 기능의 앱을 만들어보겠습니다.
4.1 프로젝트 설정
Xcode를 열고 새로운 ‘Single View App’ 프로젝트를 생성합니다.
4.2 메인 뷰 작성
ViewController.swift 파일을 열고 다음과 같은 코드를 입력합니다:
import UIKit
class ViewController: UIViewController {
    private var count = 0
    private let countLabel = UILabel()
    private let tapButton = UIButton(type: .system)
    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
    }
    
    private func setupUI() {
        countLabel.text = "Button tapped \(count) times"
        countLabel.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(countLabel)
        
        tapButton.setTitle("Tap me!", for: .normal)
        tapButton.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
        tapButton.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(tapButton)
        
        // Autolayout constraints
        NSLayoutConstraint.activate([
            countLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            countLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            tapButton.topAnchor.constraint(equalTo: countLabel.bottomAnchor, constant: 20),
            tapButton.centerXAnchor.constraint(equalTo: view.centerXAnchor)
        ])
    }
    @objc private func buttonTapped() {
        count += 1
        countLabel.text = "Button tapped \(count) times"
    }
}
UIKit에서의 개발은 SwiftUI에 비해 좀 더 boilerplate code(단순한 코드)가 필요하지만, 복잡한 UI를 구성할 때에는 더 많은 제어권을 제공합니다.
5. 뷰 컨트롤러와 SwiftUI의 통합
SwiftUI는 기존의 UIKit와 완벽하게 통합될 수 있습니다. 즉, UIKit에서 만든 앱에 SwiftUI 뷰를 추가하고, SwiftUI 앱에서 UIKit 뷰를 사용할 수 있습니다.
import SwiftUI
struct UIKitView: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> ViewController {
        return ViewController()
    }
    
    func updateUIViewController(_ uiViewController: ViewController, context: Context) {}
}
struct ContentView: View {
    var body: some View {
        UIKitView()
    }
}
6. SwiftUI의 장점과 단점
6.1 장점
- 코드가 간결하고 읽기 쉬움
 - UI와 데이터 상태의 관계를 직접 관리 가능
 - 함께 사용할 수 있는 다양한 뷰 컴포넌트 제공
 
6.2 단점
- SwiftUI의 일부 기능은 아직 안정적이지 않음
 - UIKit보다 낮은 성능을 보일 수 있음
 - 구버전 iOS에서의 호환성이 없음
 
7. 결론
SwiftUI는 애플의 최신 UI 프레임워크로, 기존 UIKit보다 훨씬 더 직관적이고 간단한 UI 개발을 가능하게 합니다. 하지만 UIKit도 여전히 견고하고 많은 개발자에게 익숙한 프레임워크이므로, 두 프레임워크를 적절하게 혼합하여 사용하는 것이 중요합니다. 각 프레임워크의 특성을 잘 이해하면, 더 나은 품질의 앱을 개발할 수 있을 것입니다.