4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[Swift] UIKitベースのプロダクトでUIをSwiftUIで開発する

Posted at

課題

  • SwiftUIが登場して、2年ぐらい経過している。2年経つが既存のプロダクトでSwiftUIで開発をするといくつかの制約に出会す。特に機能不足、不具合、サポートバージョンなどの問題もあり、UIKitベースで進めることが多い。
    しかし、長期的な視点で見るとSwiftUIが開発の中心になっていくことが予想される。今回は既存のプロダクトでUIKitとSwiftUIの共存、少しずつ置き換えるための戦略について考えてみました。

SwiftUIで実装するメリット

  • 日頃の開発でInterface Builderを使っている場合は、コードだけでUIを実装できる
  • 宣言的に実装できるのでメンテしやすく、コードの可読性が上がる
  • プレビュー機能が使える(UIKitのクラスをWrapすれば同様の機能は使える)

実装方法

  • UIHostingControllerを使う
  • SwiftUIのViewをUIHostingControllerに渡して、Child ViewControllerとして、登録することで表示することができる
import UIKit
import SwiftUI

final class SampleListDisplayController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        title = "SampleListView(SwiftUI)"
        let hostingController = UIHostingController(rootView: SampleListView())
        addChild(hostingController)
        view.addSubview(hostingController.view)
        hostingController.didMove(toParent: self)
        hostingController.view.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            hostingController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            hostingController.view.rightAnchor.constraint(equalTo: view.rightAnchor),
            hostingController.view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            hostingController.view.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
        ])
    }
}

実装 + α

  • Mewを使う
    • Mewを使います
    • Mewを使うことでchild ViewControllerの管理が楽になり、StackViewと合わせて使うとさらにレイアウトが簡単になります。
    • MicroViewControllerとすることで画面の一部のパーツに切り分けることができ、部分的に置き換えることが容易になります
    • UIHostingControllerを継承して、SwiftUIのViewをrootViewに渡すことでSwiftUIのViewを表示できます。そして、MicroViewControllerとして画面に追加することで表示できます。
import Foundation
import UIKit
import SwiftUI
import Mew

final class BodyViewController: UIHostingController<BodyView>, Instantiatable, Injectable {
    func input(_ input: Input) {}
    typealias Input = Void
    typealias Environment = Void
    private var swiftUIView: BodyView
    var environment: Void
    init(with input: Input, environment: Environment) {
        self.swiftUIView = BodyView()
        super.init(rootView: swiftUIView)
        view.backgroundColor = .clear
    }
    
    @available(*, unavailable)
    @objc required dynamic init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

まとめ

  • 今後はSwiftUIのアップデートによって、使いやすくなり、主流になっていくことが予想される。
  • Mewのライブラリを使うことで少しずつの置き換えが簡単になります。
  • 現状はSwiftUIだけでは実装したい機能を実現するのは大変である。UIKitと組み合わせ、1つの画面の一部を置き換えていくことが現実的なやり方である

環境

Xcode 12.5
Build version 12E262
Apple Swift version 5.4 (swiftlang-1205.0.26.9 clang-1205.0.19.55)
Target: x86_64-apple-darwin20.3.0
4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?