SwiftUI中Reminder结构体每次打开视图生成新UUID的问题
问题分析与解决方案:ExploreView中Reminder的UUID重复生成问题
问题描述
我开发了一款存储名言类提醒的App,ContentView展示提醒内容,支持用户自定义创建,也能从ExploreView添加我手动录入的提醒元素。但每次把ExploreView里的元素添加到ContentView数组时,会携带该元素的UUID,可从ContentView返回ExploreView后,所有元素的UUID都变成新的了。我尝试把ExploreReminder数组转移到外部类,问题依然存在。
核心原因
- Reminder的UUID自动生成逻辑:你的
Reminder结构体里id是默认赋值var id = UUID(),每次创建Reminder实例都会生成新的UUID。 - ExploreReminders重复初始化:
ExploreView里用@State var exploreReminders = ExploreReminders(),当视图重新加载(比如从详情页返回)时,会重新创建ExploreReminders实例,导致里面的所有Reminder被重新初始化,UUID全部更新。
解决方案
步骤1:修改Reminder结构体,固定预设内容的UUID
让Reminder支持两种初始化方式:自定义提醒自动生成UUID,预设名言手动传入固定UUID,避免重复生成:
struct Reminder: Codable, Identifiable, Equatable, Hashable{ var id: UUID var phrase: String var author: String // 自定义提醒用:自动生成UUID init(phrase: String, author: String) { self.id = UUID() self.phrase = phrase.addQuotationMarks() self.author = author } // 预设名言用:手动传入固定UUID init(id: UUID, phrase: String, author: String) { self.id = id self.phrase = phrase.addQuotationMarks() self.author = author } }
注:把
phrase.addQuotationMarks()的结果直接赋值,避免在初始化里修改值类型的属性引发意外。
步骤2:将ExploreReminders改为全局单例
确保整个App里只有一个ExploreReminders实例,预设数组只初始化一次:
class ExploreReminders { // 全局单例 static let shared = ExploreReminders() // 给每个预设名言分配固定UUID(自己生成替换下面的示例UUID) let exploreReminders: [Reminder] = [ Reminder(id: UUID(uuidString: "E621E1F8-C36C-495A-93FC-0C247A3E6E5F")!, phrase: "Two things are infinite: the universe and human stupidity; and I'm not sure about the universe.", author: "Albert Einstein"), Reminder(id: UUID(uuidString: "3D4F1A7B-8C9D-4E5F-A6B7-C8D9E0F1A2B3")!, phrase: "The only way to do great work is to love what you do.", author: "Steve Jobs"), Reminder(id: UUID(uuidString: "1A2B3C4D-5E6F-7A8B-9C0D-1E2F3A4B5C6D")!, phrase: "Life is what happens when you're busy making other plans.", author: "John Lennon"), Reminder(id: UUID(uuidString: "9F8E7D6C-5B4A-3210-FEDC-BA9876543210")!, phrase: "In three words I can sum up everything I've learned about life: it goes on.", author: "Robert Frost"), Reminder(id: UUID(uuidString: "A1B2C3D4-E5F6-A7B8-C9D0-E1F2A3B4C5D6")!, phrase: "You only live once, but if you do it right, once is enough.", author: "Mae West"), Reminder(id: UUID(uuidString: "FEDCBA98-7654-3210-FEDC-BA9876543210")!, phrase: "Yesterday is history, tomorrow is a mystery, today is a gift of God, which is why we call it the present.", author: "Bil Keane") ] // 私有化初始化,禁止外部创建新实例 private init() {} }
可以用Xcode的
Editor > Insert UUID生成专属固定UUID,替换示例中的字符串。
步骤3:修改ExploreView使用单例实例
去掉@State修饰的exploreReminders,直接使用全局单例:
struct ExploreView: View { // 直接调用单例,无需@State let exploreReminders = ExploreReminders.shared @EnvironmentObject var allReminders: AllReminder @State private var userSearch = "" var searchResults: [Reminder] { if userSearch.isEmpty{ return exploreReminders.exploreReminders } else{ let editedUserSearch = userSearch.lowercased().trimmingCharacters(in: .whitespacesAndNewlines) return exploreReminders.exploreReminders.filter { let editedPhrase = $0.phrase.lowercased().trimmingCharacters(in: .whitespacesAndNewlines) let editedAuthor = $0.author.lowercased().trimmingCharacters(in: .whitespacesAndNewlines) return editedPhrase.contains(editedUserSearch) || editedAuthor.contains(editedUserSearch) } } } var body: some View { NavigationStack { ScrollView{ LazyVGrid(columns:[ GridItem(.flexible(minimum: 100, maximum: 200), spacing: 20), GridItem(.flexible(minimum: 100, maximum: 200), spacing: 20) ], spacing: 20) { ForEach(searchResults) { reminder in NavigationLink{ ReminderDetailView(reminder: reminder, allReminders: allReminders) } label:{ ReminderView(reminder: reminder, allReminders: allReminders) .aspectRatio(1, contentMode: .fit) } } } .padding() } .navigationTitle("Explore") .searchable(text: $userSearch, placement: .navigationBarDrawer(displayMode: .always), prompt: "Search for Phrases or Authors") } } }
额外优化:用环境变量传递AllReminder
确保AllReminder是可观察对象,并通过环境传递,避免视图间数据传递异常:
class AllReminder: ObservableObject { @Published var reminders: [Reminder] = [] func addReminder(_ reminder: Reminder) { // 避免重复添加 if !reminders.contains(where: { $0.id == reminder.id }) { reminders.append(reminder) } } } // 在App入口初始化并传递 @main struct YourApp: App { @StateObject var allReminders = AllReminder() var body: some Scene { WindowGroup { ContentView() .environmentObject(allReminders) } } }
内容的提问来源于stack exchange,提问作者registrier rp
相关产品推荐
相关产品推荐

