Swinject / SwinjectAutoregistration

Swinject extension to automatically register your services
MIT License
251 stars 45 forks source link

SwinjectAutoregistration crashes on Xcode 12.0 (12A7209) #60

Closed muratmusic closed 3 years ago

muratmusic commented 4 years ago

Hello everybody,

How soon can you fix this problem? On Xcode 11.7 SwinjectAutoregistration works OK.

Call_Stack Source_Code

ghost commented 4 years ago

Also seeing this issue after upgrading to XCode 12

tkohout commented 4 years ago

Could you provide some example project which would work on Xcode 11 and fail to resolve in Xcode 12?

Or at least the autoregister calls that register the failing services.

ghost commented 4 years ago

Hi @tkohout, our project is confidential, so unfortunately I can only provide you modified excerpts. Hope this helps you anyway.

This is the autoregister call: container.autoregister(EnvironmentProvider.self, initializer: EnvironmentProviderImpl.init)

EnvironmentProviderImpl looks like this:

import Foundation
import Shared

public struct EnvironmentProviderImpl: EnvironmentProvider {
    private enum Paths: String {
        case imprint = "imprint"

    }

    public var supportedAppliances: [ApplianceType] = [.applX, .applY, .applZ]

    public var environment: Environment {
        #if DEV
        return .dev
        #elseif STAG
        return .stag
        #elseif LIVE
        return .live
        #endif
    }

    private var locale: String {
        Locale.current.identifier
    }
}

public extension EnvironmentProviderImpl {
    var imprintURL: URL {
        baseRedirectURL.appendingPath(Path.imprint.rawValue)
    }

}

The project compiles and runs but right at the start, we get this error:

swinject_auto_1 swinject_auto_2

Thanks for your help!

tkohout commented 4 years ago

@aknolldev Thanks for the example:

The problem is in this line:

public var supportedAppliances: [ApplianceType] = [.applX, .applY, .applZ]

If you have a struct that has a variable with a default value the compiler will create two inits, in you case it is:

.init and .init(supportedAppliances:)

For some reason, since the Swift 5.3 the compiler will pick the .init(supportedAppliances:) instead of .init which was selected in the older Swift. Swinject then tries to resolve [ApplianceType] which it can't find. Interestingly enough this will only happen if the struct has only one variable with default value. If you have e.g. 2 variables, it will work the same as in the old version.

In your case you have multiple ways to solve this error:

  1. add your own empty init to your struct:

    init() {}
  2. force the use of the correct init in the registration code:

    container.autoregister(EnvironmentProvider.self, initializer: EnvironmentProviderImpl.init as () -> EnvironmentProviderImpl)
  3. rewrite you code not to use variable with default value

    public var supportedAppliances: [ApplianceType] { [.applX, .applY, .applZ] }
ghost commented 4 years ago

Thanks @tkohout! We will go for option 2, it fits best for us and works perfectly fine. 👍