Error: Missing Return in a Closure Expected to Return 'Uiviewcontroller' (Xcode, Swift, iOS 13)

Error: Missing return in a closure expected to return 'UIViewController' (Xcode, Swift, iOS 13)

you just need to return ViewController inside closure

Var window: UIWindow?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()

let Myvc = UIViewController()

let hasSession = UserDefaults.standard.value(forKey: "UserHasSubmittedPassword") as? Bool
let vc: UIViewController = {
if let hasSession = hasSession, hasSession == true {
// next vc you want to show
return Myvc
} else {
// enter password vc
return Myvc
}
**}()**

let navigationController = UINavigationController(rootViewController: vc)
window?.rootViewController = navigationController
window?.makeKeyAndVisible()
return true
}

Detecting sheet was dismissed on iOS 13

Is there a way to detect that the presented view controller sheet was dismissed?

Yes.

Some other function I can override in the parent view controller rather than using some sort of delegate?

No. "Some sort of delegate" is how you do it. Make yourself the presentation controller's delegate and override presentationControllerDidDismiss(_:).

https://developer.apple.com/documentation/uikit/uiadaptivepresentationcontrollerdelegate/3229889-presentationcontrollerdiddismiss


The lack of a general runtime-generated event informing you that a presented view controller, whether fullscreen or not, has been dismissed, is indeed troublesome; but it's not a new issue, because there have always been non-fullscreen presented view controllers. It's just that now (in iOS 13) there are more of them! I devote a separate question-and-answer to this topic elsewhere: Unified UIViewController "became frontmost" detection?.

ios13 UIPopoverViewController showing UITableViewController - Safe Area problems / Missing parts of table

Okay, so I used up a support ticket with Apple over this - after a year on here with no answers.

The old way (setting the border on the popover) will never work again because of the under-the-hood auto layout stuff going on with the UITableViewController and it's UITableView.

The only solution is to remove the UITableViewController completely, and replace it with a UIViewController, with a single view in it, and inside that view, place a UITableView.

Thankfully the code changes are minimal (just changing the inheritance from UITableViewController to UIViewController, and then add a UITableViewDelegate in)

Then make sure that the UIViewController containing the table sets itself as the UITableView's delegate and source.

The longest part of the fix is recreating the layout in Interface Builder, but this time make sure the UITableView doesn't get it's top, leading, bottom, trailing to the SUPERVIEW, but instead to the SAFE AREA.

Then all you need to do is put this in, and it works:

override func viewDidLoad()
{
super.viewDidLoad()

self.tableView.delegate = self
self.tableView.dataSource = self

self.tableView.layer.borderWidth = 5
self.tableView.layer.borderColor = UIColor.white.cgColor
self.tableView.layer.cornerRadius = 16
}

Attempt to present UIViewController on UIViewController whose view is not in the window hierarchy

Where are you calling this method from? I had an issue where I was attempting to present a modal view controller within the viewDidLoad method. The solution for me was to move this call to the viewDidAppear: method.

My presumption is that the view controller's view is not in the window's view hierarchy at the point that it has been loaded (when the viewDidLoad message is sent), but it is in the window hierarchy after it has been presented (when the viewDidAppear: message is sent).


Caution

If you do make a call to presentViewController:animated:completion: in the viewDidAppear: you may run into an issue whereby the modal view controller is always being presented whenever the view controller's view appears (which makes sense!) and so the modal view controller being presented will never go away...

Maybe this isn't the best place to present the modal view controller, or perhaps some additional state needs to be kept which allows the presenting view controller to decide whether or not it should present the modal view controller immediately.

UIWindow not showing over content in iOS 13

I was experiencing the same problems while upgrading my code for iOS 13 scenes pattern. With parts of your second code snippet I managed to fix everything so my windows are appearing again. I was doing the same as you except for the last line. Try removing viewController.present(...). Here's my code:

let windowScene = UIApplication.shared
.connectedScenes
.filter { $0.activationState == .foregroundActive }
.first
if let windowScene = windowScene as? UIWindowScene {
popupWindow = UIWindow(windowScene: windowScene)
}

Then I present it like you do:

popupWindow?.frame = UIScreen.main.bounds
popupWindow?.backgroundColor = .clear
popupWindow?.windowLevel = UIWindow.Level.statusBar + 1
popupWindow?.rootViewController = self as? UIViewController
popupWindow?.makeKeyAndVisible()

Anyway, I personally think that the problem is in viewController.present(...), because you show a window with that controller and immediately present some 'self', so it depends on what 'self' really is.

Also worth mentioning that I store a reference to the window you're moving from inside my controller. If this is still useless for you I can only show my small repo that uses this code. Have a look inside AnyPopupController.swift and Popup.swift files.

Hope that helps, @SirOz

Change initial ViewController if user has entered a passcode

When user taps Submit button, then just save that fact as a value in UserDefaults:

UserDefaults.standard.set(true, forKey: "UserHasSubmittedPassword")

And then, you can check the condition inside of your AppDelegate file if the user has given password before and redirect the user to another screen like this:

var window: UIWindow?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

let hasSession: Bool = UserDefaults.standard.bool(forKey: "UserHasSubmittedPassword") ?? false
let vc: UIViewController = {
if hasSession {
// next vc you want to show
} else {
// enter password vc
}
}()

let navigationController = UINavigationController(rootViewController: vc)
window?.rootViewController = navigationController
window?.makeKeyAndVisible()
return true
}

Also, don't forget to delete that value when you want the user to enter the password again:

UserDefaults.standard.removeObject(forKey: "UserHasSubmittedPassword")

Presenting modal in iOS 13 fullscreen

With iOS 13, as stated in the Platforms State of the Union during the WWDC 2019, Apple introduced a new default card presentation. In order to force the fullscreen you have to specify it explicitly with:

let vc = UIViewController()
vc.modalPresentationStyle = .fullScreen //or .overFullScreen for transparency
self.present(vc, animated: true, completion: nil)

Dismiss a SwiftUI View that is contained in a UIHostingController

UPDATE: From the release notes of iOS 15 beta 1:

isPresented, PresentationMode, and the new DismissAction action dismiss a hosting controller presented from UIKit. (52556186)


I ended up finding a much simpler solution than what was offered:


final class SettingsViewController: UIHostingController<SettingsView> {
required init?(coder: NSCoder) {
super.init(coder: coder, rootView: SettingsView())
rootView.dismiss = dismiss
}

func dismiss() {
dismiss(animated: true, completion: nil)
}
}

struct SettingsView: View {
var dismiss: (() -> Void)?

var body: some View {
NavigationView {
Form {
Section {
Button("Dimiss", action: dismiss!)
}
}
.navigationBarTitle("Settings")
}
}
}

iOS16+ Present UIViewController in landscape only for single screen not working [Swift 5.7]

After many tries I came up with the simple solution. As I mentioned in the question my whole app is in portrait mode only and only one screen that I want to present in the landscape.

This code doesn't required any external window to be makeKeyAndVisible.
If you use extra window to present then you need to write to dismiss separately for iOS 16.

Old code which was working in previous versions of iOS 16 will be remain same and no change in it.

Magic lines are as below.

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if let _ = window?.rootViewController?.presentedViewController as? LandscapeChartVC {
if #available(iOS 16.0, *) {
return .landscapeLeft
} else {
return .portrait
}
} else {
return .portrait
}
}

I've identified my landscape view controller in the appDelegate's supportedInterfaceOrientationsFor.

Well you can change word presentedViewController to get your controller. And that's it.

Add support with iPad for all 3 or 4 orientation with this:

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if UIDevice.IS_IPAD {
return .allButUpsideDown
} else {
if let _ = window?.rootViewController?.presentedViewController as? LandscapeChartVC {
if #available(iOS 16.0, *) {
return .landscapeLeft
} else {
return .portrait
}
} else {
return .portrait
}
}

If requirement for iPad app to lock the orientations you can follow iPhone / above code.

This idea come up with answers and thank you everyone who shared interest. If anyone still get more improved solution I'll happy to update.

Programmatically go back to previous ViewController in Swift

Swift 3:

If you want to go back to the previous view controller

_ = navigationController?.popViewController(animated: true)

If you want to go back to the root view controller

_ = navigationController?.popToRootViewController(animated: true)

If you are not using a navigation controller then pls use the below code.

self.dismiss(animated: true, completion: nil)

animation value you can set according to your requirement.



Related Topics



Leave a reply



Submit