Постоянные ошибки при попытке заставить Views работать с многомерным массивом.

Вопрос или проблема

Я попробовал несколько различных способов создать сетку значков, теперь, когда я делаю это, вместо вызова многоразовых компонентов у меня есть многомерный массив Views.

Вот код, и я постараюсь объяснить ошибки, которые меня окружали и сделали невозможным решить эту проблему:

    static let itemMatrix: [[any View]] = [
        [ChargeBeam(), VariaSuit(), MorphBall(), HiJumpBoots(), Missiles()],
        [IceBeam(), GravitySuit(), MorphBallBomb(), SpaceJump(), SuperMissiles()],
        [WaveBeam(), EmptyCell(), SpringBall(), SpeedBooster(), PowerBombs()],
        [Spazer(), GrappleBeam(), ScrewAttack(), EmptyCell(), EnergyTanks()],
        [PlasmaBeam(), XRayScope(), EmptyCell(), EmptyCell(), ReserveTanks()]
    ]

Вы можете заметить скобки () после каждого представления. Потому что я подумал, что если я поставлю скобки здесь, разве я не должен ставить их, когда действительно запускаю представление в ContentView? Но если я не ставлю скобки здесь… появляется эта ошибка:

Тип выражения неясен без аннотации типа

И она исправляется только тогда, когда я ставлю скобки после каждого View. Теперь вы видите “any View” в объявлении вместо View… это потому, что когда это View, у меня появляется эта ошибка:

Использование протокола 'View' в качестве типа должно быть записано как 'any View'

Так что, когда я это делаю, тогда в ContentView.swift происходит следующее:

Тип 'any View' не может соответствовать 'View'

ContentView.swift:

private var itemGrid: some View {
    return VStack(spacing: 4) {
        ForEach(0..<5) { row in
            HStack(spacing: 12) {
                ForEach(0..<5) { col in
                    AppConstants.itemMatrix[row][col]
                }
            }
        }
    }
    .padding(0)
}

У меня нет понятия, почему каждый раз, когда я делаю шаг, чтобы что-то исправить или сделать то, что говорит компилятор, в итоге появляется новая ошибка из-за моего исправления.

Ответ или решение

Вопрос с ошибками, возникающими при работе с многомерным массивом Views в Swift, может быть довольно запутанным. Давайте рассмотрим вашу проблему подробнее и предложим решение, чтобы вы могли успешно отобразить сетку иконок.

Понимание проблемы

Вы работаете с многомерным массивом, который представляет собой сетку компонентов пользовательского интерфейса в Swift, и сталкиваетесь с ошибками, связанными с использованием протокола View. Основные проблемы, которые вы описали, связаны с использованием any View и вызовом компонент просмотра с использованием скобок.

Ошибки и их причины

  1. Ошибка с "Type of expression is ambiguous without a type annotation":
    Это происходит, когда компилятор не может вывести тип, поэтому он требует явного указания типа. Добавление скобок после вашего View (например, ChargeBeam()) позволяет Swift понять, что вы имеете в виду конкретные экземпляры этих View.

  2. Ошибка с "Use of protocol ‘View’ as a type must be written ‘any View’":
    В Swift, начиная с версии 5.7, протоколы необходимо использовать с предшествующим словом any, если имеется вероятность, что они будут ссылаться на различные типы. Это также объясняет необходимость использования any View вместо View.

  3. Ошибка с "Type ‘any View’ cannot conform to ‘View’" в ContentView.swift:
    Эта ошибка возникает, поскольку компилятору не известен точный тип any View. Компилятор не может обрабатывать any View в контексте ForEach, который ожидает конкретные типы.

Решение проблемы

Рассмотрим правильный способ работы с многомерными массивами Views и использования их в SwiftUI:

  1. Создайте массив с конкретными типами Views:
    Вместо использования any View, вы можете попробовать использовать конкретные типы. В вашем случае можно попробовать создать массив, который содержит определенные типы Views.

  2. Используйте Identifiable или модели данных:
    Вместо прямой работы с any View, вы можете создать структуру данных, которая будет представлять каждую ячейку вашей сетки и будет реализовывать протокол Identifiable. Это упростит работу с ForEach.

Пример реализации

Вот обновленная версия вашего кода:

import SwiftUI

struct AppConstants {
    static let itemMatrix: [[AnyView]] = [
        [AnyView(ChargeBeam()), AnyView(VariaSuit()), AnyView(MorphBall()), AnyView(HiJumpBoots()), AnyView(Missiles())],
        [AnyView(IceBeam()), AnyView(GravitySuit()), AnyView(MorphBallBomb()), AnyView(SpaceJump()), AnyView(SuperMissiles())],
        [AnyView(WaveBeam()), AnyView(EmptyCell()), AnyView(SpringBall()), AnyView(SpeedBooster()), AnyView(PowerBombs())],
        [AnyView(Spazer()), AnyView(GrappleBeam()), AnyView(ScrewAttack()), AnyView(EmptyCell()), AnyView(EnergyTanks())],
        [AnyView(PlasmaBeam()), AnyView(XRayScope()), AnyView(EmptyCell()), AnyView(EmptyCell()), AnyView(ReserveTanks())]
    ]
}

struct ContentView: View {
    private var itemGrid: some View {
        return VStack(spacing: 4) {
            ForEach(0..<5, id: \.self) { row in
                HStack(spacing: 12) {
                    ForEach(0..<5, id: \.self) { col in
                        AppConstants.itemMatrix[row][col]
                    }
                }
            }
        }
        .padding(0)
    }

    var body: some View {
        itemGrid
    }
}

Объяснение изменений

  1. AnyView: Я обернул каждый ваш View в AnyView, чтобы устранить проблему с неоднородностью типов.
  2. Идентификатор для ForEach: Я добавил id: \.self в ваш ForEach, чтобы компилятор понимал, как один идентификатор может применяться для массивов индексов.

Эти изменения должны помочь вам избавиться от текущих ошибок. Не забывайте многократно тестировать свой код, так как SwiftUI может порой вызывать неожиданные проблемы, особенно при работе с динамически изменяемыми данными.

Заключение

Работа с многомерными массивами Views в Swift может быть сложной, особенно при использовании функций, ожидающих определенные типы. Использование AnyView может решить вашу проблему в данном контексте. Если у вас возникнут дополнительные вопросы или проблемы, не стесняйтесь задавать!

Оцените материал
Добавить комментарий

Капча загружается...