ForEach를 사용하여 사전을 통해 반복되는 Swift UI
다음을 반복할 수 있는 방법이 있습니까?Dictionary
순식간에ForEach
루프? Xcode는 말합니다.
일반 구조 'ForEach'를 사용하려면 '[String:Int]'가 'RandomAccessCollection'을(를) 따라야 합니다.
그래서 스위프트 사전이 다음을 준수하도록 만드는 방법이 있습니까?RandomAccessCollection
아니면 사전이 순서가 없기 때문에 가능하지 않습니까?
제가 시도한 한 가지는 사전의 키를 반복하는 것입니다.
let dict: [String: Int] = ["test1": 1, "test2": 2, "test3": 3]
...
ForEach(dict.keys) {...}
그렇지만keys
의 배열이 아닙니다.String
s, 유형은Dictionary<String, Int>.Keys
(언제 변경되었는지 확실하지 않음).제가 사전을 가져와서 키 배열을 반환하는 도우미 기능을 작성할 수 있다는 것을 알고 있습니다. 그리고 나서 그 배열을 반복할 수 있습니다. 하지만 그것을 하는 기본적인 방법이 없을까요, 아니면 더 우아한 방법이 있을까요?연장할 수 있습니까?Dictionary
그리고 그것을 준수하게 하라.RandomAccessCollection
아니면 뭔가?
사전을 정렬하여 (키, 값) 쌍의 튜플 배열을 얻은 다음 사용할 수 있습니다.
struct ContentView: View {
let dict = ["key1": "value1", "key2": "value2"]
var body: some View {
List {
ForEach(dict.sorted(by: >), id: \.key) { key, value in
Section(header: Text(key)) {
Text(value)
}
}
}
}
}
또는 사전 키를 루프합니다.
struct ContentView: View {
let dict = ["key1": "value1", "key2": "value2"]
var body: some View {
List {
ForEach(Array(dict.keys), id: \.self) { key in
Section(header: Text(key)) {
Text(dict[key] ?? "")
}
}
}
}
}
순서가 없기 때문에, 그것을 배열로 넣는 것 밖에 방법이 없습니다. 꽤 간단합니다.하지만 배열 순서는 다를 것입니다.
struct Test : View {
let dict: [String: Int] = ["test1": 1, "test2": 2, "test3": 3]
var body: some View {
let keys = dict.map{$0.key}
let values = dict.map {$0.value}
return List {
ForEach(keys.indices) {index in
HStack {
Text(keys[index])
Text("\(values[index])")
}
}
}
}
}
#if DEBUG
struct Test_Previews : PreviewProvider {
static var previews: some View {
Test()
}
}
#endif
정렬된 사전
WWDC21에서 Apple은 다음을 포함하는 패키지를 발표했습니다.OrderedDictionary
(그 중에서도)
이제, 우리는 다음과 같이 교체하면 됩니다.
let dict: [String: Int] = ["test1": 1, "test2": 2, "test3": 3]
포함:
let dict: OrderedDictionary = ["test1": 1, "test2": 2, "test3": 3]
또는 다음 중 하나를 다른 하나에서 시작할 수 있습니다.
let dict: [String: Int] = ["test1": 1, "test2": 2, "test3": 3]
let orderedDict = OrderedDictionary(uniqueKeys: dict.keys, values: dict.values)
참고만 해주세요.dict
순서가 없습니다. 정렬할 수 있습니다.orderedDict
일관된 명령을 실행합니다.
Swift에서 사용할 수 있는 예는 다음과 같습니다.UI 보기:
import Collections
import SwiftUI
struct ContentView: View {
let dict: OrderedDictionary = ["test1": 1, "test2": 2, "test3": 3]
var body: some View {
VStack {
ForEach(dict.keys, id: \.self) {
Text("\($0)")
}
}
}
}
참고: 현재Collections
별도의 패키지로 사용할 수 있으므로 프로젝트로 가져와야 합니다.
자세한 내용은 여기에서 확인할 수 있습니다.
- WWDC 세션 - Swift Algorithms and Collections 패키지 만나기
- swift.org 발표 - Swift Collections 소개
간단한 대답: 아니오.
당신이 정확히 지적했듯이, 사전은 순서가 없습니다.ForEach는 컬렉션의 변경 사항을 확인합니다.이러한 변경사항에는 삽입, 삭제, 이동 및 업데이트가 포함됩니다.이러한 변경 사항이 발생하면 업데이트가 트리거됩니다.참조: https://developer.apple.com/videos/play/wwdc2019/204/ 46:10:
A For Each 컬렉션의 변경 사항을 자동으로 확인합니다.
저는 당신이 그 강연을 보는 것을 추천합니다 :)
다음과 같은 이유로 ForEach를 사용할 수 없습니다.
- 그것은 수집품을 보고 움직임을 감시합니다.정리되지 않은 사전으로는 불가능합니다.
- 할 때(예 뷰예재때할용사를예()
UITableView
될 수 때 합니다.List
의 지원을 받습니다.UITableViewCells
그리고 내 생각엔ForEach
동일한 작업을 수행하고 있음), 표시할 셀을 계산해야 합니다.데이터 원본에서 인덱스 경로를 쿼리하여 이 작업을 수행합니다.논리적으로 말하자면, 데이터 소스가 순서가 없으면 인덱스 경로가 쓸모가 없습니다.
Xcode: 11.4.1~
...
var testDict: [String: Double] = ["USD:": 10.0, "EUR:": 10.0, "ILS:": 10.0]
...
ForEach(testDict.keys.sorted(), id: \.self) { key in
HStack {
Text(key)
Text("\(testDict[key] ?? 1.0)")
}
}
...
자세한 내용:
final class ViewModel: ObservableObject {
@Published
var abstractCurrencyCount: Double = 10
@Published
var abstractCurrencytIndex: [String: Double] = ["USD:": 10.0, "EUR:": 15.0, "ILS:": 5.0]
}
struct SomeView: View {
@ObservedObject var vm = ViewModel()
var body: some View {
NavigationView {
List {
ForEach(vm.abstractCurrencytIndex.keys.sorted(), id: \.self) { key in
HStack {
Text(String(format: "%.2f", self.vm.abstractCurrencyCount))
Text("Abstract currency in \(key)")
Spacer()
Text(NumberFormatter.localizedString(from: NSNumber(value: self.vm.abstractCurrencytIndex[key] ?? 0.0), number: .currency))
}
}
}
}
}
}
swift-collection의 Ordered Dictionary(주문된 컬렉션의 일부)를 사용하는 경우 다음 작업을 수행할 수 있습니다.
var states: OrderedDictionary<Player, String>
ForEach(states.elements, id:\.key) { player, state in
PlayerRow(player: player, state: state)
}
이 작업에 사용할 키 개체가 식별되는지 확인하고, 그렇지 않으면 ForEach(각각)에서 id 매개 변수를 조정합니다.
이 게시물에 대한 일부 답변에서 코드를 사용하여 발생한 구문 오류는 제가 제 문제에 대한 해결책을 찾는 데 도움이 되었습니다.
다음이 포함된 사전 사용:
key
꾸짖음CoreDataEntity
;value
해당 수 관(유)에서의엔인수스턴스티터해NSSet
).
저는 @J의 답을 강조합니다.순서가 지정되지 않은/무작위 수집에 대한 실험계획법 및 주석Dictionary
셀 테보셀과기 (AppKit))과 에 가장 수 .NSTableView
유이킷UITableView
스위프트 UIList
행)을 선택합니다.
이후에는 어레이로 작업할 수 있도록 코드를 재구성할 예정입니다.
하지만 만약 당신이 일을 해야 한다면,Dictionary
다음은 제 작업 솔루션입니다.
struct MyView: View {
var body: some View {
// ...code to prepare data for dictionary...
var dictionary: [CoreDataEntity : Int] = [:]
// ...code to create dictionary...
let dictionarySorted = dictionary.sorted(by: { $0.key.name < $1.key.name })
// where .name is the attribute of the CoreDataEntity to sort by
VStack { // or other suitable view builder/s
ForEach(dictionarySorted, id: \.key) { (key, value) in
Text("\(value) \(key.nameSafelyUnwrapped)")
}
}
}
}
extension CoreDataEntity {
var nameSafelyUnwrapped: String {
guard let name = self.name else {
return String() // or another default of your choosing
}
return name
}
}
가장 깨끗한 방법은 (이것만을 위해 패키지 종속성을 설정하지 않으려면) 대신 Tuples를 대신 사용하는 것이라고 생각합니다.
let myTuple: [(key: String, value: Int)] = [("test1": 1), ("test2": 2), ("test3": 3)]
...
ForEach(myTuple, id:\.0) {...}
저는 열거형/Int 쌍 사전을 통해서도 이 문제를 해결하려고 했습니다.Andre가 제안한 대로 효과적으로 배열로 변환하고 있지만, 지도를 사용하는 대신 키를 주조합니다.
enum Fruits : Int, CaseIterable {
case Apple = 0
case Banana = 1
case Strawberry = 2
case Blueberry = 3
}
struct ForEachTest: View {
var FruitBasket : [Fruits: Int] = [Fruits.Apple: 5, Fruits.Banana : 8, Fruits.Blueberry : 20]
var body: some View {
VStack {
ForEach([Fruits](FruitBasket.keys), id:\Fruits.hashValue) { f in
Text(String(describing: f) + ": \(self.FruitBasket[f]!)")
}
}
}
}
struct ForEachTest_Previews: PreviewProvider {
static var previews: some View {
ForEachTest()
}
}
구현 방법은 다음과 같습니다.
struct CartView: View {
var cart:[String: Int]
var body: some View {
List {
ForEach(cart.keys.sorted()) { key in
Text(key)
Text("\(cart[key]!)")
}
}
}
}
첫 번째 텍스트 보기는 문자열인 키를 출력합니다.두 번째 텍스트 보기는 해당 키의 Int 값을 출력합니다.다음에 나오는 !는 이 Int가 포함된 Optional(옵션)의 포장을 해제하는 것입니다.프로덕션에서는 이 옵션을 보다 안전하게 포장을 풀 수 있도록 검사를 수행하지만 이는 개념 증명입니다.
아니요, 사용할 수 없습니다.ForEach
View
와 함께Dictionary
시도할 수 있지만 특히 사용하는 경우 충돌할 가능성이 높습니다.id: .\self
열거되거나 해킹을 나타냅니다.설명서에 나와 있는 것처럼 다음을 사용합니다.ForEach
View
정확하게는 식별 가능한 사용자 지정 구조를 만들고 다음과 같은 구조를 포함하는 배열을 사용하여 생성할 수 있는 "식별된 데이터 모음"이 필요합니다.
private struct NamedFont: Identifiable {
let name: String
let font: Font
var id: String { name } // or let id = UUID()
}
private let namedFonts: [NamedFont] = [
NamedFont(name: "Large Title", font: .largeTitle),
NamedFont(name: "Title", font: .title),
NamedFont(name: "Headline", font: .headline),
NamedFont(name: "Body", font: .body),
NamedFont(name: "Caption", font: .caption)
]
var body: some View {
ForEach(namedFonts) { namedFont in
Text(namedFont.name)
.font(namedFont.font)
}
}
언급URL : https://stackoverflow.com/questions/56675532/swiftui-iterating-through-dictionary-with-foreach
'programing' 카테고리의 다른 글
C# 6.0을 사용하기 위한 레이저 뷰 엔진 제조 방법 (0) | 2023.08.07 |
---|---|
MYSQL의 모든 테이블에서 데이터 삭제 (0) | 2023.08.07 |
Google 스크립트를 사용하여 mariadb에 연결, 오류:연결 URL에서 지원되지 않는 JDBC 프로토콜을 사용합니다. (0) | 2023.08.07 |
JavaScript/jQuery로 페이지 맨 위로 스크롤하는 방법은 무엇입니까? (0) | 2023.08.07 |
파단(루프/스위치)에 대응하는 내부 구조물의 외부 루프를 파단하는 방법 (0) | 2023.08.07 |