admin管理员组

文章数量:1122846

In SwiftUI, I want to use onChange(of:, action:) function for scenePhase, but the build fails.

struct MyView: View {
    @Environment(\.scenePhase) var scenePhase
    @State private var timerStatus: TimerStatus

    var body: some View {
        VStack {
            Text(...)
            Button(...)
        }
        .onChange(of: scenePhase) { oldState, newState in // Error on this line
            if newState == .active {
                // some code
            } else if oldState == .active {
                // some code
            }
        }
        .onChange(of: timerStatus) { oldState, newState in
            // some code
        }
    }
}

enum TimerStatus {
    case paused
    case runningActive
    case runningInactive
}

I get the following error:

"Contextual closure type '(ScenePhase) -> Void' expects 1 argument, but 2 were used in closure body"

Do you have any idea why I get this error, and how to fix it?

I'm developing the program for iOS 18.2 in Xcode.

When I used "Jump to Definition" function for the onChange() function, the older version of onChange was shown:

@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)
extension View {
    @inlinable nonisolated public func onChange<V>(of value: V, perform action: @escaping (_ newValue: V) -> Void) -> some View where V : Equatable
}

onChange(of: timerStatus) works without the error and "Jump to Definition" shows the newer definition:

@available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *)
extension View {
    nonisolated public func onChange<V>(of value: V, initial: Bool = false, _ action: @escaping (_ oldValue: V, _ newValue: V) -> Void) -> some View where V : Equatable
}

In SwiftUI, I want to use onChange(of:, action:) function for scenePhase, but the build fails.

struct MyView: View {
    @Environment(\.scenePhase) var scenePhase
    @State private var timerStatus: TimerStatus

    var body: some View {
        VStack {
            Text(...)
            Button(...)
        }
        .onChange(of: scenePhase) { oldState, newState in // Error on this line
            if newState == .active {
                // some code
            } else if oldState == .active {
                // some code
            }
        }
        .onChange(of: timerStatus) { oldState, newState in
            // some code
        }
    }
}

enum TimerStatus {
    case paused
    case runningActive
    case runningInactive
}

I get the following error:

"Contextual closure type '(ScenePhase) -> Void' expects 1 argument, but 2 were used in closure body"

Do you have any idea why I get this error, and how to fix it?

I'm developing the program for iOS 18.2 in Xcode.

When I used "Jump to Definition" function for the onChange() function, the older version of onChange was shown:

@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)
extension View {
    @inlinable nonisolated public func onChange<V>(of value: V, perform action: @escaping (_ newValue: V) -> Void) -> some View where V : Equatable
}

onChange(of: timerStatus) works without the error and "Jump to Definition" shows the newer definition:

@available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *)
extension View {
    nonisolated public func onChange<V>(of value: V, initial: Bool = false, _ action: @escaping (_ oldValue: V, _ newValue: V) -> Void) -> some View where V : Equatable
}
Share Improve this question asked yesterday Kbb BioKbb Bio 11 bronze badge New contributor Kbb Bio is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct. 2
  • 1 Could not replicate your issue, all works well for me. On MacOS 15.3, Xcode 16.2, target iOS-18.2, tested on real iOS device and MacCatalyst. What Xcode are you using? Note you should use @State private var timerStatus: TimerStatus = .paused, that is give it an initial value. – workingdog support Ukraine Commented yesterday
  • Note that the error might be misleading and that the real issue is somewhere else. What happens if you comment out the whole onChange, what happens if you comment out what’s inside the closure for onChange? Do you get a different error, does it disappear? – Joakim Danielson Commented yesterday
Add a comment  | 

1 Answer 1

Reset to default 0

The scenePhase environment value in SwiftUI reflects only the current lifecycle state of the app. It does not provide the oldValue in the onChange(of:) method.

Store the previous value in a separate variable:

@Environment(\.scenePhase) var scenePhase
@State private var previousScenePhase: ScenePhase?

var body: some View {
    VStack {
        Text("...")
        Button("...")
    }
    .onChange(of: scenePhase) { newState in
        if let oldState = previousScenePhase {
            if newState == .active {
                // Handle activation
            } else if oldState == .active {
                // Handle deactivation
            }
        }
        previousScenePhase = newState
    }
}

本文标签: swiftSwiftUI View method OnChange(of scenePhase) does not accept 2argument actionStack Overflow