我目前正在使用SwiftUI和Combine进行项目。我正在使用Xcode11 Beta5。我想获取我的Github存储库,显示它们,然后可以对其中一些添加书签。
我能够获取它们并显示它们。我正在使用Combine with @Published属性包装器来更新我的视图。到目前为止,一切都按预期进行。
因此,我继续下一步,为存储库添加了书签。我想使用Realm来保留这些存储库。
我的问题是,我有一个Observable类,该类具有一个@Published的存储库数组。存储库是可解码的类。在我的存储库类中,现在有一个简单的类属性isFavorite设置为false。
在我的存储库列表中,当我单击存储库以查看详细信息时,我希望可以将其添加为书签。因此,我从存储库数组中按其ID检索其索引,并将其属性isFavorite设置为true。但是我的观点没有更新。我的意思是我有条件渲染,并且被固定为false。
这是我的代码:
import SwiftUI import Combine struct RepositoryList : View { @ObservedObject var store: Store func move(from source: IndexSet, to destination: Int) { store.repositories.swapAt(source.first!, destination) } @State private var isTapped = false @State private var bgColor = Color.white var body: some View { NavigationView { VStack { List { Section(header: Text("\(String(store.repositories.count)) repositories")) { ForEach(store.repositories) { repository in NavigationLink(destination: RepositoryDetail(store: self.store, repository: repository)) { RepositoryRow(repository: repository) }.padding(.vertical, 8.0) }.onDelete { index in self.store.repositories.remove(at: index.first!) }.onMove(perform: move) } } } }.navigationBarTitle("Github user").navigationBarItems(trailing: EditButton()) } } struct RepositoryDetail : View { @ObservedObject var store: Store var repository: Repository var repoIndex: Int { let repoIndex = store.repositories.firstIndex(where: {$0.id == repository.id})! print("### IS FAVORITE \(String(store.repositories[repoIndex].isFavorite))") return repoIndex } var body: some View { VStack(alignment: .leading) { Text(String(store.repositories[repoIndex].isFavorite)) Button(action: { self.store.repositories[self.repoIndex].isFavorite.toggle() }) { if (self.store.repositories[self.repoIndex].isFavorite) { Image(systemName: "star.fill").foregroundColor(Color.yellow) } else { Image(systemName: "star").foregroundColor(Color.gray) } } }.navigationBarTitle(Text(repository.name), displayMode: .inline) } } class Store: ObservableObject { private var cancellable: AnyCancellable? = nil @Published var repositories: [Repository] = [] init () { var urlCompOnents= URLComponents(string: "https://api.github.com/users/Hurobaki/repos")! var request = URLRequest(url: urlComponents.url!) request.addValue("application/json", forHTTPHeaderField: "Content-Type") cancellable = URLSession.shared.send(request: request) .decode(type: [Repository].self, decoder: JSONDecoder()) .receive(on: DispatchQueue.main) .sink(receiveCompletion: { completion in print("### .sink() received the completion", String(describing: completion)) switch completion { case .finished: break case .failure(_): print("### ERROR") } }, receiveValue: { repositories in self.repositories = repositories }) } } class Repository: Decodable, Identifiable { var id: Int = 0 var name: String = "" var desc: String? = nil var isFavorite = false private enum CodingKeys: String, CodingKey { case id, name case desc = "description" } }
我不知道为什么我的Button组件永远不会显示Image(systemName: "star.fill").foregroundColor(Color.yellow)
当我打印isFavorite属性时,它的值从true变为false,反之亦然,但是我的视图没有更新。
我从Apple Developer那里获得了教程,他们做的事情完全相同,所以我不知道为什么会出现这个错误,我想念的是什么?
一些帮助将不胜感激和/或评论我的代码:)
谢谢
PS:为了不发布更长的代码,我已将其上传到Pastebin https://pastebin.com/zjDwQSGq
感谢您发布完整的代码。它使故障排除变得更加容易。
您的问题很简单。您创建Repository
了一个类,而不是一个结构。这意味着,当您更改时.isFavorite
,数组中的对象不会更改,因为它是引用类型。如果您更改并且将Repository构造为结构,则代码将起作用,因为更改时,.isFavorite
您实际上是在更改值,而Publisher会捕获它。
如果您不知道引用类型和值类型之间的区别,请检查以下页面:https : //developer.apple.com/swift/blog/?id=10对其进行了详细说明。但是请记住,类是引用类型,而结构是值类型。
如果您仍然想保留Repository
一个类,可以这样做,但是您需要在商店的objectWillChange主题上手动调用send:
Button(action: {
self.store.repositories[self.repoIndex].isFavorite.toggle()
self.store.objectWillChange.send()
}) {
if (self.store.repositories[self.repoIndex].isFavorite) {
Image(systemName: "star.fill").foregroundColor(Color.yellow)
} else {
Image(systemName: "star").foregroundColor(Color.gray)
}
}