Skip to content

Dismiss and present on presenting UIViewController #3570

@v-slobodianiuk

Description

@v-slobodianiuk

Description

Hello!
I get incorrect behavior when leaving the screen and opening a new one in a modal window. Sometimes everything works correctly, but other times all my windows just close. I wrote a Unit test and a UI test. The UI test sometimes fails.

Here is a link to the repository with an Example project

Steps:

  1. Present AViewController on RootViewController
  2. Present BViewController on AViewController
  3. Dismiss BViewController and present CViewController on AViewController

Image

Error:
Image

Checklist

  • I have determined whether this bug is also reproducible in a vanilla SwiftUI project.
  • If possible, I've reproduced the issue using the main branch of this package.
  • This issue hasn't been addressed in an existing GitHub issue or discussion.

Expected behavior

Present CViewController

Actual behavior

Dissmis AViewController

Reproducing project

import ComposableArchitecture
import UIKit

@Reducer
struct AFeature {
    @ObservableState
    struct State: Equatable {
        @Presents var destination: Destination.State?
    }

    @Reducer
    enum Destination {
        case bFeature(BFeature)
        case cFeature(CFeature)
    }

    enum Action {
        case showB
        case showC
        case destination(PresentationAction<Destination.Action>)
    }

    var body: some Reducer<State, Action> {
        Reduce { state, action in
            switch action {
            case .showB:
                state.destination = .bFeature(.init())
                return .none

            case .showC:
                state.destination = .cFeature(.init())
                return .none
                
            case .destination(.presented(.bFeature(.delegate(.closeAndShowC)))):
                return .send(.showC)

            default:
                return .none
            }
        }
        .ifLet(\.$destination, action: \.destination)
    }
        
}

extension AFeature.Destination.State: Equatable {}

final class AViewController: UIViewController {
    lazy var button = UIButton(type: .system, primaryAction: .init(handler: { [weak self] _ in
        self?.store.send(.showB)
    }))

    @UIBindable private var store: StoreOf<AFeature>
    
    init(store: StoreOf<AFeature>) {
        self.store = store
        super.init(nibName: nil, bundle: nil)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    deinit {
        logger.info("✅ Deinit: \(String(describing: Self.self))")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .systemBackground
        button.configureTintedButton(withTitle: "Show B")
        button.center = view.center
        view.addSubview(button)
        
        present(item: $store.scope(state: \.destination?.bFeature, action: \.destination.bFeature)) { store in
            BViewController(store: store)
        }
        
        present(item: $store.scope(state: \.destination?.cFeature, action: \.destination.cFeature)) { store in
            CViewController(store: store)
        }
    }
}

Image

Example project

The Composable Architecture version information

1.17.1

Destination operating system

iOS 18

Xcode version information

Xcode 16.2

Swift Compiler version information

swift-driver version: 1.115.1 Apple Swift version 6.0.3 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)
Target: arm64-apple-macosx15.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working due to a bug in the library.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions