Apple 建议的 .indexed() 属性如何在 ForEach 中工作? [英] How does the Apple-suggested .indexed() property work in a ForEach?

查看:24
本文介绍了Apple 建议的 .indexed() 属性如何在 ForEach 中工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Apple 在 iOS 13 的发行说明中说:

In the release notes to iOS 13 Apple said:

绑定结构对集合协议的条件一致性被删除.(51624798).然后建议以这种方式遍历数组:

The Binding structure’s conditional conformance to the Collection protocol is removed. (51624798). And then suggested iterating through arrays this way:

var body: some View {
        List(landmarks.indexed(), id: \.1.id) { (index, landmark) in
            Toggle(landmark.name, isOn: self.$landmarks[index].isFavorite)
        }
    }

但您还需要实现这一点:

But you also need to implement this:

struct IndexedCollection<Base: RandomAccessCollection>: RandomAccessCollection {
    typealias Index = Base.Index
    typealias Element = (index: Index, element: Base.Element)

    let base: Base

    var startIndex: Index { base.startIndex }

    var endIndex: Index { base.startIndex } // Possibly this should be endIndex?

    func index(after i: Index) -> Index {
        base.index(after: i)
    }

    func index(before i: Index) -> Index {
        base.index(before: i)
    }

    func index(_ i: Index, offsetBy distance: Int) -> Index {
        base.index(i, offsetBy: distance)
    }

    subscript(position: Index) -> Element {
        (index: position, element: base[position])
    }
}

extension RandomAccessCollection {
    func indexed() -> IndexedCollection<Self> {
        IndexedCollection(base: self)
    }
}

首先,第 6 行似乎有一个错字:可能需要将其更改为 base.endIndex,但 无论如何都行不通.这是一种耻辱,因为它看起来是一种同时使用元素和索引进行迭代的巧妙方法.那么,我在实施它的方式上是否犯了错误?

So first of all there appears to be a typo on line 6: that might need to be changed to base.endIndex but it doesn't work either way. It's a shame because it looks like a neat way to iterate with both element and index. So, is there a mistake I am making in how I'm implementing it?

代码:

import SwiftUI


let screenWidth = UIScreen.main.bounds.size.width
let screenHeight = UIScreen.main.bounds.size.height


struct SingleBall: Identifiable {
    var id = UUID()
    var position = CGPoint.zero
    var isDeleting = false
}

class BallStorage: ObservableObject {
    
    @Published var balls: [SingleBall] = [
        
        SingleBall(position: CGPoint(x: 110, y: 220)),
        SingleBall(position: CGPoint(x: 150, y: 120)),
        SingleBall(position: CGPoint(x: 200, y:160)),
        SingleBall(position: CGPoint(x: 200, y: 200))
        
    ]
    
}


struct StartScreen: View {
    
    
    @ObservedObject var ballStorage = BallStorage()
    @State var isDeleting = false
    
    var body: some View {
        
        
        
            
            ZStack {  // stack of balls
                
            
                ForEach(ballStorage.balls.indexed(), id: \.1.id) {
                
              (number, item) in
            
                    littleBall(
                        ballStorage: ballStorage,
                        numberInArray: number )
                
                }
                
            }
            .frame(width:screenWidth, height:screenHeight) //end stack balls
        

            
        
    }
    
}

Littleball 是一个只显示一个黑色圆圈的东西.因此,当我通过迭代索引来做同样的事情时,四个圆圈会得到很好的呈现(但正在寻找替代方法,因为您无法从带有索引的数组中删除内容).
使用上面的代码,什么都不会渲染.为什么?

Littleball is a thing that just displays a black circle. So when I am doing the same thing by iterating over indices, four circles get rendered nicely (but looking for alternative way because you can't delete things from the array with indices).
With the above code nothing gets rendered. Why?

澄清一下,.indexed() 实现显然也在发布代码的范围内.

To clarify, the .indexed() implementation is obviously also in the scope of the posted code.

推荐答案

这个版本的 .indexed() 确实有效:

This version of .indexed() does work:

struct IndexedCollection<Base: RandomAccessCollection>: RandomAccessCollection {
    typealias Index = Base.Index
    typealias Element = (index: Index, element: Base.Element)
    let base: Base
    var startIndex: Index { self.base.startIndex }
    var endIndex: Index { self.base.endIndex }

    func index(after i: Index) -> Index {
        self.base.index(after: i)
    }

    func index(before i: Index) -> Index {
        self.base.index(before: i)
    }

    func index(_ i: Index, offsetBy distance: Int) -> Index {
        self.base.index(i, offsetBy: distance)
    }

    subscript(position: Index) -> Element {
        (index: position, element: self.base[position])
    }
}

extension RandomAccessCollection {
    func indexed() -> IndexedCollection<Self> {
        IndexedCollection(base: self)
    }
}

  • 完整示例和更多信息
  • 这篇关于Apple 建议的 .indexed() 属性如何在 ForEach 中工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆