1

I have a custom class, located in a Swift Package, I am using as the super class to my AppDelegate

When I run the following code, testVar will be empty when printed to the console.

import UIKit
import CustomSwiftPackage

@main
class AppDelegate: CustomSwiftPackageDelegate {
    
    let testVar = "test"

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        print(testVar)
        
        return true
        
    }

}

Note: If I change let testVar = "test" to lazy var testVar = "test", it works as the variable is initialized at runtime.


When I run the follow code now, the testVar will be printed to the console with "test"

import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    
    let testVar = "test"

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        print(testVar)
        
        return true
        
    }

}

If I try to make a new class that that does the same exact thing as CustomSwiftPackageDelegate and place it in the same package as my AppDelegate, the testVar will print "test" to the console.

What is going on here? Does Apple allocate memory slightly different for Swift Packages?

Michael
  • 9,639
  • 3
  • 64
  • 69
  • @loremipsum wrong wrapper? Like as in I should be using `SceneDelegate`? Doesn't fit this case. This is just a new default iOS application with one package being added. – Michael Jun 08 '23 at 19:31
  • This is a UIKit app with the @main entry point being `AppDelegate` – Michael Jun 08 '23 at 19:38
  • Maybe I’m wrong then – lorem ipsum Jun 08 '23 at 19:40
  • I have created a new app and a new package and set them up as you described. The print was as expected (correct). Can you try and make the same and confirm that you are still getting the same issue? Maybe try and pinpoint what exactly you need to do to as minimum to replicate the behaviour you are experiencing. – Matic Oblak Jun 08 '23 at 21:24
  • @MaticOblak Install this package: https://github.com/trycourier/courier-ios And follow this step to reproduce: https://github.com/trycourier/courier-ios/blob/master/Docs/PushNotifications.md#3-implement-the-courierdelegate You need to have the CustomAppDelegate coming from a Swift Package – Michael Jun 08 '23 at 22:22

1 Answers1

0

The minimum reproducible example is actually subclassing from an app delegate class that has restricted access to overridden constructor. So basically you can create another app delegate in same file and use private override init() {}. The following will crash:

class SomeAppDelegate: UIResponder, UIApplicationDelegate {
    
    private override init() {
        super.init()
    }
    
}

@main
class AppDelegate: SomeAppDelegate {

    var someText: String = "Hi there"

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {  
        print("The text is: \(someText)")
    }

And simply removing private will remove the crash.

class SomeAppDelegate: UIResponder, UIApplicationDelegate {
        
    override init() {
        super.init()
    }
        
}

The fix when same is used within a package is to simply use public on the constructor. In your case that would be inside CourierDelegate found here.

Since I can assume that this specific tool is not yours you have a couple of options:

  • Fork it and make the change in the repo
  • Report a problem and wait for the fix
  • Do not use the tool because it doesn't work very well
  • Avoid using non-lazy properties in app delegate

Why exactly this happens in the first place is a good question. Probably the system does something special when creating app delegate as being marked with @main entry point. I could try and guess that restricting visibility to constructor somehow breaks the pipeline of instantiating this object on lower level and the top level constructor is not being called at all. With it the memory is probably allocated but default values are not assigned to it. It might actually be a good idea to ask another question about it.

Matic Oblak
  • 16,318
  • 3
  • 24
  • 43