SwiftUI List 需要精确的位置来渲染结果,所以如果没有 [0] 等就不会渲染结果

Posted

技术标签:

【中文标题】SwiftUI List 需要精确的位置来渲染结果,所以如果没有 [0] 等就不会渲染结果【英文标题】:SwiftUI List requires exact position to render results, so won't render result without [0] etc 【发布时间】:2022-01-11 03:27:55 【问题描述】:

在尝试从 SwiftUI 中的 REST API 端点解析一些数据时,我很难正确呈现到列表中。

在下面的示例中,我的 List 需要精确的数组位置来呈现结果,因此如果没有 [0] 等,它将不会显示任何内容...

我习惯于在 javascript 中使用 for 循环解决此类问题,并对其进行迭代以将每个数组位置分配给 [i],但在 SwiftUI 中我正在努力做同样的事情。

我认为这可能是我如何处理嵌套 JSON 对象的问题,但我们开始吧。我也相信这可能是一个简单的解决方案,我只是在这里空白。

我创建了一个测试端点,如果您需要在本地运行它可以从中获取(这已经在下面的示例中)。

澄清我要在这里做什么。我想遍历数组以引用(例如)Text(item.objects.title),而不必指定我要查找的数组中的哪个项目。可悲的是,使用 ForEach 不起作用,因为 List(viewModel.items, id: \.self) item in 本质上是在复制 ForEach 循环并且也不起作用。

型号

struct ObjectResponse: Hashable, Decodable 
    let objects: [Object]


struct Object: Hashable, Decodable 
    let slug: String
    let title: String
    let metadata: Metadata


struct Metadata: Hashable, Decodable 
    let published: String
    let url: String
    let snippet: String
    let read: Bool

视图模型


class ContentViewModel: ObservableObject 
    @Published var items: [ObjectResponse] = []
    func fetchData() 
        let api = "https://api.cosmicjs.com/v2/buckets/a5e294b0-55ee-11ec-942e-ef0a04148eb7/objects?pretty=true&query=%7B%22type%22%3A%22bookmarks%22%7D&read_key=fufvo5ceSy1W88afkchDIRjYrUIzErPw9YzcW2vQV1SxKqjNHo&limit=20&props=slug,title,content,metadata,"
        
        guard let url = URL(string: api) else  return 
        
        URLSession.shared.dataTask(with: url)  (data, response, error) in
            do 
                if let data = data 
                    let result = try JSONDecoder().decode(ObjectResponse.self, from: data)
                    DispatchQueue.main.async 
                        self.items = [result]
                        
                        /* Prints out everything nicely
                        result.objects.forEach 
                             print($0.title)
                        
                        */
                        
                    
                 else 
                    print("No data")
                
             catch (let error) 
                print(error)
            
        .resume()
    

内容视图

struct ContentView: View 
    @ObservedObject var viewModel = ContentViewModel()
    
    var body: some View 
        NavigationView 
            List(viewModel.items, id: \.self)  item in
                VStack(alignment: .leading) 
                    Text(item.objects[0].title) // Requires me to provide array position
                
            
            .navigationTitle("Bookmarks")
        
        .onAppear(perform: 
            viewModel.fetchData()
        )
    

JSON 响应示例


  "objects": [
    
      "slug": "the-navigation-bar-isnt-hidden-as-expected-in-swiftui",
      "title": "The Navigation Bar Isn’t Hidden as Expected in SwiftUI",
      "content": null,
      "metadata": 
        "published": "28 Nov 2021 at 16:30",
        "url": "https://betterprogramming.pub/swiftui-navigationbar-is-not-really-hidden-as-you-expect-785ff0425c86",
        "snippet": "",
        "read": true
      
    ,
    
      "slug": "hey-facebook-i-made-a-metaverse-27-years-ago",
      "title": "Hey, Facebook, I Made a Metaverse 27 Years Ago",
      "content": null,
      "metadata": 
        "published": "28 Nov 2021 at 21:39",
        "url": "https://www.theatlantic.com/technology/archive/2021/10/facebook-metaverse-was-always-terrible/620546/",
        "snippet": "Michel Baret / Gamma-Rapho / Getty In a booth at Ted’s Fish Fry, in Troy, New York, my friend Daniel Beck and I sketched out our plans for the metaverse. ",
        "read": true
      
    ,
    
      "slug": "when-big-tech-buys-small-tech-benedict-evans",
      "title": "When big tech buys small tech — Benedict Evans",
      "content": null,
      "metadata": 
        "published": "28 Nov 2021 at 21:39",
        "url": "https://www.ben-evans.com/benedictevans/2021/11/12/when-big-tech-buys-small-tech",
        "snippet": "Acquisitions are a big part of the discussion around competition in tech today, and a big set of questions. It’s easy to say that we wouldn’t let Amazon buy Zappos or Google buy DoubleClick again, but everyone’s favourite puzzle is Instagram. ",
        "read": false
      
    
  ],
  "total": 171,
  "limit": 3

【问题讨论】:

这里期望的行为是什么?循环遍历每个项目并将其包含在VStack?你试过ForEach吗? 嘿!没错,我想遍历数组以引用(例如)Text(item.objects.title),而不必指定我要查找的数组中的哪个项目。可悲的是,使用ForEach 不起作用,因为List(viewModel.items, id: \.self) item in 本质上是在复制ForEach 循环。所以我认为这与我的模型有关,但我不确定! 没有什么可以阻止您在 List 中使用 ForEach。我只是不清楚所需的输出是什么——不知何故,你将不得不处理输出中的嵌套数组。 哦,当然,我想我的挑战是我无法理解如何在ForEach 循环中进一步分解问题来解决这个问题。我猜你的意思是我可以使用ForEach 来迭代List 的数组以深入一层? 知道了!耶,终于。感谢 jnpdx 的推送。 【参考方案1】:

好的,解决了,感谢 jnpdx 的一点帮助。需要通过ForEach 循环进一步钻取该数组,如下所示:

List(viewModel.items, id: \.self)  item in
 ForEach(item.objects, id: \.self)  bookmark in
   VStack(alignment: .leading) 
    Text(bookmark.title)
   
 

【讨论】:

以上是关于SwiftUI List 需要精确的位置来渲染结果,所以如果没有 [0] 等就不会渲染结果的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI视图旋转腾挪那些事儿

SwiftUI - 如何获取新创建的按钮的确切中心坐标/位置

swiftui 请求 渲染数据

如何在 SwiftUI 中将 Firebase 结果转换为 List

SwiftUI 列表(List)中字符串末尾带数字导致排序不正确的解决

swiftui删除核心数据行