Initializer is inaccessable due to 'internal' protection level

86,868

Solution 1

Just add to your FacebookLoginStrategy:

public init() {}

As long as you do not implement init() explicitly, it is marked as internal by default. You need to overwrite that permission level to be able to instantiate from outside your framework.

Solution 2

If you are running in to this in code within an XCTestCase, make sure that you have added @testable import My-Awesome-App to the top of your test file.

Solution 3

Add init method as Public access

public init() {}
Share:
86,868

Related videos on Youtube

Khuong
Author by

Khuong

Follow my twitter https://twitter.com/khuong291

Updated on December 09, 2021

Comments

  • Khuong
    Khuong over 2 years

    I have some protocols

    LoginStrategy

    public protocol LoginStrategy {
        func login(_ viewController: UIViewController)
        func getUserInfo(withCompletionHandler completionHandler: @escaping (_ userInfo: [String: Any]?) -> ())
        func createLoginButton(_ frame: CGRect, withCompletionHandler completionHandler: @escaping (_ loginButton: UIView) -> ())
        func getUserId() -> String
    }
    

    and two classes:

    LoginProvider

    public class LoginProvider {
    
        public let strategy: LoginStrategy
    
        public func login(_ viewController: UIViewController) {
            return self.strategy.login(viewController)
        }
    
        public func getUserInfo(withCompletionHandler completionHandler: @escaping (_ userInfo: [String: Any]?) -> ()) {
            return self.strategy.getUserInfo(withCompletionHandler: completionHandler)
        }
    
        public func createLoginButton(_ frame: CGRect, withCompletionHandler completionHandler: @escaping (_ loginButton: UIView) -> ()) {
            return self.strategy.createLoginButton(frame, withCompletionHandler: completionHandler)
        }
    
        public func getUserId() -> String {
            return self.strategy.getUserId()
        }
    
        public init(strategy: LoginStrategy) {
            self.strategy = strategy
        }
    
    }
    

    FacebookLoginStrategy

    import Foundation
    import FacebookCore
    import FacebookLogin
    
    public class FacebookLoginStrategy: LoginStrategy {
    
        public var grantedPermissions: Set<Permission>? = nil
    
        public var declinedPermissions: Set<Permission>? = nil
    
        public var userId: String = ""
    
        public func login(_ viewController: UIViewController) {
            let loginManager = LoginManager()
            let permissions: [ReadPermission] = [.publicProfile, .userFriends, .email]
            loginManager.logIn(permissions, viewController: viewController) { loginResult in
                switch loginResult {
                case .failed(let error):
                    print(error)
                case .cancelled:
                    print("User cancelled login.")
                case .success(let grantedPermissions, let declinedPermissions, let accessToken):
                    self.userId = accessToken.userId ?? ""
                    self.grantedPermissions = grantedPermissions
                    self.declinedPermissions = declinedPermissions
                    print("Logged in!")
                }
            }
        }
    
        public func getUserId() -> String {
            return userId
        }
    
        public func getUserInfo(withCompletionHandler completionHandler: @escaping (_ userInfo: [String: Any]?) -> ()) {
            let request = GraphRequest(graphPath: "me", parameters: ["fields":"email, name"], accessToken: AccessToken.current, httpMethod: .GET, apiVersion: FacebookCore.GraphAPIVersion.defaultVersion)
            request.start { (response, result) in
                switch result {
                case .success(let value):
                    print(value.dictionaryValue)
                    completionHandler(value.dictionaryValue)
                case .failed(let error):
                    print(error)
                }
            }
        }
    
        public func createLoginButton(_ frame: CGRect, withCompletionHandler completionHandler: @escaping (_ loginButton: UIView) -> ()) {
            let permissions: [ReadPermission] = [.publicProfile, .userFriends, .email]
            let loginButton = LoginButton(readPermissions: permissions)
            loginButton.frame = frame
            completionHandler(loginButton)
        }
    }
    

    In my ViewController:

    When I use:

    let facebookLoginProvider = LoginProvider(strategy: FacebookLoginStrategy())
    

    It says:

    'FacebookLoginStrategy' is inaccessable due to 'internal' protection level

  • Paul Razvan Berg
    Paul Razvan Berg almost 7 years
    Great answer! And watch out for Swift4, it's actually an error if you don't implement it.
  • jboi
    jboi over 6 years
    Just into the class.
  • LightningStryk
    LightningStryk about 5 years
    this is so dumb that Swift requires this. If I declare the whole class type public, the free init() should come as public as well
  • lee
    lee over 4 years
    This should a bug of Swift. It should not an error of compiler, since we had marked public for class/struct.
  • jboi
    jboi over 4 years
    Just learned, that it also works for structs. Got the error-message, was confused, googled and found my own answer. It's getting late on a Friday...
  • AndreG
    AndreG over 4 years
    I've added public before my init and I am still getting that same message. Is there another protection?
  • jboi
    jboi over 4 years
    Hi @AndreG , can you share some code with us? Maybe just ask your question.
  • fredy
    fredy over 2 years
    Thank you so much.
  • Peter Schorn
    Peter Schorn over 2 years
    @lee It's not dumb, nor is it a bug. Sometimes you don't want the initializers for a type to be public. It's easy to forget about the existence of synthesized initializers because they don't actually appear in your code. Therefore, if these initializers were public, it'd be easy to accidentally expose them outside of the module.