SwiftUI - PresentationButton с модальным полноэкранным режимом

Что вызывает ArrayIndexOutOfBoundsException?

Если вы думаете о переменной как о «поле», где вы можете поместить значение, то массив представляет собой ряд ящиков, расположенных рядом с eachother, где число Ячейки представляют собой конечное и явное целое число.

Создание такого массива:

final int[] myArray = new int[5]

создает строку из 5 полей, каждая из которых имеет int. Каждый из ящиков имеет индекс, позицию в ряду ящиков. Этот индекс начинается с 0 и заканчивается на N-1, где N - размер массива (количество ящиков).

Чтобы получить одно из значений из этой серии ящиков, вы можете обратиться к нему через его индекс, например:

myArray[3]

Который даст вам значение 4-го ящика в серии (так как в первом поле есть индекс 0).

ArrayIndexOutOfBoundsException вызвано попыткой извлечь «ящик», который не существует, передав индекс, который выше индекса последнего «поля» или отрицательный.

В моем примере работы эти фрагменты кода приведут к такому исключению:

myArray[5] //tries to retrieve the 6th "box" when there is only 5
myArray[-1] //just makes no sense
myArray[1337] //waay to high

Как избежать ArrayIndexOutOfBoundsException

Чтобы предотвратить ArrayIndexOutOfBoundsException, необходимо рассмотреть некоторые ключевые моменты:

Looping

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

for (int i = 0; i < myArray.length; i++) {

Обратите внимание на <, никогда не смешивайте там =.

Возможно, вам захочется сделать что-то вроде этого:

for (int i = 1; i <= myArray.length; i++) {
    final int someint = myArray[i - 1]

Просто нет. Придерживайтесь одного выше (если вам нужно использовать индекс), и это сэкономит вам много боли.

По возможности используйте foreach:

for (int value : myArray) {

Таким образом, вы вообще не придется вообще обдумывать индексы.

Когда вы выполняете цикл, что бы вы ни делали, НИКОГДА не изменяйте значение итератора цикла (здесь: i). Единственное место, которое должно изменить значение, это сохранить цикл. Изменение в противном случае просто рискует исключением и в большинстве случаев не является обязательным.

Retrieval / update

При извлечении произвольного элемента массива всегда проверяйте его действительность индекс по длине массива:

public Integer getArrayElement(final int index) {
    if (index < 0 || index >= myArray.length) {
        return null; //although I would much prefer an actual exception being thrown when this happens.
    }
    return myArray[index];
}
14
задан Alexandre Lordelo 25 June 2019 в 14:34
поделиться

2 ответа

Эта версия фиксирует ошибку компиляции, существующую в XCode 11.1, а также гарантирует, что контроллер представлен в стиле, который передается в.

import SwiftUI

struct ViewControllerHolder {
    weak var value: UIViewController?
}

struct ViewControllerKey: EnvironmentKey {
    static var defaultValue: ViewControllerHolder {
        return ViewControllerHolder(value: UIApplication.shared.windows.first?.rootViewController)

    }
}

extension EnvironmentValues {
    var viewController: UIViewController? {
        get { return self[ViewControllerKey.self].value }
        set { self[ViewControllerKey.self].value = newValue }
    }
}

extension UIViewController {
    func present<Content: View>(style: UIModalPresentationStyle = .automatic, @ViewBuilder builder: () -> Content) {
        let toPresent = UIHostingController(rootView: AnyView(EmptyView()))
        toPresent.modalPresentationStyle = style
        toPresent.rootView = AnyView(
            builder()
                .environment(\.viewController, toPresent)
        )
        self.present(toPresent, animated: true, completion: nil)
    }
}

Для использования этой версии код неизменен от предыдущей версии.

struct MyView: View {

    @Environment(\.viewController) private var viewControllerHolder: UIViewController?
    private var viewController: UIViewController? {
        self.viewControllerHolder.value
    }

    var body: some View {
        Button(action: {
           self.viewController?.present(style: .fullScreen) {
              MyView()
           }
        }) {
           Text("Present me!")
        }
    }
}
0
ответ дан Gene Z. Ragan 23 October 2019 в 11:51
поделиться

Таким образом, я боролся с этим, и мне не нравилась функция наложения, ни ViewController обернул версию, так как он дал мне некоторую ошибку памяти, и я очень плохо знаком с iOS и только знаю SwiftUI и никакой UIKit.

я разработал кредиты следующее только с SwiftUI, который является, вероятно, что делает наложение, но в моих целях это намного более гибко:

struct FullscreenModalView<Presenting, Content>: View where Presenting: View, Content: View {

    var isShowing: Binding<Bool>
    let parent: () -> Presenting
    let content: () -> Content

    @inlinable public init(isShowing: Binding<Bool>, parent: @escaping () -> Presenting, @ViewBuilder content: @escaping () -> Content) {
        self.isShowing = isShowing
        self.parent = parent
        self.content = content
    }

    var body: some View {
        GeometryReader { geometry in
            ZStack {
                self.parent()
                ZStack {
                    self.content()
                    VStack {
                        HStack {
                            Spacer()
                            Button(action: {
                                withAnimation {
                                    self.isShowing.wrappedValue.toggle()
                                }
                            }, label: {
                                Text("done_button").frame(width: 200, height: 120)
                            })
                            .frame(width: 200, height: 120)
                        }
                        Spacer()
                    }
                }
                .frame(width: geometry.size.width, height: geometry.size.height)
                .animation(Animation.easeInOut(duration: 0.3))
                .background(Color.primary.colorInvert())
                .offset(x: 0, y: self.isShowing.wrappedValue ? 0 : geometry.size.height + geometry.safeAreaInsets.top)
            }
        }
    }
}

Добавление расширения View:

extension View {

    func modal<Content>(isShowing: Binding<Bool>, @ViewBuilder content: @escaping () -> Content) -> some View where Content: View {
        FullscreenModalView(isShowing: isShowing, parent: { self }, content: content)
    }

}

Использование:

struct ContentView : View {
    @State private var showModal: Bool = false
    var body: some View {
        ZStack {
            Button(action: {
                withAnimation {
                    self.showModal.toggle()
                }
            }, label: {
                HStack{
                   Image(systemName: "eye.fill")
                    Text("Calibrate")
                }
               .frame(width: 220, height: 120)
            })
        }
        .modal(isShowing: self.$showModal, content: {
            Text("Hallo")
        })
    }
}

я надеюсь, что это помогает!

поздравления krjw

1
ответ дан 30 November 2019 в 13:40
поделиться