You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中如何在不同View间共享并使用数组数据

解决SwiftUI中两个View共享数组数据的问题

你之前的做法无效的核心原因:在NewsView中创建SavedNewsView的新实例,修改的只是这个新实例的savedArticles数组,和界面上正在显示的SavedNewsView实例完全无关,自然无法同步数据。

下面是正确的实现方案,通过共享ViewModel实现两个View的数据同步:


1. 创建共享数据源ViewModel

这个ViewModel负责管理savedArticles数组,所有对数组的操作都在这里统一处理:

兼容iOS13+的写法(使用ObservableObject)

import SwiftUI
import Combine

class SavedArticlesViewModel: ObservableObject {
    // @Published会自动通知View数据更新
    @Published var savedArticles: [Article] = []
    
    // 添加文章的方法
    func addArticle(_ article: Article) {
        savedArticles.append(article)
    }
    
    // 删除文章的方法
    func removeArticle(at offsets: IndexSet) {
        savedArticles.remove(atOffsets: offsets)
    }
}

iOS17+简化写法(使用@Observable)

import SwiftUI

@Observable
class SavedArticlesViewModel {
    var savedArticles: [Article] = []
    
    func addArticle(_ article: Article) {
        savedArticles.append(article)
    }
    
    func removeArticle(at offsets: IndexSet) {
        savedArticles.remove(atOffsets: offsets)
    }
}

2. 修改SavedNewsView,依赖共享ViewModel

把原来的@State数组替换为对ViewModel的引用:

iOS13-16版本

struct SavedNewsView: View {
    @ObservedObject var viewModel: SavedArticlesViewModel
    
    var body: some View {
        NavigationView {
            List {
                ForEach(viewModel.savedArticles, id: \.self) { article in
                    NewsComponentView(title: article.title, description: article.description, urlToImage: article.urlToImage, url: article.url)
                }
                .onDelete(perform: viewModel.removeArticle)
            }
            .listStyle(.plain)
        }
        .navigationTitle("Saved News")
    }
}

iOS17+版本

struct SavedNewsView: View {
    let viewModel: SavedArticlesViewModel
    
    var body: some View {
        NavigationStack { // iOS16+推荐用NavigationStack替代NavigationView
            List {
                ForEach(viewModel.savedArticles, id: \.self) { article in
                    NewsComponentView(title: article.title, description: article.description, urlToImage: article.urlToImage, url: article.url)
                }
                .onDelete(perform: viewModel.removeArticle)
            }
            .listStyle(.plain)
        }
        .navigationTitle("Saved News")
    }
}

3. 修改NewsView,引用同一个ViewModel

移除原来的savedArray实例,改用共享的ViewModel来添加文章:

iOS13-16版本

struct NewsView: View {
    @StateObject var newsViewModel = ViewModel()
    @ObservedObject var savedViewModel: SavedArticlesViewModel
    
    var body: some View {
        List {
            ForEach(newsViewModel.news, id: \.self) { article in
                if article.urlToImage != nil {
                    NewsComponentView(title: article.title, description: article.description, urlToImage: article.urlToImage, url: article.url)
                        .swipeActions() {
                            Button {
                                // 调用ViewModel的方法添加文章
                                savedViewModel.addArticle(article)
                            } label: {
                                Label("Save", systemImage: "bookmark")
                            }
                            .tint(.yellow)
                        }
                }
            }
        }
        .listStyle(.plain)
        .onAppear {
            newsViewModel.fetch()
        }
    }
}

iOS17+版本

struct NewsView: View {
    @StateObject var newsViewModel = ViewModel()
    let savedViewModel: SavedArticlesViewModel
    
    var body: some View {
        List {
            ForEach(newsViewModel.news, id: \.self) { article in
                if article.urlToImage != nil {
                    NewsComponentView(title: article.title, description: article.description, urlToImage: article.urlToImage, url: article.url)
                        .swipeActions() {
                            Button {
                                savedViewModel.addArticle(article)
                            } label: {
                                Label("Save", systemImage: "bookmark")
                            }
                            .tint(.yellow)
                        }
                }
            }
        }
        .listStyle(.plain)
        .onAppear {
            newsViewModel.fetch()
        }
    }
}

4. 在父View中初始化共享ViewModel并传递给子View

比如在TabView或其他父容器中,创建一次ViewModel实例,再传递给两个子View:

struct MainView: View {
    // iOS13-16用@StateObject,iOS17+用@State
    @StateObject var savedViewModel = SavedArticlesViewModel()
    // @State var savedViewModel = SavedArticlesViewModel() // iOS17+
    
    var body: some View {
        TabView {
            NewsView(savedViewModel: savedViewModel)
                .tabItem {
                    Label("News", systemImage: "newspaper")
                }
            
            SavedNewsView(viewModel: savedViewModel)
                .tabItem {
                    Label("Saved", systemImage: "bookmark")
                }
        }
    }
}

原理说明

共享ViewModel持有唯一的数组数据源,通过@Published(或@Observable的自动追踪)实现数据变更通知,两个View都引用同一个ViewModel实例,所以任何对数组的修改都会同步触发两个View的刷新,实现数据一致。

内容的提问来源于stack exchange,提问作者zrgn4k

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 16:00:52