MVVM vs The Composable Architecture (TCA)
iOSで最も人気のある2つのアーキテクチャパターンの対決:伝統的なMVVMとPoint-Freeの関数型TCA。正しいアーキテクチャをどう選ぶか?
Appleの未来像:宣言的、リアクティブ、クロスプラットフォーム
15年にわたり実戦で鍛えられた、強力で成熟したフレームワーク
| カテゴリー | SwiftUI | UIKit |
|---|---|---|
| パフォーマンス | 8/10 | 10/10 |
| 学習のしやすさ | 8/10 | 5/10 |
| エコシステム | 8/10 | 9/10 |
| コミュニティ | 8/10 | 9/10 |
| 求人市場 | 8/10 | 9/10 |
| 将来性 | 10/10 | 6/10 |
// SwiftUI - ユーザープロフィールカード
import SwiftUI
struct ProfileCard: View {
@StateObject private var viewModel = ProfileViewModel()
@State private var isFollowing = false
var body: some View {
VStack(alignment: .leading, spacing: 16) {
HStack {
AsyncImage(url: viewModel.user.avatarURL) { image in
image.resizable().scaledToFill()
} placeholder: {
ProgressView()
}
.frame(width: 64, height: 64)
.clipShape(Circle())
VStack(alignment: .leading) {
Text(viewModel.user.name)
.font(.headline)
Text(viewModel.user.title)
.font(.subheadline)
.foregroundStyle(.secondary)
}
Spacer()
Button(isFollowing ? "Takipten Çık" : "Takip Et") {
withAnimation(.spring(response: 0.3)) {
isFollowing.toggle()
}
}
.buttonStyle(.bordered)
.tint(isFollowing ? .gray : .blue)
}
}
.padding()
.background(.regularMaterial)
.clipShape(RoundedRectangle(cornerRadius: 16))
}
}// UIKit - ユーザープロフィールカード
import UIKit
class ProfileCardViewController: UIViewController {
private let avatarImageView: UIImageView = {
let iv = UIImageView()
iv.contentMode = .scaleAspectFill
iv.clipsToBounds = true
iv.layer.cornerRadius = 32
iv.translatesAutoresizingMaskIntoConstraints = false
return iv
}()
private let nameLabel: UILabel = {
let label = UILabel()
label.font = .preferredFont(forTextStyle: .headline)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
private lazy var followButton: UIButton = {
var config = UIButton.Configuration.bordered()
config.title = "Takip Et"
let btn = UIButton(configuration: config)
btn.addTarget(self, action: #selector(followTapped), for: .touchUpInside)
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
loadUserData()
}
private func setupUI() {
view.addSubview(avatarImageView)
view.addSubview(nameLabel)
view.addSubview(followButton)
NSLayoutConstraint.activate([
avatarImageView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
avatarImageView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
avatarImageView.widthAnchor.constraint(equalToConstant: 64),
avatarImageView.heightAnchor.constraint(equalToConstant: 64)
])
}
@objc private func followTapped() {
UIView.animate(withDuration: 0.3) {
self.followButton.alpha = 0.5
} completion: { _ in
UIView.animate(withDuration: 0.3) { self.followButton.alpha = 1 }
}
}
}2025年以降の新規プロジェクトではSwiftUIを選ぶべきです。Appleのすべての投資はこの方向に向かっています。ただし、複雑なカスタム要件、iOS 13未満のサポート、大規模なレガシーコードベースがある場合は、依然としてUIKitが必須となります。理想的なアプローチは、まずSwiftUIを試し、必要に応じてUIViewRepresentableでUIKitコンポーネントを組み込むことです。
無料相談を受けるはい。UIHostingControllerを使ってSwiftUIビューをUIKit内に、UIViewRepresentableを使ってUIKitビューをSwiftUI内に組み込むことができます。大規模プロジェクトではハイブリッドアプローチが一般的です。