SwiftUI: AppDelegate on MacOS - macos

I'm porting a SwiftUI iOS app to macOS. It uses the #UIApplicationDelegateAdaptor property wrapper to bind a UIApplicationDelegate class. Unfortunately, the UIApplicationDelegate class isn't available on macOS, so I'm wondering how I bind my custom AppDelegate.
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
...
}
}
struct MyApp: App {
#UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
...
}
}

it's almost the same, but then use NS instead of UI. I did it slightly different than you:
#main
struct MyApp: App {
// MARK: - Properties
// Used variables
#NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
#Environment(\.openURL) var openURL
var body: some Scene {
WindowGroup {
MainControlView()
}
.commands {
FileMenuCommands(listOfContainers: listOfContainers)
}
}
}
Then you can write your application delegate like:
import AppKit
import SwiftUI
class AppDelegate: NSObject, NSApplicationDelegate {
// Whatever you want to write here
}
This all worked for me.

The macOS equivalent has the NS prefix
import AppKit
class AppDelegate: NSObject, NSApplicationDelegate {
...
#NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
and the DidFinishLaunching delegate method has a different signature
func applicationDidFinishLaunching(_ aNotification: Notification) [ ...

Related

Xcode 11 beta: AppDelegate file doesn't have window global variable

I am facing an issue in Xcode 11 beta.
The problem is that I am not getting default window variable declared in AppDelegate file.
Is anybody facing this same issue?
In Xcode 11 this is now done in SceneDelegate
EDIT: if you’re still supporting iOS 12 or prior (or want to support 13 plus prior)
Add the UIWindowSceneDelegate to ApplicationDelegate
Add : var window:UIWindow?
Then proceed as you would to setting up in didFinishLaunching
The default var window: UIWindow? Is now moved in SceneDelegate.swift. To set a rootViewController in Xcode 11 you can work within SceneDelegate.swift file, In the scene delegate, you must create the window instance and the root view controller like below:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// set or create your viewController here
let yourViewController = UIStoryboard.init(name: "Main", bundle: nil).instantiateViewController(identifier: "yourViewController") as! YourViewController
// set the rootViewController here using window instance
self.window?.rootViewController = yourViewController
}
Also this answer is helpful : Why is manually setup root view controller showing black screen?
Hope it will help you!
My approach:
first, in AppDelegate create a static property with the class of the view controller you want to access, like this
class AppDelegate: UIResponder, UIApplicationDelegate {
// MARK: Home
static var homeViewController: HomeViewController?
...
}
then, in the view controller
// MARK: - Managing the view
override func viewDidLoad() {
super.viewDidLoad()
// Singleton
AppDelegate.homeViewController = self
...
}
how to use:
extension UIViewController {
var homeViewController: HomeViewController? {
if let controller = self as? HomeViewController {
return controller
}
return AppDelegate.homeViewController
}
}
In my case, that's all it takes.
var window: UIWindow? // add this by yourself
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: Device.bounds)
let root = DDTabBarController()
window?.rootViewController = root
window?.makeKeyAndVisible()
return true
}

Cannot change PlivoLoginAppDelegate to swift in iOS SDK

In your iOS SDK PlivoLogin, there are PlivoLoginAppDelegate.h and PlivoLoginAppDelegate.m.
I want to change it to swift file.
I changed it to the following.
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
class var shared: AppDelegate {
return UIApplication.shared.delegate as! AppDelegate
}
var providerDelegate: ProviderDelegate?
var window: UIWindow?
#IBOutlet var viewController: ViewController?
var phone: Phone?
// MARK: UIApplicationDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
print("Finished launching with options: \(launchOptions)")
// // Phone
self.phone = Phone()
self.viewController = self.window?.rootViewController as? ViewController
self.viewController?.phone = self.phone
self.phone?.setDelegate(self.viewController)
return true
}
...
}
But the log only says
Creating endpoint
Generating random password
and stops, fails to get a delegate response to - (void)successWithResponse:.
How can we get a delegate response?
Plivo Sales Engineer here.
Plivo iOS SDK has Objective C interface and you can access the Objective-C library from the Swift 3.0. This is a sample app in the Swift 3.0 using the iOS SDK's Objective-C interface. This app makes outgoing calls and gets delegate callbacks in Swift 3.0.

Detection of WebView load finish

I am creating a simple app with a WebView basing on this tutorial.
I would like to display a progress indicator while loading the page, but the methods didStartProvisionalLoadForFrame and didFinishLoadForFrame are never called. What am I doing wrong?
ViewController.swift
import Cocoa
import WebKit
class ViewController: NSViewController {
#IBOutlet weak var webView: WebView!
#IBOutlet weak var webViewProgressIndicator: NSProgressIndicator!
let messengerUrl = "https://www.messenger.com/"
override func viewDidLoad() {
super.viewDidLoad()
self.webView.mainFrame.loadRequest(NSURLRequest(URL: NSURL(string: messengerUrl)!))
}
override var representedObject: AnyObject? {
didSet {
// Update the view, if already loaded.
}
}
func webView(sender: WebView!, didStartProvisionalLoadForFrame frame: WebFrame!)
{
self.webViewProgressIndicator.startAnimation(self)
}
func webView(sender: WebView!, didFinishLoadForFrame frame: WebFrame!)
{
self.webViewProgressIndicator.stopAnimation(self)
}
}
I am using Xcode 7 Beta and OS X 10.11 Beta.
Rich's answer works on Xcode 7.0.1 ElCaptain Swift2
BUT I had to connect it in the connections inspector as Swift2 did not accept
self.view.frameLoadDelegate = self
as it gave the following error
Cannot assign a value of type 'ViewController' to a value of type
'WebFrameLoadDelegate!'
So as long as you connect it up as follows, all works great.
The tutorial missed out something, Need to add:
self.webView.frameLoadDelegate = self
(can be done in connections inspector)
then call the load..
self.webView.mainFrame.loadRequest(NSURLRequest(URL: NSURL(string: messengerUrl)!))
Also add the WebFrameLoadDelegate interface to your ViewController.. (thanks tjv)
class ViewController: NSViewController, WebFrameLoadDelegate{ .....
You need to assign the delegate of your UIWebview ie: webview.delegate = self

windowDidResize protocol swift OSX

I am creating a program and I would like the UI to change based on the size of the window. I'm looking for some method that is called when the window has been resized. I went to the documentation for windowDidResize, but I cannot get it to work when the window is resized.
import SpriteKit
import AppKit
class GameScene: SKScene , SKPhysicsContactDelegate ,NSWindowDelegate{
**** bunch of code ****
func windowDidResize (notification: NSNotification) {
HUDComp.updatePosition(size)
println("Screen has been resized")
}
}
Any info would be greatly appreciated.
Swift 5 macOS 11+
Updated for Xcode 12.2 and macOS Big Sur.
This will call windowDidResize when the window's dimensions have changed.
class ViewController: NSViewController, NSWindowDelegate {
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(NSWindowDelegate.windowDidResize(_:)), name: NSWindow.didResizeNotification, object: nil)
}
func windowDidResize(_ notification: Notification) {
print(view.window?.frame.size as Any)
}
}
If you inherit NSWindowDelegate, the only thing you should do is add observer onto NSNotificationCenter.
Code is here.
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("windowDidResize:"), name: NSWindowDidResizeNotification, object: nil)
my two cents for swift 5. (showing both delegate and notification, choose one..)
import Cocoa
class ViewController: BaseController, NSWindowDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.makeItListenZoom()
}
override func viewDidAppear() {
self.view.window?.delegate = self
}
private final func makeItListenZoom(){
NotificationCenter.default.addObserver(forName: NSWindow.didResizeNotification, object: nil, queue: OperationQueue.main) { (n: Notification) in
print("didresize---")
}
}
func windowDidResize(_ notification: Notification){
print("windowDidResize")
}
}

Nib's custom class won't hook up to class

The nib I am loading is a custom About window for my app. When the 'About' NSMenuItem is pressed I load the nib in AppDelegate in the following manner:
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
var about = NSWindowController()
#IBAction func aboutClicked(sender: NSMenuItem) {
about = AboutWindow(windowNibName: "AboutWindow") as AboutWindow
NSBundle.mainBundle().loadNibNamed("AboutWindow", owner: about, topLevelObjects: nil)
}
*both the class that I want to hook up to the nib and nib itself are named 'AboutWindow'.
Once I create my NSWindowController and it's nib file, The custom class option for the nib's NSWindow does not allow me to put in the 'AboutWindow' class that I created alongside the nib.
As you can see the nib's custom class is set to NSWindow and it won't change
Any help on how to hook up this custom class and the nib is greatly appreciated.
Can you describe what the following doesn't do that you want to be done:
//
// AboutWindowController.swift
// AboutWindow
//
import Cocoa
class AboutWindowController: NSWindowController {
override func windowDidLoad() {
super.windowDidLoad()
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
}
}
That was hooked up automatically by Xcode to AboutWindowController.xib, whose name I changed to AboutWindow.xib.
Next file:
//
// AppDelegate.swift
// AboutWindow
//
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet weak var window: NSWindow!
var about = NSWindowController()
func applicationDidFinishLaunching(aNotification: NSNotification) {
// Insert code here to initialize your application
}
func applicationWillTerminate(aNotification: NSNotification) {
// Insert code here to tear down your application
}
#IBAction func aboutClicked(sender: NSMenuItem) {
about = AboutWindowController(windowNibName: "AboutWindow")
about.showWindow(self)
}
}
In IB, I dragged from the About menu item to the First Responder object to hook up the action. When I run the app and click on the About menu item, the AboutWindow displays.
I did not attempt to change any class names in IB.
Response to comment:
If I change AboutWindowController to this:
//
// AboutWindowController.swift
// AboutWindow
//
import Cocoa
class AboutWindowController: NSWindowController {
override func windowDidLoad() {
super.windowDidLoad()
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
println("The About window has loaded")
}
}
I see the message printed in the console.

Resources