I come from an iPhone OS development background. I'm now trying to write apps for OSX, but I don't understand where cocoa on OSX decides where the program gets control.
I can see the main function, but where does program control go from there? Say for example I want to programatically create a window with an NSView in it once the app has finished launching - how would I do that? There is no app delegate created that I can see, in iPhone OS I would wait for the -(void) applicationDidFinishLaunching:(UIApplication *)application
method to be called. I really don't want to use the Interface Builder or NIB files to setup my window/view. How would I go about this?
It's much the same as the iPhone. In your application controller class, override NSApplication's applicationDidFinishLaunching delegate method. If you used the standard Xcode project template your app controller is already instantiated in your Interface Builder MainMenu.xib and set to be the application's delegate; if not you'll need to drag it in there and set up those connections yourself.
Speaking more generally, an OS X app begins its life in the main method, where Cocoa will automatically set up your application's run loop and load the .xib file you specify in Info.plist. This xib is usually where your application controller is instantiated. By overriding one of the methods such as +initialize, -init, -applicationWillFinishLaunching or -applicationDidFinishLaunching (which all have subtly different behaviors) you can load additional controllers and nibs with objects that interact with the run loop at a future date, so you can continue to execute code after your launch method has finished.
Related
In my SwiftUI project I see AppDelegate file as well as a SceneDelegate file.
What are the differences between them?
For example between the methods in SceneDelegate
scene(_:willConnectTo:options:)
and in the AppDelegate
application(_:didFinishLaunchingWithOptions:)
The two files are meant to split the work by what is needed to run the app as a whole and what is needed for one "instance" that would support visibly running in the background. This would be something like configuring a database once, but displaying different sets of values by window.
You could think of them as the global and private versions. One is shared and the other is limited to the individual owner. In a way, they are exactly what you would expect by the names.
Multi-window support is happening
Next time you create a new Xcode project you’ll see your AppDelegate
has split in two: AppDelegate.swift and SceneDelegate.swift. This is a
result of the new multi-window support that landed with iPadOS, and
effectively splits the work of the app delegate in two.
From iOS 13 onwards, your app delegate should:
Set up any data that you need for the duration of the app.
Respond to any events that focus on the app, such as a file being shared with you.
Register for external services, such as push notifications.
Configure your initial scenes.
In contrast, scene delegates are there to handle one instance of your
app’s user interface. So, if the user has created two windows showing
your app, you have two scenes, both backed by the same app delegate.
Keep in mind that these scenes are designed to work independently from
each other. So, your application no longer moves to the background,
but instead individual scenes do – the user might move one to the
background while keeping another open.
Courtesy of https://www.hackingwithswift.com/articles/193/whats-new-in-ios-13
AppDelegate is responsible for handling application-level events(like app launch), application lifecycle, and setup.
SceneDelegate is responsible for handling what is shown on the screen (Windows or Scenes) and managing the way your app is shown.
scene(_:willConnectTo:options:) is the first method called in UISceneSession life cycle. This method will create a new UIWindow, set the root view controller, and make this window the key window to be displayed.
application(_:didFinishLaunchingWithOptions:) is called when the application is launched and where the application set-up is done. Earlier iOS 13, we might have used this method to configure the UIWindow object and assign a ViewController instance to the UIWindow object to make it display on the screen. From iOS 13, if your application has scenes, then AppDelegate is no longer responsible for handling this and is moved to SceneDelegate.
From: https://medium.com/#kalyan.parise/understanding-scene-delegate-app-delegate-7503d48c5445
Multiplatform
In addition to the answer of Abandoned Cart, Since Xcode 11, You have a new option called Multiplatform for choosing as a starting template. That's where you will only see a file contains:
#main
struct MyMultiplatformApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
This is how the system knows where to start the code with #main (in Swift 5.3) and it contains WindowGroup that manages multiple windows of your app in all apple platforms. So you don't need the be worry about SceneDelegate and AppDelegate anymore.
If you need it to be like the old app delegate, for example when you want to use its methods, You should subscribe for corresponding notifications or use the UIAppDelegateAdapter wrapper as I described here
I'm new to Objective-C and iOS programming. I've read through a few of Apple's "Getting Started" docs and I've downloaded a few sample applications to try and get familiar with what is going on in the app. What I'm confused about is what exactly happens from the application's launch. I see in main.m that UIApplicationMain gets called and invokes the AppDelegate. From what I've read, now, if applicationDidFinishLaunching returns true, the app will enter the main event loop.
Is this all correct? If so, how do I tie my code to events? Where do I create instances of my classes when an event occurs?
Finally, from my understanding, Xcode now creates all template apps with storyboards. However, some applications I am looking at are a bit older and don't use storyboards, but I don't see .xib or .nib files anywhere in the directory, but the applications successfully build. Am I wrong in assuming that applications require these files?
An application does not require a .xib or .nib to run. Many programmers do not use any of the visual design tools that generate storyboards or .nib files. You can define your UI completely in code if you wish.
The call to UIApplicationMain in main.m creates a singleton UIApplication object, sets up an event loop, and sets up your UIApplicationDelegate which works in tandem with UIApplication so you can customize the behavior of your app at key points in its lifecycle. UIApplication manages the event loop for you. It receives events from the system and dispatches them to your code for handling.
In order to really understand event handling you need to understand the responder chain. If you look at the superclass of your app delegate you will see it is UIResponder. This is the interface that lets objects respond to and handle events. It is the superclass of UIApplication and UIView and handles most of the raw event handling for you. Events follow a defined path through your code. In the simplest case, touch events, UIApplication pops an event from the event loop and hands it off to UIWindow. UIWindow will perform a hit test to try and deliver it directly to the UIView under the finger. It gets more complicated and motion events take a different path but the point is that much of the raw event processing is handled for you by UIKit. All you really need to do is setup your UIWindow and its rootViewController and events will follow a specific delivery path through all your UIKit responders. You can read about the responder chain in detail here https://developer.apple.com/library/ios/documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/event_delivery_responder_chain/event_delivery_responder_chain.html.
When your app starts, the following delegate methods will get called in this order:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions;
- (void)applicationDidBecomeActive:(UIApplication *)application;
In addition, your initial view controller will get created and shown and the following methods will get called (assuming you are using storyboards or xib files):
-(void)viewDidLoad;
-(void) viewWillAppear:(BOOL)animated;
As for "tying your code to events", what type of events are you talking about? What are you trying to accomplish?
You no longer need to use xib files if you are using storyboards, however, you can if you want to.
I was using Xcode 4.1 and after upgrading to 4.2, things started to become out of date. I am using many examples from different books, such as Big Nerd Ranch Guides, which do not use Storyboards and the Windows-Based Application had been changed to "Empty" Application.
With these new changes, I feel like the books and tutorials I had been using to start have become outdated. In many of these examples, they say to write the methods and variables in the delegate header files for 4.1. With the new 4.2 Xcode, there is an AppDelegate and ViewController. Should I still be writing the methods and class members in the AppDelegate, or should I be now writing them in the Controller file?
I am confused. Does Apple now want us to create our controller and reference it through the delegate?
When your app is run, it creates an instance of UIApplication. You want to know things that only the UIApplication object knows (did we just get switched to the background? did we just open?) so you use the delegate pattern to get it. When you start a new project Apple starts you off with an already-assigned App Delegate. You can open up MainWindow.nib and inspect your App Delegate to see how it is connected to your UIApplication instance (File's Owner, in this case).
In general you only want to put code in there that has to do with the basic functionality of your app. Launch, quit, go to background and come to foreground are when you'll be doing things in the App Delegate.
Most everything else should go in your view controllers or model objects. Since 'delegate' is just a design pattern, your view controllers can be delegates of other objects. For example, if you present a UITableView, you will assign a view controller as it's delegate in order to respond to events such as selection and scrolling. Your app has many delegates, but it only has one App Delegate.
The AppDelegate is really just a "launcher" for your app. Ie: You shouldn't be writing much code in it at all.
If you're concerned with "set up" code, do it in your View Controller, under viewDidLoad.
Could anyone tell me when we use the AppDelegate.m and AppDelegate.h during iPhone programming? I have used only the ViewController.m and ViewController.h for basic learning. I just want to know when and why AppDelegate is used.
Both define classes, but the classes are used for different things. ViewController.h/m define a view controller class that manages a hierarchy of views -- basically, one screen of an application. You might have multiple screens that each have their own view controller.
AppDelegate.h/m define a class that manages the application overall. The app will create one instance of that class and send that object messages that let the delegate influence the app's behavior at well-defined times. For example, -application:didFinishLaunchingWithOptions: is sent when the app has finished launching and is ready to do something interesting. Take a look at the UIApplicationDelegate reference page for a list of messages that the app delegate can implement to modify the behavior of the application.
I would like to add the following to #Caleb's answer.
If care is not taken, the AppDelegate could easily become one of the most accessed objects in the application. I usually refrain from calling methods in the AppDelegate from any of my ViewControllers. Unless, something needs to be reported to the AppDelegate that would influence the behaviour of the whole application.
I keep my AppDelegate for the following:
initialization: whatever needs to be done on the very first launch (after an install or an update)
data migration from version to version (e.g. if you use CoreData and migrations)
configuration of objects linked via IBOutlets from MainWindow.xib
determining the initial orientation to launch in
saving uncommitted data / state prior to the application being terminated or entering background mode
registering for the Apple Push Notification Service and sending the device token to our server
opening one of the supported application URLs (e.g. maps://)
For other use case scenarios and a more thourough description of the AppDelegate, see the iOS Application Programming Guide.
The view-controller. h/m is responsible of controlling the connection between your model and your view (more on MVC here).
AppDelegate. h/m is responsible for the life-cycle of your application. What to do when the user press the home button and exit your app, what to do when the app enter background. Things like this.
I couldn't find a good answer anywhere to this. I am using a UINavigationController for my iPhone app, with everything is generated programmatically, nothing in Interface Builder. I am trying to port my app to iPad, using a UISplitViewController and my existing UINavigationController, but I am not sure where I should have the logic of my program separating the view controllers for iPhone or iPad.
Do I set up my main file to use a different app delegate or do I use the same app delegate and have the user interface conditionally set up within it?
Besides this, whenever I try to compile my app on the simulator it does not recognize the UISplitViewController or even the condition in which I check if the class exists.
Can please someone put me in the right direction, remembering that I am not using any xibs?
If you want to see an example of a completely programmatic iPhone / iPad interface that uses a split view, you can download the source code of my application Molecules.
Within that application, I use one application delegate, but I set up the interface differently depending on which user interface idiom is present (iPad or iPhone). For the iPhone, I instantiate a root view controller which manages the appropriate interface for that device. For the iPad, I first create a UISplitViewController and attach it to the root window, then create my iPad-specific root view controller and place it as the detail view of the split view controller (with a navigation controller that I use for item selection as the left-hand controller for the split view).
Again, I recommend looking at that application project to see how I set this up programmatically. The code's available under a BSD license, so you can copy and paste this into your own application if you'd like.
As far as the compilation errors you're getting, you will need to migrate your application target to be a universal application using the "Upgrade Current Target for iPad" menu option. Once that has completed, set your build SDK to 3.2. Go to your application's build settings and set its Deployment Target to the earliest OS you want to support with your application (with 3.0 being the farthest back you can go).
Finally, you will need to weak-link UIKit. For how to do that, see my answer here. Weak linking of frameworks is no longer necessary if you are building using the iOS 4.2 or later SDK. Simply check for the presence of the appropriate classes at runtime by seeing if their +class method returns nil.