SwiftUI에서 UIKit 통합하기: 사용 사례와 구현 방법

SwiftUI는 iOS 개발자들에게 선언적 UI 작성 방식을 제공하며, 코드의 간결함과 재사용성을 극대화합니다. 그러나 UIKit은 여전히 강력한 기능과 제어력을 제공합니다. 많은 프로젝트에서 SwiftUI와 UIKit의 조화로운 통합이 필요합니다. 이 글에서는 SwiftUI에서 UIKit을 사용하는 방법을 중심으로, 대표적인 사용 사례와 구현 방법을 설명하겠습니다.

SwiftUI와 UIKit을 통합해야 하는 이유

SwiftUI는 강력하지만, 여전히 UIKit에 의존해야 하는 경우가 있습니다. 다음은 UIKit을 통합해야 하는 주요 이유입니다:

  1. 기존 UIKit 기반 코드 재사용
    • 오래된 프로젝트에서 일부 UI를 SwiftUI로 전환하고 싶을 때.
    • UIKit으로 이미 구현된 커스텀 UI 컴포넌트 활용.
  2. SwiftUI에서 구현이 어려운 고급 기능
    • 예: UIScrollView의 세부 설정, UIImagePickerControllerMKMapView와 같은 고급 UIKit 뷰.
    • SwiftUI는 일부 UIKit의 복잡한 기능을 완전히 지원하지 않음.
  3. 프로젝트 초기 단계에서 점진적인 전환
    • SwiftUI로 전체 프로젝트를 전환하기 전, 일부 화면만 SwiftUI로 작성.

1. SwiftUI에서 UIKit 뷰 사용하기

SwiftUI는 UIViewRepresentable과 UIViewControllerRepresentable 프로토콜을 통해 UIKit 뷰와 뷰 컨트롤러를 통합할 수 있습니다. 이 두 프로토콜은 UIKit 뷰를 SwiftUI의 선언적 UI 구조에 적합하게 변환합니다.

1.1 UIViewRepresentable 사용하기

UIViewRepresentable은 UIKit의 UIView를 SwiftUI에서 사용하도록 도와줍니다.
다음은 UILabel을 SwiftUI에서 사용하는 간단한 예입니다.

import SwiftUI

struct UILabelRepresentable: UIViewRepresentable {
    var text: String

    func makeUIView(context: Context) -> UILabel {
        let label = UILabel()
        label.textAlignment = .center
        label.font = UIFont.boldSystemFont(ofSize: 24)
        return label
    }

    func updateUIView(_ uiView: UILabel, context: Context) {
        uiView.text = text
    }
}

struct ContentView: View {
    var body: some View {
        UILabelRepresentable(text: "Hello, UIKit in SwiftUI!")
            .frame(height: 50)
            .padding()
    }
}

위 코드는 UIKit의 UILabel을 SwiftUI에서 사용 가능하게 만들어줍니다. makeUIView에서 UILabel을 생성하고, updateUIView에서 상태 변화를 반영합니다.


1.2 UIViewControllerRepresentable 사용하기

UIViewControllerRepresentable은 UIKit의 UIViewController를 SwiftUI에서 사용할 때 유용합니다.
다음은 UIImagePickerController를 SwiftUI에서 사용하는 예입니다.

import SwiftUI
import UIKit

struct ImagePicker: UIViewControllerRepresentable {
    @Binding var selectedImage: UIImage?
    @Environment(\.presentationMode) var presentationMode

    class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
        let parent: ImagePicker

        init(parent: ImagePicker) {
            self.parent = parent
        }

        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            if let image = info[.originalImage] as? UIImage {
                parent.selectedImage = image
            }
            parent.presentationMode.wrappedValue.dismiss()
        }
    }

    func makeCoordinator() -> Coordinator {
        return Coordinator(parent: self)
    }

    func makeUIViewController(context: Context) -> UIImagePickerController {
        let picker = UIImagePickerController()
        picker.delegate = context.coordinator
        return picker
    }

    func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {}
}

위 코드는 사용자가 이미지를 선택할 수 있도록 UIImagePickerController를 SwiftUI에서 사용하는 방법을 보여줍니다.


2. UIKit에서 SwiftUI 사용하기

UIKit 기반 프로젝트에서도 SwiftUI 뷰를 사용할 수 있습니다. UIHostingController를 사용하면 SwiftUI 뷰를 UIKit 뷰 컨트롤러에 통합할 수 있습니다.

예제: SwiftUI 뷰를 UIViewController에서 사용하기

import SwiftUI
import UIKit

struct SwiftUIView: View {
    var body: some View {
        Text("This is a SwiftUI View in UIKit!")
            .font(.largeTitle)
            .padding()
    }
}

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        let hostingController = UIHostingController(rootView: SwiftUIView())
        addChild(hostingController)
        view.addSubview(hostingController.view)

        hostingController.view.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            hostingController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            hostingController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            hostingController.view.topAnchor.constraint(equalTo: view.topAnchor),
            hostingController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
        hostingController.didMove(toParent: self)
    }
}

이 코드는 UIKit의 UIViewController에 SwiftUI 뷰를 추가하는 방법을 보여줍니다.


3. UIKit과 SwiftUI 통합 시 주의사항

UIKit과 SwiftUI를 통합할 때 다음 사항을 유념해야 합니다:

  1. 상태 관리
    • SwiftUI의 상태(@State@Binding)를 UIKit에 전달할 때 적절한 동기화가 필요합니다.
    • 데이터 흐름이 복잡한 경우, Combine 또는 NotificationCenter를 사용할 수 있습니다.
  2. 성능 최적화
    • UIKit 뷰를 SwiftUI에서 지나치게 많이 사용할 경우, 성능 문제가 발생할 수 있습니다.
    • 통합은 필요한 경우에만 사용해야 합니다.
  3. 라이프사이클 차이
    • UIKit의 뷰 라이프사이클과 SwiftUI의 선언적 상태 업데이트 방식은 차이가 있습니다. 이를 고려해 설계해야 합니다.

결론

SwiftUI와 UIKit의 통합은 iOS 앱 개발의 유연성과 생산성을 크게 향상시킵니다.

  • UIViewRepresentable과 UIViewControllerRepresentable을 사용해 UIKit 컴포넌트를 SwiftUI에서 활용할 수 있습니다.
  • UIHostingController를 사용해 SwiftUI를 UIKit 기반 프로젝트에 통합할 수 있습니다.

SwiftUI가 빠르게 발전하고 있지만, UIKit의 강력한 기능은 여전히 중요한 자산입니다. 두 기술을 조화롭게 활용해 더욱 강력한 앱을 개발해 보세요!

Leave a Comment