当前位置: 首页 > 知识库问答 >
问题:

我是否可以创建一个可由多个ContentView使用的通用ObserveObject类?

白坚壁
2023-03-14

嗨,我只是想知道有没有可能创建一个通用类来确认ObserveObject协议,它可以被多个ContentView使用。

如果我能做到这一点,那么我将能够使我的ContentView和Model类完全通用和可重用。

我希望实现的一个例子:

protocol ContentViewModelType: ObservableObject {
    var propertyToInitialiseView: [String] { get }
}

struct ContentView: View {
    @ObservedObject var viewModel: some ViewModel

    var body: some View {
        Text("Hello World")
    }
}

如果我能做到这一点,任何类都可以实现ContentViewModelType,并成为ContentView的模型,使其通用且可重用。举个例子

class ViewModel: ObservableObject {
    var objectWillChange = PassthroughSubject<ViewModel, Never>()
}

但是当我尝试初始化ContentView时,xcode给我一个类型错误。

我认为引入一些关键字的目的是为了让我们可以使用protocol作为那些需要关联类型的协议的类型,因此这应该是可行的。但它给出了一个错误。

如果任何人有任何关于这个问题的参考资料或知识,他们可以分享,或者可能有一个解决方案,那就太好了。

提前谢谢。

共有3个答案

秦天宇
2023-03-14

如果我没理解错的话,你可以这样做:

您可以有一个ObserveObject类,如下所示:

import Foundation

class SampleTimer: ObservableObject {
    @Published var timerVar: Int = 0

    init(){
        Timer.scheduledTimer(withTimeInterval: 1, repeats: true){
            timer in
            DispatchQueue.main.async {
                self.timerVar += 1
            }
        }
    }
}

内容视图:

import SwiftUI

struct ContentView: View {
    @ObservedObject var sampleTimer = SampleTimer()
    var body: some View {
        NavigationView {
            VStack {
                Text("\(sampleTimer.timerVar)")
                NavigationLink(destination: SecondView(sampleTimer: sampleTimer) ){
                    Text("Go to second view")
                }
            }
        }
    }
}

第二种观点是:

import SwiftUI

struct SecondView: View {
    @ObservedObject var sampleTimer : SampleTimer
    var body: some View {
        VStack {
            Text("\(sampleTimer.timerVar)")
        }
    }
}

我想概述的重要事情是,如果您像我一样有一个计时器,并且它在init()函数中初始化,并且您在第二视图中创建了一个新的SampleTimer()实例(即:####################################################################################################################################################################这意味着ContentView第二视图中的值不会相同。

向泽语
2023-03-14

这不是some的目的some创建不透明的返回类型,而不是存在(“any”)类型。有关更多详细信息,请参阅文档。另请参见SwiftUI中的'some'关键字是什么?

某个类型必须是编译时已知的单个类型。只是打电话的人不知道。您要做的是传递存在主义,这是运行时已知的类型。Swift 5.1中关于存在主义的内容没有任何改变。如果这是您想要的,您仍然需要用AnyContentViewModel将其包装起来。(我需要考虑一下这是否是个好主意。

但是你写的代码也没有做到你所描述的。您实际上并没有在任何地方使用ContentViewModelType。你是说一些ContentViewModelType吗?那仍然行不通,但似乎就是你的意思。

淳于典
2023-03-14

试图理解你的问题,但我不太确定我是否理解你的意图。。。但要创建一个采用通用视图模型(基于之前的协议)的视图,需要以下代码:

protocol ViewModelWithProperties: ObservableObject {
    var properties: [String] { get }
}

struct SomeView<T>: View where T: ViewModelWithProperties {
// this can also be written as 
// struct SomeView<T: ViewModelWithProperties>: View {
    @ObservedObject var item: T

    var body: some View {
        VStack {
            ForEach(item.properties, id: \.self) {
                Text($0)
            }
        }
    }
}

要使用此实例,您需要:

struct ContentView: View {
    var body: some View {
        SomeView(item: MyViewModel())
    }
}

正如在另一个答案中所述,some用于不透明类型,它不会使您的代码通用。

 类似资料:
  • 我有两个版本的应用程序: > 没有广告。 我的应用程序中有订阅。我想在这些应用程序之间共享一个订阅。例如这样一个场景: 用户在应用程序中购买带有广告的订阅,然后购买没有广告的应用程序。我想将第一个应用程序中的订阅分享给第二个应用程序。有没有可能使用标准的谷歌账单库?

  • 问题内容: 想法是在片中具有可变数量的通道,将通过通道接收的每个值推入单个通道,并在最后一个输入通道关闭后关闭该输出通道。这样的事情,但对于多个渠道来说,要超过两个: 上面的代码避免了繁忙的循环,因为没有任何情况,这是很好的(编辑:看起来,“,ok”的存在使select语句成为非阻塞状态,并且循环毕竟是繁忙的。但是出于示例的目的,就好像将代码阻止一样)。是否可以通过任意数量的输入通道来实现相同的功

  • 问题内容: 是否可以创建一个使用EasyMock实现多个接口的模拟对象? 例如,接口和接口? 在Rhino Mocks中,创建模拟对象时可以提供多个接口,但是EasyMock的方法仅采用一种类型。 是否可以通过EasyMock来实现此目的,而不必依靠创建扩展了和的临时接口,然后进行模拟的后备呢? 问题答案: EasyMock不支持此功能,因此您会陷入临时接口的后备状态。 顺便说一句,我闻到了一些代

  • 问题内容: 我想创建一个包含一个或多个容器的Docker容器。Docker有可能吗? 问题答案: 在docker内部运行docker绝对是可能的。最主要的是,您将外部容器具有额外的特权(以开头),然后在该容器中安装docker。 查看此博客文章以获取更多信息:Docker-in-Docker。 本条目中描述了一种可能的用例。该博客介绍了如何在Jenkins Docker容器中构建Docker容器。

  • 我有几份产品数据表。每个文件都是一个单独的文件。我想做的是使用iText根据Web表单的答案生成一组摘要/建议的操作,然后将所有相关的数据表附加到这些操作中。这样,我只需要在浏览器中打开一个新选项卡来打印所有信息,而不是为摘要打开一个选项卡,为所需的每个数据表打开一个选项卡。 那么,使用iText可以做到这一点吗?

  • 从文档中可以看出,这在spring-boot-maven-plugin中是不可能的。 所以现在我正在尝试创建一个测试JAR,但是当我运行应用程序类时,我得到了 有没有关于如何在没有maven插件的情况下打包SpringBoot应用程序的文档?