Using Document Browser View Controller with Mac Catalyst - swift

I have just started experimenting with Catalyst. My app is a document browser based app.
The stock MacOS Finder dialog is indeed launched when the appropriate button is clicked. The main app window completely disappears when the Finder dialog appears, unless I choose in the IB for the document browser view controller to appear in "Automatic" mode.
Cancelling the operation indeed brings back the main window.
However, selecting a file will yield a blank screen and no results. A little debugging revealed that none of the file selection functions is being called, and I have implemented all of them:
func documentBrowser(_ controller: UIDocumentBrowserViewController, didPickDocumentURLs documentURLs: [URL]) {...}
func documentBrowser(_ controller: UIDocumentBrowserViewController, didImportDocumentAt sourceURL: URL, toDestinationURL destinationURL: URL) {...}
func documentBrowser(_ controller: UIDocumentBrowserViewController, failedToImportDocumentAt documentURL: URL, error: Error?) {...}
Is there another function or handle used in Catalyst? I found nothing in the documentation.
EDIT:
I should clarify that I manipulated the app to present the DocumentViewController before the DocumentBrowserViewController, although Apple requires that the DocumentBrowserViewController is the initial view controller. I did it by changing the app delegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
...
// Set the documentViewController to appear first
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "main")
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
return true
}
Taking this out still doesn't change anything. And a default project created from the document browser template does seem to work. What could prevent these methods from being called?

I would suggest to implement func documentBrowser(_ controller: UIDocumentBrowserViewController, didPickDocumentsAt documentURLs: [URL]) as well

Related

swift pushkit -> open call screen without open total app

I have some problem with my app, the exactly I want is to only open call screen when get pushkit VOIP call. But the problem is that the app gets open again(when killed), so many request were sent to server, i just want to open only callscreen, then may exit app after call dismiss.
I will fully explain the problem now:
First, in app delegate i replace with this class(this class have same UI with splash Screen)
initiateFirstScreen("SplashScreen", storyboardName : "sheet")
Inside this class. I have to check token, user info, connect to signalr server, it's took about 5-8 seconds, and when all loaded, i call this function to navigate to the HomeScreen:
func checkLogin() {
if let oauth = AppDelegate.shared.authState, oauth.isAuthorized{
initiateFirstScreen("HomeVC", storyboardName : "main")
}else{
initiateFirstScreen("LoginVC", storyboardName : "main")
}
}
func initiateFirstScreen(_ vcName: String, storyboardName : String) {
guard let window = AppDelegate.shared.window else{
AlertUtils.alertMessageWithOkAction(vc: self, mes: Language.get("Something went wrong")){b in
exit(0)
}
return
}
let storyBoard: UIStoryboard = UIStoryboard(name: storyboardName, bundle: nil)
let vc = storyBoard.instantiateViewController(withIdentifier: vcName)
window.rootViewController = vc
window.makeKeyAndVisible()
}
Inside above code, im using window.rootViewController = vc to dislay HomeScreen without any animation.
The problem:
Because of long loading in SplashScreen, when I got pushKit -> show Callkit screen, user may took 3-4 seconds to answer(when the app is killed/swiped)
-> didFinishLaunchingWithOptions called
-> SplashScreen called, and while user is answering call, the "check token, user info, connect to signalr" is loaded
-> Hence, the below function called:
window.rootViewController = vc
window.makeKeyAndVisible()
-> It's clear my callscreen now, that is the problem.
So i want to solved this problem, sorry for my silly question, but it's make me waste 3 days but can not solved this :(
You can use the delegate
func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession)
This delegate gets call when you answer the call. So just navigate directly to call screen. and add a flag eg. isCall = true and prevent the user to navigate to Home Screen this time

iOS 13/Facebook SDK error "Unable to find a valid UIWindow"

(To forestall well-intended suggestions, yes I posted this question last week on Facebook's developer forum. No responses yet.)
TL;DR
Facebook SDK 5.8 complains at startup FBSDKLog: Unable to find a valid UIWindow.
The Main Story
In a from-scratch, one-view Xcode 11/iOS 13 project, there is no longer a default UIWindow member associated with the application. (The window per se is still around; you can see it, contained in a UIWindowScene, using the View Hierarchy Debugger in Xcode, or the Reveal app.)
FBSDK 5.8 does seem to be iOS-13-aware, and looks around for it. The relevant code is at line 498 of
https://github.com/facebook/facebook-ios-sdk/blob/master/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKInternalUtility.m.
Facebook's code iterates over the application's connectedScenes member, which for me is an empty set. How do I modify my code so that FBSDK finds the window?
Some Hacking
I tried adding the following to scene(_:willConnectTo:options:) but it seems to be too late — the FBSDKLog message has already appeared by then. (So I'm flailing...)
guard let s = (scene as? UIWindowScene) else { return }
self.window = UIWindow(windowScene: s)
The following also failed, but it was just a shot in the dark:
guard let s = (scene as? UIWindowScene) else { return }
self.window = UIWindow(frame: s.coordinateSpace.bounds)
self.window?.windowScene = s
self.window?.rootViewController = ViewController(nibName: nil, bundle: nil)
self.window?.makeKeyAndVisible()
If you don't use the new behaviour and don't mind reverting to the old way, you can try the following
Delete Application Scene Manifest key from Info.plist
Delete SceneDelegate.swift
Add var window: UIWindow?to AppDelegate.swift
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow? // <-- Here
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
// window!.makeKeyAndVisible()
return true
}
}
Add window variable to AppDelegate class
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
Assign UIWindow inside didFinishLaunchingWithOptions
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
if let window = window {
window.makeKeyAndVisible()
self.window = window
}
ApplicationDelegate.shared.application(
application,
didFinishLaunchingWithOptions: launchOptions
)
return true
}

How to set property in app delegate for tabview controller

I've read several of the suggested posts that were to help with this problem but could not find something for this particular issue.
I need to set a property on my controller, the book is saying to do so in the app delegate. In the previous assignment using a navbar, this worked:
func application(_ application: UIApplication, didFinishLaunchingWithOptions
launchOptions: [UIApplicationLaunchOptionsKey : Any]?) -> Bool {
// Override point for customization after application launch.
// Create an ItemStore to hold list of items
let itemStore = ItemStore()
// Access the ItemsViewController and set its item store
let itemsController = window!.rootViewController as! ItemsViewController
itemsController.itemStore = itemStore
return true
}
However, creating a similar program I need to use tab bar but can't get it to work and keep running into the error stated above, on the let editcontroller = tabcontroller. - line
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
// Create an pindatabase
let pinDataBase = PinDatabase()
// Access the pairsViewController and set its database
let tabController = window!.rootViewController as! UITabBarController
// this edit controller line is where I am stuck
let editController = tabController.tabBar as! EditViewController
editController.pinDataBase = pinDataBase
return true
}
The error is:
fatal error: unexpectedly found nil while unwrapping an Optional value
The controller I'm trying to set the property on is not the root controller but the third tab if that helps.
Your issue is your attempt to cast the UITabBar to your EditViewController. You need to access the array of view controllers from the tab bar controller and access the one that is actually the EditViewController.
let editController = tabController.viewControllers[2] as! EditViewController
This will access the 3rd view controller and cast it as needed.

Receive SIGABRT error when trying to hijack root view controller

I am trying to have my application open a different view controller based upon whether an array is empty in the user's NSUserDefaults. Essentially, if the user has previously saved data in the app, the app will open up to where they can select the data. Otherwise, the app will open to a welcome screen.
However, when the array is empty, I see the background color that I set for the welcome screen, but not the text or button that I laid out in the storyboard. When the array is not empty and the data page should open, my app crashes with a SIGABRT error. I checked all of the outlets for the view controller in question and nothing seems to be disconnected. Additionally, when I comment out the code in the app delegate and set the data view controller as my initial starting view, the app runs fine.
The full error is "Thread 1: signal SIGABRT" and it is tagged in the class AppDelegate line.
The code I used in the App Delegate is below:
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
var accounts = loadAccounts()!
if accounts.isEmpty {
let welcomeController = WelcomeViewController()
self.window!.rootViewController = welcomeController
} else {
let tableController = AccountTableViewController()
self.window!.rootViewController = tableController
}
return true
}
func loadAccounts() -> [Account]? {
return NSKeyedUnarchiver.unarchiveObject(withFile: Account.ArchiveURL.path) as? [Account]
}
Maybe the UIWindow is not set properly.
let bounds = UIScreen.main.bounds
self.window = UIWindow(frame: bounds)
self.window?.rootViewController = `your view controller`
self.window?.makeKeyAndVisible()
What else can go wrong?
var accounts = loadAccounts()!
This line is the culprit for you. Precisely this symbol ! is I guess. You are trying to fetch data from a database or a filesystem and expect it will always be there.
Think about it, it can't be true all the time.
# check if account array is not empty; I would have returned nil if it would be empty and so we can avoid that extra check here.
if let accounts = loadAccounts(), !accounts.isEmpty {
let tableController = AccountTableViewController()
self.window!.rootViewController = tableController
return true
}
let welcomeController = WelcomeViewController()
self.window!.rootViewController = welcomeController
Also, if you can provide more info about the error message from your debug console. Then I would be able to help in a better way.

Prevent appearing of last accessed view after launch screen when app is restarted in iOS?

I’ve created iOS app, where Im facing small issue related to UI.
Say app is having launcher, view1 and view2 screens.
Assume App is launched, after that view1 is loaded, from there view2 is loaded (ex. on button press).
Now user quit the app and re-started. Now after launcher screen, view2 appears for fraction of second before view1 appears.
I tried following code, but still Im not able to avoid appearing of view2 after launcher and before view1. I assume this is due to app restoration feature of iOS.
In AppDelegate, added below code -
func application(application: UIApplication, shouldSaveApplicationState coder: NSCoder) -> Bool {
return false
}
func application(application: UIApplication, shouldRestoreApplicationState coder: NSCoder) -> Bool {
return false
}
Any help.. please..:)
You are missing an underscore in the function signature. Try
func application(_ application: UIApplication, shouldRestoreApplicationState coder: NSCoder) -> Bool {
return false
}
But I don't think this method does what you need.
See https://developer.apple.com/library/archive/qa/qa1838/_index.html for one of Apple's solutions