SwiftUI和UIKit区别

SwiftUI 和 UIKit 是苹果提供的两个 UI 框架,它们在设计理念、开发方式和能力上有显著区别:

  1. 设计理念

SwiftUI - 声明式

swift 复制代码
struct ContentView: View {
    @State private var isOn = false
    
    var body: some View {
        VStack {
            Toggle("开关", isOn: $isOn)
            if isOn {
                Text("开关已打开")
                    .foregroundColor(.green)
            }
        }
        .padding()
    }
}

UIKit - 命令式

swift 复制代码
class ViewController: UIViewController {
    private let toggle = UISwitch()
    private let label = UILabel()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
        toggle.addTarget(self, action: #selector(toggleChanged), for: .valueChanged)
    }
    
    @objc func toggleChanged() {
        label.isHidden = !toggle.isOn
        label.text = "开关已打开"
        label.textColor = .green
    }
    
    private func setupUI() {
        // 手动创建和配置所有视图
    }
}
  1. 数据绑定和状态管理

SwiftUI - 自动响应

swift 复制代码
struct UserProfile: View {
    @State private var username = ""
    @StateObject private var viewModel = ProfileViewModel()
    
    var body: some View {
        VStack {
            TextField("用户名", text: $username)
            Text("你好, \(username)")
                .opacity(username.isEmpty ? 0 : 1)
            
            Button("保存") {
                viewModel.saveUser(name: username)
            }
        }
    }
}

UIKit - 手动更新

swift 复制代码
class UserProfileViewController: UIViewController {
    @IBOutlet weak var usernameField: UITextField!
    @IBOutlet weak var greetingLabel: UILabel!
    @IBOutlet weak var saveButton: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        usernameField.addTarget(self, action: #selector(textFieldChanged), for: .editingChanged)
    }
    
    @objc func textFieldChanged() {
        let username = usernameField.text ?? ""
        greetingLabel.text = "你好, \(username)"
        greetingLabel.isHidden = username.isEmpty
        saveButton.isEnabled = !username.isEmpty
    }
}
  1. 布局系统

SwiftUI - 修饰符布局

swift 复制代码
VStack(spacing: 20) {
    Text("标题")
        .font(.title)
        .padding()
    
    HStack {
        Image(systemName: "star")
        Text("评分: 4.8")
    }
    
    Spacer()
    
    Button("确认") { }
        .frame(maxWidth: .infinity)
        .padding()
}
.background(Color.gray.opacity(0.1))

UIKit - 自动布局约束

swift 复制代码
private func setupConstraints() {
    NSLayoutConstraint.activate([
        titleLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20),
        titleLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
        
        stackView.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 20),
        stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
        stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
        
        confirmButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20),
        confirmButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
        confirmButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
        confirmButton.heightAnchor.constraint(equalToConstant: 50)
    ])
}
  1. 视图生命周期

SwiftUI - 基于视图结构

swift 复制代码
struct LifecycleView: View {
    var body: some View {
        Text("示例")
    }
    
    // 生命周期事件
    .onAppear {
        print("视图出现")
    }
    .onDisappear {
        print("视图消失")
    }
    .task {
        // 异步任务,自动取消
        await loadData()
    }
}

UIKit - 基于视图控制器

swift 复制代码
class LifecycleViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // 视图加载完成
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        // 视图将要出现
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        // 视图已经出现
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        // 视图将要消失
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        // 视图已经消失
    }
}
  1. 列表和集合视图

SwiftUI - List 和 ForEach

swift 复制代码
struct UserListView: View {
    let users: [User]
    
    var body: some View {
        List(users) { user in
            HStack {
                AsyncImage(url: user.avatarURL) { image in
                    image.resizable()
                } placeholder: {
                    ProgressView()
                }
                .frame(width: 50, height: 50)
                .clipShape(Circle())
                
                VStack(alignment: .leading) {
                    Text(user.name)
                        .font(.headline)
                    Text(user.email)
                        .font(.subheadline)
                        .foregroundColor(.gray)
                }
            }
            .swipeActions {
                Button("删除", role: .destructive) {
                    deleteUser(user)
                }
            }
        }
        .refreshable {
            await refreshUsers()
        }
    }
}

UIKit - UITableView

swift 复制代码
class UserListViewController: UITableViewController {
    var users: [User] = []
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return users.count
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "UserCell", for: indexPath) as! UserCell
        let user = users[indexPath.row]
        cell.configure(with: user)
        return cell
    }
    
    override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
        if editingStyle == .delete {
            deleteUser(at: indexPath)
        }
    }
}
  1. 动画和过渡

SwiftUI - 隐式动画

swift 复制代码
struct AnimatedView: View {
    @State private var isExpanded = false
    
    var body: some View {
        VStack {
            Button("切换") {
                withAnimation(.spring()) {
                    isExpanded.toggle()
                }
            }
            
            Rectangle()
                .fill(Color.blue)
                .frame(
                    width: isExpanded ? 200 : 100,
                    height: isExpanded ? 200 : 100
                )
                .rotationEffect(.degrees(isExpanded ? 180 : 0))
        }
    }
}

UIKit - 显式动画

swift 复制代码
class AnimatedViewController: UIViewController {
    @IBOutlet weak var boxView: UIView!
    var isExpanded = false
    
    @IBAction func toggleTapped(_ sender: UIButton) {
        UIView.animate(withDuration: 0.5, 
                      delay: 0,
                      usingSpringWithDamping: 0.6,
                      initialSpringVelocity: 0,
                      options: []) {
            if self.isExpanded {
                self.boxView.transform = CGAffineTransform.identity
            } else {
                self.boxView.transform = CGAffineTransform(rotationAngle: .pi)
                    .scaledBy(x: 2, y: 2)
            }
        } completion: { _ in
            self.isExpanded.toggle()
        }
    }
}
  1. 导航和路由

SwiftUI - NavigationStack

swift 复制代码
struct MainApp: View {
    var body: some View {
        NavigationStack {
            List {
                NavigationLink("用户详情", value: "user_detail")
                NavigationLink("设置", value: "settings")
            }
            .navigationDestination(for: String.self) { route in
                switch route {
                case "user_detail":
                    UserDetailView()
                case "settings":
                    SettingsView()
                default:
                    Text("未知页面")
                }
            }
        }
    }
}

UIKit - UINavigationController

swift 复制代码
class MainViewController: UITableViewController {
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        switch indexPath.row {
        case 0:
            let userDetailVC = UserDetailViewController()
            navigationController?.pushViewController(userDetailVC, animated: true)
        case 1:
            let settingsVC = SettingsViewController()
            navigationController?.pushViewController(settingsVC, animated: true)
        default:
            break
        }
    }
}
  1. 主要区别总结

特性 SwiftUI UIKit 编程范式 声明式 命令式 数据流 响应式数据绑定 手动更新 布局 基于栈的布局系统 Auto Layout 约束 状态管理 @State, @Binding, @ObservedObject 手动管理状态 预览 实时预览 Interface Builder 跨平台 iOS, macOS, watchOS, tvOS 主要 iOS/tvOS 学习曲线 相对平缓 相对陡峭 代码量 通常更少 通常更多 版本要求 iOS 13+ iOS 2+ 性能 优化良好,持续改进 成熟稳定

  1. 混合使用

在实际项目中,可以混合使用两者:

swift 复制代码
// 在 SwiftUI 中使用 UIKit 组件
struct MapView: UIViewRepresentable {
    func makeUIView(context: Context) -> MKMapView {
        MKMapView()
    }
    
    func updateUIView(_ uiView: MKMapView, context: Context) {
        // 更新地图
    }
}

// 在 UIKit 中使用 SwiftUI
class HostingViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let swiftUIView = ContentView()
        let hostingController = UIHostingController(rootView: swiftUIView)
        
        addChild(hostingController)
        view.addSubview(hostingController.view)
        hostingController.didMove(toParent: self)
    }
}
相关推荐
非专业程序员2 小时前
iOS 实现微信读书的仿真翻页
ios·swiftui·swift
非专业程序员Ping4 小时前
iOS 实现微信读书的仿真翻页
ios·swiftui·swift
AirDroid_cn11 小时前
iPhone 的5G 信号弱时,如何强制切换为4G?
5g·ios·iphone
用户1972959188911 天前
WKWebView的重定向(objective_c)
前端·ios
lancoff1 天前
#3 Creating Shapes in SwiftUI
ios·swiftui
lancoff1 天前
#1 How to use Xcode in SwiftUI project
ios·swiftui
lancoff1 天前
#2 Adding Text in SwiftUI
ios·swiftui
良逍Ai出海1 天前
Build in Public|为什么我开始做一款相册清理 App(听说有竞品年收益40W)
ios·uni-app·ai编程·coding
笑尘pyrotechnic2 天前
LLDB进阶:使用命令行进行检查
ios·objective-c·cocoa·lldb