我需要在
中定义引用@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, Codable, 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,
"imageName":"test-f1a",
"imageUrl":"https://my-url/test-f1a",
"description":"test1a",
"category":"test1"
},
...
]
答案 0 :(得分:0)
从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
}
}
答案 1 :(得分:0)
将“分组:testData”替换为“分组:networkManager.tests”,并使用“ @ObservedObject var networkManager:NetworkManager = NetworkManager()”,使testData的定义变得多余,从而解决了问题。感谢@Josh Homann的回答和评论,这帮助我克服了这个问题。