微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

iOS 14将ObservedObject添加到var导致视图不出现在iPhone上

如何解决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 举报,一经查实,本站将立刻删除。