23

We have a custom UIApplication object, so our main.swift was

import Foundation
import UIKit

UIApplicationMain(Process.argc, Process.unsafeArgv, NSStringFromClass(MobileUIApplication), NSStringFromClass(AppDelegate))

and that didn't work in Xcode 8 beta 5 so we used this

//TODO Swift 3 workaround? https://forums.developer.apple.com/thread/46405
UIApplicationMain( Process.argc, UnsafeMutablePointer<UnsafeMutablePointer<CChar>>(Process.unsafeArgv), nil, NSStringFromClass(AppDelegate.self))

On Xcode 8 beta 6 we get Use of unresolved identifier 'Process'

What do we need to do in Xcode 8 beta 6/Swift 3 to define the UIApplicationMain?

Jason Hocker
  • 6,585
  • 9
  • 39
  • 76

2 Answers2

59

I write it this way:

UIApplicationMain(
    CommandLine.argc,
    UnsafeMutableRawPointer(CommandLine.unsafeArgv)
        .bindMemory(
            to: UnsafeMutablePointer<Int8>.self,
            capacity: Int(CommandLine.argc)),
    nil,
    NSStringFromClass(AppDelegate.self)
)

To change the UIApplication class, substitute NSStringFromClass(MobileUIApplication.self) for nil in that formulation.

However, if your only purpose here is to substitute a UIApplication subclass as the shared application instance, there's an easier way: in the Info.plist, add the "Principal class" key and set its value to the string name of your UIApplication subclass, and mark your declaration of that subclass with an @objc(...) attribute giving it the same Objective-C name.

EDIT This problem is now solved in Swift 4.2. CommandLine.unsafeArgv now has the correct signature, and one can call UIApplicationMain easily:

UIApplicationMain(
    CommandLine.argc, CommandLine.unsafeArgv, 
    nil, NSStringFromClass(AppDelegate.self)
)
William GP
  • 1,029
  • 1
  • 11
  • 27
matt
  • 447,615
  • 74
  • 748
  • 977
  • 2
    "CommandLine.unsafeArgv now has the correct signature" might be misleading, it has the same signature as in older Swift versions. The signature of UIApplicationMain changed, and the argv parameter now matches CommandLine.unsafeArgv. – Anyway, it is nice that this has been fixed. – Martin R Sep 27 '18 at 13:57
  • 3
    I'm getting this warning: `'UIApplicationMain' is deprecated: Use the overload of UIApplicationMain where the type of the second parameter is UnsafeMutablePointer?>, which is the same as the type of CommandLine.unsafeArgv.` – Hemang Oct 29 '18 at 07:35
5

It seems Process has been renamed to CommandLine in beta 6.

CommandLine

But the type of CommandLine.unsafeArgv is mismatching the second argument of UIApplication, so you may need to write something like this:

CommandLine.unsafeArgv.withMemoryRebound(to: UnsafeMutablePointer<Int8>.self, capacity: Int(CommandLine.argc)) {argv in
    _ = UIApplicationMain(CommandLine.argc, argv, NSStringFromClass(MobileUIApplication.self), NSStringFromClass(AppDelegate.self))
}

(UPDATE)This mismatching should be considered as a bug. Generally, you'd better send a bug report when you find "this-should-not-be" things, like the third parameter in beta 5. I hope this "bug" will be fixed soon.


If you just want to designate your custom UIApplication class, why don't you use Info.plist?

NSPrincipalClass | String | $(PRODUCT_MODULE_NAME).MobileUIApplication

(Shown as "Principal class" in non-Raw Keys/Values view.)

With this in your Info.plist, you can use your MobileUIApplication with normal way using @UIApplicationMain.

(ADDITION) Header doc of UIApplicationMain:

// If nil is specified for principalClassName, the value for NSPrincipalClass from the Info.plist is used. If there is no
// NSPrincipalClass key specified, the UIApplication class is used. The delegate class will be instantiated using init.
OOPer
  • 44,179
  • 5
  • 90
  • 123
  • Please note that this situation is regarded as a bug. This answer is more or less identical to the one given here: https://bugs.swift.org/browse/SR-1390?focusedCommentId=17441&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-17441 – matt Aug 22 '16 at 22:14
  • @matt , I don't think telling `Process` is renamed to `CommandLine` is not identical to bug report. But, yes, seemingly the main code in my answer is showing a workaround for the bug, and I'll update the part. – OOPer Aug 22 '16 at 22:27
  • @OOPer @matt I was able to use `NSPrincipleClass` in the Info.plist for an iOS app. But as far as I can tell it is not documented. This approach works better for my project. – Brad Sep 14 '16 at 17:41
  • @Brad, it's documented in the header doc. Cmd-click on `UIApplicationMain`. As far as I know, iOS 8 SDK has the description about this and with all combination of iOS versions (8+) and simulators and devices I have tested (not much, though), it works fine. – OOPer Sep 14 '16 at 20:42
  • @OOPer Finally figured this out. In Swift, it's crucial to mark the UIApplication subclass declaration with `@objc(...)` to give it an unmunged Objective-C name. Then NSPrincipalClass works. – matt Sep 28 '17 at 17:11
  • @matt, thanks for reporting. Unfortunately, my testing code does not have `@objc` attribute on the `UIApplication` subclass, but it worked. So, it does not explain all aspects of using `NSPrincipalClass`. But, it may be the safer way as you say you could have made it work. – OOPer Sep 28 '17 at 21:36
  • @OOPer Perhaps sometimes the name gets munged and other times it doesn't. But in my new tests, it we use `@objc(...)` with a name, like `@objc(MyApplication) class MyApplication`, it always works. – matt Sep 28 '17 at 22:51
  • @matt, that may happen. A minor 0.0.1 version up, or any other things may affect. As for now, we need to expect your _always_ would apply to our apps always. – OOPer Sep 29 '17 at 10:59