如何在以下类别中引用@Published var:类NetworkManager:ObservableObject

我需要在

中定义引用@Published var测试的testData:[Test]:[Test]

NetworkManager类:ObservableObject(请参见代码)。

我尝试了以下定义:

/// The app does not compile with this definition
//let testData:[Test] = NetworkManager(tests: Test)

/// The app works with this definition,but shows no remote json data
let testData:[Test] = NetworkManager().tests

class NetworkManager: ObservableObject {

@Published var tests:[Test] = [Test]()

func getallTests() {
    let file = URLRequest(url: URL(string: "https://my-url/remote.json")!)
    let task = URLSession.shared.dataTask(with: file) { (data,_,error) in
    guard error == nil else { return }

        do {
            let tests = try JSONDecoder().decode([Test].self,from: data!)

            DispatchQueue.main.async {
                    self.tests = tests
                print(tests)

            }
        } catch {
            print("Failed To decode: ",error)
        }
    }
    task.resume()
}
    init() {
        getallTests()
}
    init(tests: [Test]) {
        self.tests = tests
}
}

下面的代码可以正常工作

/// The app works with this definition and shows the local json data
let testData:[Test] = load("local.json")

func load<T:Decodable>(_ filename:String,as type:T.Type = T.self) -> T {
let data:Data
guard let file = Bundle.main.url(forResource: filename,withExtension: nil)
    else {
        fatalError("Couldn't find \(filename) in main bundle.")
}
do {
    data = try Data(contentsof: file)
} catch {
    fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
}

do {
    let decoder = JSONDecoder()
    return try decoder.decode(T.self,from: data)
} catch {
    fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
}
}

但是,对于第一部分,我会收到错误消息:

“无法将类型'Test.Type'的值转换为预期的参数类型'[Test]'”

我在这里想念什么?我们非常感谢您的帮助。

针对回答和问题的其他信息,显示了如何使用testData:

import SwiftUI
import Combine

struct Test: Hashable,Codable,Identifiable {
    var id:Int
    var imageName:String
    var imageUrl:String
    var category:Category
    var description:String

    enum Category: String,CaseIterable,Hashable {
        case t1 = "test1"
        case t2 = "test2"
        case t3 = "test3"
    }
}

class NetworkManager: ObservableObject {

      @Published var tests:[Test] = [Test]()
      private var subscriptions = Set<AnyCancellable>()

      func getallTests() {
        let file = URLRequest(url: URL(string: "https://my-url/remote.json")!)
        URLSession
          .shared
          .dataTaskPublisher(for: file)
          .map(\.data)
          .decode(type: [Test].self,decoder: JSONDecoder())
          .replaceError(with: [])
          .receive(on: RunLoop.main)
          .assign(to: \.tests,on: self)
          .store(in: &subscriptions)
      }
      init() {
        getallTests()
      }
      init(tests: [Test]) {
        self.tests = tests
      }
    }

let testData:[Test] = NetworkManager().tests

struct ContentView: View {

var categories:[String:[Test]] {
    .init(
        grouping: testData,by: {$0.category.rawValue}
    )
}

var body: some View {
    NavigationView{
        List (categories.keys.sorted(),id: \String.self) {key in TestRow(categoryName: "\(key) - Case".uppercased(),tests: self.categories[key]!)
            .frame(height: 320)
            .padding(.top)
            .padding(.bottom)
        }
        .navigationBarTitle(Text("TEST"))
    }
}

}

struct TestRow: View {

var categoryName:String
var tests:[Test]

    var body: some View {

        VStack {

            Text(self.categoryName)
                .font(.title)
                .multilineTextAlignment(.leading)

                ScrollView(.horizontal,showsIndicators: false) {
                    HStack(alignment: .top) {
                        ForEach(self.tests,id: \.self) { tests in

                            NavigationLink(destination:
                                TestDetail(test: tests)) {
                                TestItem(test: tests)
                                    .frame(width: 300)
                                    .padding(.trailing,30)
                                  Spacer()

                        }}
                }
                .padding(.leading)
            }
        }

    }
}

struct TestDetail: View {

    var test:Test
    var body: some View {
        List{
        ZStack(alignment: .bottom) {

            Image(test.imageUrl)
                .resizable()
                .aspectRatio(contentMode: .fit)
            Rectangle()
                .padding()
                .frame(height: 80.0)
                .opacity(0.25)
                .blur(radius: 10)
            HStack{
                VStack(alignment: .leading) {
                    Text(test.imageName)
                        .padding()
//                    .color(.white)
                    .colorScheme(.light)
                    .font(.largeTitle)
            }
            .padding(.leading)
            .padding(.bottom)
            Spacer()
            }
        }
            .listRowInsets(EdgeInsets())
            VStack(alignment: .leading) {
                Text(test.description)
//                  .padding(.bottom)
//                  .color(.primary)
                    .colorScheme(.light)
                    .font(.body)
                    .lineLimit(nil)
                    .linespacing(12)

                HStack {
                    Spacer()
                    OrderButton()
                    Spacer()
                }.padding(.top,50)
            }.padding(.top)
            .padding(.bottom)
        }
        .edgesIgnoringSafeArea(.top)
    .navigationBarHidden(true)
    }
}

struct TestItem: View {

    var test:Test
    var body:some View{
        VStack(spacing: 16.0)
        {
            Image(test.imageUrl)
            .resizable()
            .renderingMode(.original)
            .aspectRatio(contentMode: .fill)
            .frame(width: 300,height: 170)
            .cornerRadius(10)
            .shadow(radius: 10)

            VStack(alignment: .leading,spacing: 5.0)
            {
            Text(test.imageName)
//                .color(.primary)
                .font(.headline)
            Text(test.description)
                .font(.subheadline)
                //                .color(.secondary)
                .multilineTextAlignment(.leading)
                .lineLimit(2)
                .frame(height: 40)
            }
        }
    }
}

struct OrderButton : View {
    var body: some View {
        Button(action: {}) {
            Text("Order Now")
        }.frame(width: 200,height: 50)
            .foregroundColor(.white)
            .font(.headline)
            .background(Color.blue)
        .cornerRadius(10)
    }
}

class ImageLoader:ObservableObject
{
    @Published var data:Data = Data()
    func getImage(imageURL:String) {
        guard let test = URL(string: imageURL) else { return }

        URLSession.shared.dataTask(with: test) { (data,response,error) in
            DispatchQueue.main.async {
                if let data = data {
                    self.data = data
                }
            }
            print(data as Any)
        }.resume()
    }
    init(imageURL:String) {
        getImage(imageURL: imageURL)
    }
}

struct ContentView_Previews: PreviewProvider {
    @ObservedObject var imageLoader: ImageLoader
    init(test:String)
    {
        imageLoader = ImageLoader(imageURL: test)
    }
    static var previews: some View {
        ContentView()
    }
}

// local.json

[
{
"id":101,"imageName":"test-f1a","imageUrl":"test-f1a","description":"test1a","category":"test1"
},...
]

// remote.json

[
{
"id":101,"imageUrl":"https://my-url/test-f1a",...
]
ttdrhfiaid 回答:如何在以下类别中引用@Published var:类NetworkManager:ObservableObject

从iOS 13开始,URLSession已与发布者进行了扩展,因此习惯上您的代码变为:

import UIKit
import Combine

struct Test: Codable {
  var name: String
}

class NetworkManager: ObservableObject {

  @Published var tests:[Test] = [Test]()
  private var subscriptions = Set<AnyCancellable>()

  func getAllTests() {
    let file = URLRequest(url: URL(string: "https://my-url/remote.json")!)
    URLSession
      .shared
      .dataTaskPublisher(for: file)
      .map(\.data)
      .decode(type: [Test].self,decoder: JSONDecoder())
      .replaceError(with: [])
      .receive(on: RunLoop.main)
      .assign(to: \.tests,on: self)
      .store(in: &subscriptions)
  }
  init() {
    getAllTests()
  }
  init(tests: [Test]) {
    self.tests = tests
  }
}
,

将“分组:testData”替换为“分组:networkManager.tests”,并使用“ @ObservedObject var networkManager:NetworkManager = NetworkManager()”,使testData的定义变得多余,从而解决了问题。感谢@Josh Homann的回答和评论,这帮助我克服了这个问题。

本文链接:https://www.f2er.com/3156537.html

大家都在问