如何解决iOS 14将ObservedObject添加到var导致视图不出现在iPhone上
我正在研究斯坦福在线CS139p中的示例。绘制了用于记忆游戏的卡。我将viewmodel设置为ObservableObject,发布代表内存游戏的var,然后运行该应用程序。一切都按我的预期进行。然后,将@Observedobject属性处理器添加到视图控制器中的viewmodel var中。当我运行该应用程序时,我不再看到卡片被抽出。
问题1:发生了什么事?
问题2:我该如何调试?我尝试设置一个断点并逐步通过,但我无法确定出了什么问题。我在Google上搜索了一下,找到了一些可以尝试的方法,但最终无法使其正常工作。这个例子是一年前我第一次尝试时为我工作的。
MemorizeApp.swift
import SwiftUI
@main
struct MemorizeApp: App {
var body: some Scene {
WindowGroup {
let game = EmojiMemoryGame()
EmojiMemoryGameView(viewmodel: game)
}
}
}
EmojiMemoryGameView.swift
import SwiftUI
// uncomment the below line and then comment the line below it to see the condition that does not work.
struct EmojiMemoryGameView: View {
// @Observedobject var viewmodel: EmojiMemoryGame
var viewmodel:EmojiMemoryGame
var body: some View {
HStack {
ForEach(viewmodel.cards) { card in
CardView(card: card).onTapGesture {
viewmodel.choose(card: card)
}
}
}
.foregroundColor(Color.orange)
.padding()
.font(viewmodel.cards.count == 10 ? Font.title : Font.largeTitle)
}
}
struct CardView: View {
var card: MemoryGame<String>.Card
var body: some View {
ZStack {
if card.isFaceUp {
RoundedRectangle(cornerRadius: 10.0).fill(Color.white)
RoundedRectangle(cornerRadius: 10.0).stroke(linewidth: 3.0)
Text(card.content)
} else {
RoundedRectangle(cornerRadius: 10.0).fill()
}
}
.aspectRatio(2/3,contentMode: .fit)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
EmojiMemoryGameView(viewmodel: EmojiMemoryGame())
}
}
EmojiMemoryGame.swift
import SwiftUI
func createCardContent(pairIndex: Int) -> String {
return "?"
}
// This is the viewmodel
class EmojiMemoryGame: ObservableObject {
@Published private var model: MemoryGame<String> = EmojiMemoryGame.createMemoryGame()
static func createMemoryGame() -> MemoryGame<String> {
let emojies = ["?","?","?"]
return MemoryGame<String>(numberOfPairsOfCards: Int.random(in: 2...5)) { pairIndex in
return emojies.randomElement()!
//return emojies[pairIndex]
}
}
// MARK: Access to the Model
var cards: Array<MemoryGame<String>.Card> {
model.cards.shuffle()
return model.cards
}
// MARK: Intent(s)
func choose(card: MemoryGame<String>.Card) {
model.choose(card: card)
}
}
MemoryGame.swift
import Foundation
struct MemoryGame<CardContent> {
var cards: Array<Card>
mutating func choose(card: Card) {
print("Card Choosen: \(card)")
let chosenIndex: Int = index(of: card)
cards[chosenIndex].isFaceUp = !cards[chosenIndex].isFaceUp
}
func index(of card: Card) -> Int {
for index in 0..<cards.count {
if self.cards[index].id == card.id {
return index
}
}
return 0 // Todo: bogus!
}
init(numberOfPairsOfCards: Int,cardContentFactory: (Int) -> CardContent) {
cards = Array<Card>()
for pairIndex in 0..<numberOfPairsOfCards {
let content = cardContentFactory(pairIndex)
cards.append(Card(content: content,id: pairIndex*2))
cards.append(Card(content: content,id: pairIndex*2+1))
}
}
struct Card: Identifiable {
var isFaceUp: Bool = true
var isMatched: Bool = false
var content: CardContent
var id: Int
}
}
解决方法
通过更改对象@ObservedObject
的属性,@Published
可以使视图重新呈现,这是通过其objectWilLChange
属性(也可以直接通过@Published
来确定的,但是不会)在这里申请)。
您只有一个@Published private var model: MemoryGame<String> = ...
属性,即:
model
(无关紧要,它仍然是通知观察对象的对象)
因此,只要更新cards
,视图就会重新呈现。
事实上,模型总是在计算属性ForEach
中更新,视图通过其var cards: Array<MemoryGame<String>.Card> {
model.cards.shuffle() // this mutates the model
return model.cards
}
访问该属性:
model.cards.shuffle()
因此,基本上,当视图重新计算其主体时,该主体访问其视图模型,从而导致其作为副作用发生变异,该状态已经失效,并且需要进行另一次重新计算-在无穷大中循环。
在吸气剂内部产生副作用通常是一种糟糕的做法。
解决方法是从吸气剂内部移除bundle -v
Bundler version 2.1.4
ruby -v
ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x86_64-linux-gnu]
bundle -v
Bundler version 2.1.4
rvm -v
rvm 1.29.10 (manual) by Michal Papis,Piotr Kuczynski,Wayne E. Seguin [https://rvm.io]
rails -v
Rails 5.2.3
,并将其放在有意义的其他位置。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。