Xcode 8 beta 6: main.swift won't compile
Asked Answered
A

2

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?

Ammieammine answered 22/8, 2016 at 21:21 Comment(2)
How do I specify the UIApplication class that way?Ammieammine
Looks like this problem is finally fixed in iOS 12 Xcode 10.Thoracoplasty
T
60

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)
)
Thoracoplasty answered 22/8, 2016 at 22:25 Comment(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.Corlisscorly
I'm getting this warning: 'UIApplicationMain' is deprecated: Use the overload of UIApplicationMain where the type of the second parameter is UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>, which is the same as the type of CommandLine.unsafeArgv.Minneapolis
S
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.
Shluh answered 22/8, 2016 at 22:5 Comment(8)
Please note that this situation is regarded as a bug. This answer is more or less identical to the one given here: bugs.swift.org/browse/…Thoracoplasty
@Thoracoplasty , 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.Shluh
@Shluh @Thoracoplasty 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.Unasked
@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.Shluh
@Shluh 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.Thoracoplasty
@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.Shluh
@Shluh 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.Thoracoplasty
@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.Shluh

© 2022 - 2024 — McMap. All rights reserved.