swiftui - 协议“GetSignQuestions”只能用作通用约束,因为它具有 Self 或关联的类型要求
问题描述
我有一个协议和两个不同的扩展。当 PoliceSignalsView 打开时,当我使用 PoliceSignQuestion() 更改 SignQuestionProvider 中的共享变量时,它会返回与警察相关的问题。如果我用 TrafficSignQuestion() 替换它,它会返回与交通相关的问题。这工作正常。但是,有一个问题。
型号 1:
struct TrafficSignQuestion: Codable, Hashable {
var trafficQuestions: [TrafficSign]?
}
enum TrafficSignSectionType: String, Codable, Hashable {
case A = "A"
case B = "B"
}
struct TrafficSign: Codable, Hashable {
var id: Int?
var image: String?
var sections: [TrafficSignSectionType.RawValue : String]?
var correct: String?
}
型号 2:
struct PoliceSignQuestion: Codable, Hashable {
var policeQuestions: [PoliceSign]?
}
enum PoliceSignSectionType: String, Codable, Hashable {
case A = "A"
case B = "B"
case C = "C"
}
struct PoliceSign: Codable, Hashable {
var id: Int?
var image: String?
var sections: [PoliceSignSectionType.RawValue : String]?
var correct: String?
}
协议:
protocol GetSignQuestions {
func getQuestions(jsonService: JSONService) -> [Self]?
}
**SignQuestionProvider**
class SignQuestionProvider<T: Any>: ObservableObject {
var shared: GetSignQuestions?
@Published var allQuestions: T?
func getQuestions() {
let questions = shared?.getQuestions(jsonService: JSONService())
allQuestions = questions as? T
print("\(allQuestions)")
}
}
扩展:
extension PoliceSign: GetSignQuestions {
func getQuestions(jsonService: JSONService) -> [PoliceSign]? {
if let questions = jsonService.getQuestion(fileName: "policeQuestions", using: PoliceSignQuestion.self) {
return questions.policeQuestions ?? []
}
return []
}
}
extension TrafficSign: GetSignQuestions {
func getQuestions(jsonService: JSONService) -> [TrafficSign]? {
if let questions = jsonService.getQuestion(fileName: "trafficQuestions", using: TrafficSignQuestion.self) {
return questions.trafficQuestions ?? []
}
return []
}
}
JSON服务:
class JSONService: ObservableObject {
func getQuestion<T: Codable>(fileName: String, using modelType: T.Type) -> T? {
if let url = Bundle.main.url(forResource: fileName, withExtension: "json") {
do {
let data = try Data(contentsOf: url)
let decoder = JSONDecoder()
let jsonData = try decoder.decode(modelType, from: data)
return jsonData
} catch {
print("error:\(error)")
}
}
return nil
}
}
警察信号视图(FirstView):
如何将我从这里获得的数据传输到 QuestionCardView()?我无法进行通用绑定构建。
struct PoliceSignalsView: View {
@StateObject var questionProvider = SignQuestionProvider<PoliceSignQuestion>()
var body: some View {
VStack {
QuestionCardView()
}
.onAppear {
questionProvider.shared = PoliceSignQuestion()
// When I change it to "TrafficSignQuestion", the TrafficSign function in the protocol works and returns TrafficSigns questions. I want to pass the result returned from here to QuestionCardView. How can I do that ?
questionProvider.getQuestions()
}
.environmentObject(questionProvider)
}
}
第二视图(问题卡视图):
在此处显示来自policeSignalsView 的数据时,我不想看到policeQuestions 属性,因为它可以在此页面的trafficQuestions 中。如果我这样写,我会得到一个错误。我该如何解决这个问题?
struct QuestionCardView: View {
@EnvironmentObject var optionConfigure: OptionConfigure
@EnvironmentObject var questionProvider: SignQuestionProvider<PoliceSignQuestion>
var body: some View {
VStack {
ForEach(questionProvider.allQuestions?.policeQuestions?.indices ?? 0..<0, id: \.self) { item in
// here.. I don't want the "policeQuestions" property here. Because it should be a generic construct.
Text("")
.animation(.spring())
}
}
}
}
正如我所说,我不希望 QuestionCardView 屏幕上 ForEach 中的 policeQuestions 属性。我按照这种方式将其删除。
协议:
protocol GetSignQuestions {
func getQuestions(jsonService: JSONService) -> [Self] // Array
}
扩展:
extension PoliceSign: GetSignQuestions {
func getQuestions(jsonService: JSONService) -> [PoliceSign] {
if let questions = jsonService.getQuestion(fileName: "policeQuestions", using: PoliceSignQuestion.self) {
return questions.policeQuestions ?? []
}
return []
}
}
extension TrafficSign: GetSignQuestions {
func getQuestions(jsonService: JSONService) -> [TrafficSign] {
if let questions = jsonService.getQuestion(fileName: "trafficQuestions", using: TrafficSignQuestion.self) {
return questions.trafficQuestions ?? []
}
return []
}
}
警察信号查看:
struct PoliceSignalsView: View {
@StateObject var questionProvider = SignQuestionProvider<PoliceSign>()
var body: some View {
VStack {
QuestionCardView()
}
.onAppear {
questionProvider.shared = PoliceSign()
questionProvider.getQuestions()
}
.environmentObject(questionProvider)
}
}
当我以这种方式进行更改时,我会收到图像中的错误。
解决方案
我已经重新组织了一些代码,并重新添加了Question
我之前对您的回答中的协议。我还稍微编辑了您的模型以使TrafficSign
和PoliceSign
具有非可选id
属性。否则,在 中使用它们将ForEach
是有问题的。
struct TrafficSignQuestion: Codable, Hashable {
var trafficQuestions: [TrafficSign]?
}
enum TrafficSignSectionType: String, Codable, Hashable {
case A = "A"
case B = "B"
}
struct TrafficSign: Codable, Hashable, Question {
var id: Int
var image: String?
var sections: [TrafficSignSectionType.RawValue : String]?
var correct: String?
}
struct PoliceSignQuestion: Codable, Hashable {
var policeQuestions: [PoliceSign]?
}
enum PoliceSignSectionType: String, Codable, Hashable {
case A = "A"
case B = "B"
case C = "C"
}
struct PoliceSign: Codable, Hashable, Question {
var id: Int
var image: String?
var sections: [PoliceSignSectionType.RawValue : String]?
var correct: String?
}
protocol Question {
var id: Int { get set }
var image: String? { get set }
}
protocol GetSignQuestions {
associatedtype QuestionType : Question
func getQuestions(jsonService: JSONService) -> [QuestionType]?
}
class SignQuestionProvider<T: GetSignQuestions>: ObservableObject {
@Published var allQuestions : [T.QuestionType] = []
func getQuestions(getter: T) {
if let questions = getter.getQuestions(jsonService: JSONService()) {
self.allQuestions = questions
}
print("\(allQuestions)")
}
}
struct PoliceSignGetter : GetSignQuestions {
func getQuestions(jsonService: JSONService) -> [PoliceSign]? {
if let questions = jsonService.getQuestion(fileName: "policeQuestions", using: PoliceSignQuestion.self) {
return questions.policeQuestions ?? []
}
return []
}
}
struct TrafficSignGetter: GetSignQuestions {
func getQuestions(jsonService: JSONService) -> [TrafficSign]? {
if let questions = jsonService.getQuestion(fileName: "trafficQuestions", using: TrafficSignQuestion.self) {
return questions.trafficQuestions ?? []
}
return []
}
}
class JSONService: ObservableObject {
func getQuestion<T: Codable>(fileName: String, using modelType: T.Type) -> T? {
if let url = Bundle.main.url(forResource: fileName, withExtension: "json") {
do {
let data = try Data(contentsOf: url)
let decoder = JSONDecoder()
let jsonData = try decoder.decode(modelType, from: data)
return jsonData
} catch {
print("error:\(error)")
}
}
return nil
}
}
struct PoliceSignalsView: View {
@StateObject var questionProvider = SignQuestionProvider<PoliceSignGetter>()
var body: some View {
VStack {
QuestionCardView<PoliceSign>(questions: questionProvider.allQuestions)
}
.onAppear {
questionProvider.getQuestions(getter: PoliceSignGetter())
}
}
}
struct QuestionCardView<T: Question>: View {
var questions: [Question]
var body: some View {
VStack {
ForEach(questions, id: \.id) { item in
Text("")
.animation(.spring())
}
}
}
}
推荐阅读
- c# - 如何将图像从 UWP 发布到 .NET 核心 Web api?
- voltdb - 从 VoltDB 定期运行 VoltDB 存储过程
- python - PyQt 5.10 - 为 MacOS 启用高 DPI 支持,像素图质量差
- meshlab - MeshLab:如何实现各个组件的信息
- apache-spark - 生产 Spark Pipeline
- swift - 将文本输入保存到设备
- python - 在达到一定的准确性后,有什么方法可以停止在 Keras 中训练模型?
- mongodb - React Fullstack 应用程序显示 mongodb 连接错误
- android - 尝试从图像文件中解码位图并发送到服务器
- java - 动态更改 side_nav_bar.xml 形状颜色的颜色