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

SwiftUI中通过@Binding实现结构体间数组的引用传递与修改

SwiftUI中通过@Binding传递并修改数组的问题

我有一个DropletsView结构体,内部定义了状态数组:

@State private var savedQuotes: [Quote] = []

Quote是自定义类型。现在需要将这个数组传给SingleQuoteView,让后者能够修改它。之前尝试用类似C++的引用传递方式行不通,转而尝试@Binding实现,但遇到了初始化错误。

当前代码情况

原SingleQuoteView的调用与初始化

之前的调用方式:

SingleQuoteView(quote: quote)

对应的初始化函数:

init(quote: Quote) {
    self.quote = quote
    self._isBookmarked = State(initialValue: isQuoteBookmarked(quote))
    self._isLiked = State(initialValue: isQuoteLiked(quote))
}

添加@Binding后的尝试代码

给SingleQuoteView新增@Binding变量并修改初始化逻辑:

@Binding private var savedQuotes: [Quote]
    
init(quote: Quote, savedQuotesArg: Binding<[Quote]>) {
    self.quote = quote
    self._isBookmarked = State(initialValue: isQuoteBookmarked(quote))
    self._isLiked = State(initialValue: isQuoteLiked(quote))
    self._savedQuotes = savedQuotesArg
}

调用时更新为:

SingleQuoteView(quote: quote, savedQuotesArg: $savedQuotes)

此时编译器报错:Variable 'self.savedQuotes' used before being initialized。

目标需求

希望在SingleQuoteView的toggleBookmark函数中修改DropletsView里的savedQuotes状态变量:

private func toggleBookmark() {
    isBookmarked.toggle()
    
    var bookmarkedQuotes = getBookmarkedQuotes()
    if isBookmarked {
        bookmarkedQuotes.append(quote)
    } else {
        bookmarkedQuotes.removeAll { $0.id == quote.id }
        
        // 需要添加的代码:修改父视图的savedQuotes
        savedQuotes.removeAll { $0.id == quote.id }
    }
    saveBookmarkedQuotes(bookmarkedQuotes)
    
    interactionsIncrease()
}

解决方案

1. 修正初始化顺序

Swift要求初始化时必须先完成所有存储属性的初始化,包括@Binding对应的底层变量。报错原因是你在初始化_isBookmarked、_isLiked之后才初始化_savedQuotes,而isQuoteBookmarked函数大概率依赖savedQuotes数组(判断当前quote是否已收藏),导致编译器认为savedQuotes未初始化就被调用。

调整初始化顺序,先完成_savedQuotes的初始化,再调用依赖它的函数:

@Binding private var savedQuotes: [Quote]
private let quote: Quote
@State private var isBookmarked: Bool
@State private var isLiked: Bool

init(quote: Quote, savedQuotesArg: Binding<[Quote]>) {
    self.quote = quote
    self._savedQuotes = savedQuotesArg
    // 通过wrappedValue直接获取Binding的当前值,避免访问未完全初始化的self
    self._isBookmarked = State(initialValue: isQuoteBookmarked(quote, savedQuotes: savedQuotesArg.wrappedValue))
    self._isLiked = State(initialValue: isQuoteLiked(quote))
}

同时需要修改isQuoteBookmarked函数,新增savedQuotes参数,直接传入数组值而非依赖内部访问。

2. 简化初始化逻辑(可选)

如果isBookmarked的状态不需要在初始化时确定,可以把状态延迟到视图出现时设置,避免初始化顺序问题:

@Binding private var savedQuotes: [Quote]
private let quote: Quote
@State private var isBookmarked: Bool = false
@State private var isLiked: Bool = false

init(quote: Quote, savedQuotesArg: Binding<[Quote]>) {
    self.quote = quote
    self._savedQuotes = savedQuotesArg
}

var body: some View {
    // 视图内容
    .onAppear {
        isBookmarked = isQuoteBookmarked(quote, savedQuotes: savedQuotes)
        isLiked = isQuoteLiked(quote)
    }
}

3. 完善toggleBookmark函数的数组修改逻辑

通过@Binding修改数组时,SwiftUI会自动同步回父视图的@State变量,确保数据一致性:

private func toggleBookmark() {
    isBookmarked.toggle()
    
    var bookmarkedQuotes = getBookmarkedQuotes()
    if isBookmarked {
        bookmarkedQuotes.append(quote)
        savedQuotes.append(quote) // 同步添加到父视图数组
    } else {
        bookmarkedQuotes.removeAll { $0.id == quote.id }
        savedQuotes.removeAll { $0.id == quote.id } // 同步从父视图数组移除
    }
    saveBookmarkedQuotes(bookmarkedQuotes)
    
    interactionsIncrease()
}

注意:如果getBookmarkedQuotes是从本地存储读取数据,建议以savedQuotes为唯一数据源,避免本地存储和内存数组出现数据不一致的情况。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 05:49:52