SwiftUI vs UIKit. Преимущества и недостатки

В последние годы SwiftUI стал революционным шагом в разработке приложений для платформ Apple. Предложив новый декларативный подход, SwiftUI значительно изменил способ создания пользовательских интерфейсов, сделав этот процесс более интуитивным и простым. В то время как UIKit на протяжении многих лет оставался основным инструментом для разработки интерфейсов на iOS и других платформах Apple, с появлением SwiftUI разработчикам стало доступно больше возможностей для создания современных, кросс-платформенных приложений. Однако вопрос о том, какой фреймворк лучше использовать, до сих пор актуален, так как у обоих подходов есть свои сильные и слабые стороны.

Рассмотрим преимущества SwiftUI по сравнению с UIKit

Декларативный синтаксис:

  • SwiftUI:

    struct ContentView: View {
        @State private var isRed = false
    
        var body: some View {
            VStack {
                Text("Hello, World!")
                    .foregroundColor(isRed ? .red : .blue)
                Button("Toggle Color") {
                    isRed.toggle()
                }
            }
        }
    }
    

    В этом примере вы описываете, как должен выглядеть интерфейс (Text и Button), и как он изменяется при нажатии кнопки — цвет текста изменяется на красный или синий в зависимости от состояния.

  • UIKit:

    class ViewController: UIViewController {
        var isRed = false
        let label = UILabel()
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            label.text = "Hello, World!"
            label.textColor = .blue
            view.addSubview(label)
            
            let button = UIButton(type: .system)
            button.setTitle("Toggle Color", for: .normal)
            button.addTarget(self, action: #selector(toggleColor), for: .touchUpInside)
            view.addSubview(button)
        }
    
        @objc func toggleColor() {
            isRed.toggle()
            label.textColor = isRed ? .red : .blue
        }
    }
    

    Здесь нужно явным образом настроить все компоненты (UILabel и UIButton), а затем вручную обновлять цвет текста при изменении состояния.

Управление состоянием:

  • SwiftUI:

    struct ContentView: View {
        @State private var counter = 0
    
        var body: some View {
            VStack {
                Text("Counter: \(counter)")
                Button("Increase") {
                    counter += 1
                }
            }
        }
    }
    

    @State автоматически отслеживает изменения переменной counter и обновляет интерфейс.

  • UIKit:

    class ViewController: UIViewController {
        var counter = 0
        let label = UILabel()
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            label.text = "Counter: \(counter)"
            view.addSubview(label)
            
            let button = UIButton(type: .system)
            button.setTitle("Increase", for: .normal)
            button.addTarget(self, action: #selector(increaseCounter), for: .touchUpInside)
            view.addSubview(button)
        }
    
        @objc func increaseCounter() {
            counter += 1
            label.text = "Counter: \(counter)"
        }
    }
    

    В UIKit вам нужно вручную обновлять текст метки при изменении переменной counter.

Кросс-платформенность:

  • SwiftUI (может использоваться как на iOS, так и на macOS, watchOS, tvOS):

    struct ContentView: View {
        var body: some View {
            Text("Hello, Cross-platform!")
        }
    }
    

    Этот код можно использовать практически на любой платформе Apple без изменений.

  • UIKit (только для iOS):

    class ViewController: UIViewController {
        override func viewDidLoad() {
            super.viewDidLoad()
    
            let label = UILabel()
            label.text = "Hello, iOS only!"
            view.addSubview(label)
        }
    }
    

    UIKit предназначен только для разработки приложений под iOS.

Живой предпросмотр и "горячая" перезагрузка:

  • SwiftUI: В Xcode можно использовать живой предпросмотр:

    struct ContentView: View {
        var body: some View {
            Text("Hello, Preview!")
        }
    }
    
    struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
            ContentView()
        }
    }
    

    Изменения видны сразу без запуска симулятора.

  • UIKit: Нет функции живого предпросмотра. Чтобы увидеть изменения, нужно запустить приложение через симулятор или на устройстве.

Меньше шаблонного кода:

  • SwiftUI:

    struct ContentView: View {
        var body: some View {
            VStack {
                Text("Hello")
                Text("World")
            }
        }
    }
    

    Просто и лаконично.

  • UIKit:

    class ViewController: UIViewController {
        override func viewDidLoad() {
            super.viewDidLoad()
    
            let label1 = UILabel()
            label1.text = "Hello"
            view.addSubview(label1)
            
            let label2 = UILabel()
            label2.text = "World"
            view.addSubview(label2)
        }
    }
    

    Для выполнения того же необходимо больше кода для создания меток и их добавления в иерархию представлений.

Легкость в изучении:

  • SwiftUI:

    struct ContentView: View {
        var body: some View {
            Text("SwiftUI is easy!")
        }
    }
    

    Простое и понятное описание интерфейса.

  • UIKit:

    class ViewController: UIViewController {
        override func viewDidLoad() {
            super.viewDidLoad()
    
            let label = UILabel()
            label.text = "UIKit requires more setup"
            view.addSubview(label)
        }
    }
    

    Более сложная настройка компонентов.

Интеграция с современными API:

  • SwiftUI:

    import Combine
    
    struct ContentView: View {
        @State private var data = ""
        let dataPublisher = Just("Data from Combine")
    
        var body: some View {
            Text(data)
                .onReceive(dataPublisher) { newValue in
                    data = newValue
                }
        }
    }
    

    Интеграция с Combine для реактивного программирования.

  • UIKit: Чтобы использовать Combine в UIKit, нужно вручную настраивать реактивное программирование:

    import Combine
    class ViewController: UIViewController {
        var label = UILabel()
        var dataPublisher = Just("Data from Combine")
        var cancellable: AnyCancellable?
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            view.addSubview(label)
    
            cancellable = dataPublisher.sink { [weak self] value in
                self?.label.text = value
            }
        }
    }
    

Недостатки SwiftUI по сравнению с UIKit

Зрелость фреймворка:

  • SwiftUI: Некоторые сложные задачи, такие как кастомизация анимаций, могут оказаться сложными в реализации.

  • UIKit: Поддерживает кастомизацию всех аспектов анимаций:
    UIView.animate(withDuration: 0.5) {
        // Полный контроль над анимацией
    }
    

Обратная совместимость:

  • SwiftUI: Работает только на iOS 13 и новее.

  • UIKit: Поддерживает более старые версии iOS.

Производительность сложных интерфейсов:

  • SwiftUI: При работе с большими списками или сложными анимациями производительность может снижаться.

    List(0..<10000) { i in
        Text("Item \(i)")
    }
    
  • UIKit: Оптимизирован для работы с большими данными:
    UITableViewDataSource
    

Документация и сообщество:

  • SwiftUI: Меньше примеров и решений в сообществе.

  • UIKit: Огромное количество документации и примеров.

Настройка и контроль:

  • SwiftUI: Ограниченные возможности настройки сложных элементов интерфейса.

  • UIKit: Полный контроль и кастомизация всех элементов:

Взаимодействие между фреймворками:

  • SwiftUI + UIKit:

    struct UIKitWrapper: UIViewControllerRepresentable {
        func makeUIViewController(context: Context) -> UIViewController {
            return MyViewController()
        }
    
        func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
        }
    }
    

    Здесь нужно интегрировать UIViewController в SwiftUI.

  • UIKit: Нет необходимости в интеграции фреймворков, так как используется только UIKit.

Заключение

SwiftUI и UIKit предоставляют разработчикам мощные инструменты для создания приложений на платформах Apple, и выбор между ними зависит от конкретных задач и требований проекта. SwiftUI, с его декларативным подходом и простотой, идеально подходит для разработки современных приложений, в то время как UIKit остаётся надежным выбором для сложных проектов, требующих полной кастомизации и поддержки старых версий iOS. Владея обоими фреймворками, разработчик становится универсальным специалистом, способным создавать качественные и инновационные продукты.