Twitter khuong291
Twitter khuong291

Reputation: 11702

Initializer is inaccessable due to 'internal' protection level

I have a protocol

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

Upvotes: 146

Views: 132928

Answers (4)

Aravind Samala
Aravind Samala

Reputation: 317

In case anyone faces this issue when implementing Swift packages for building reusable SwiftUI views, there are a couple of things to keep in mind.

  1. If there are component props that are being set from the parent component, don't forget to add them to the constructor
  2. If the property is wrapped with @State, then assign the state to the underlying object as shown below.
public struct Layout: View {
    @State var layout: NavType = .TOP
    var navItems: [NavItemObject]
    public init(layout: NavType, navItems: [NavItemObject]) {
        _layout = State(initialValue: layout);
        self.navItems = navItems;
    }
}

Upvotes: 6

Yogesh Rathore
Yogesh Rathore

Reputation: 183

Add init method as Public access

public init() {}

Upvotes: 8

Alex Zavatone
Alex Zavatone

Reputation: 4323

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.

Upvotes: 24

jboi
jboi

Reputation: 11912

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.

Upvotes: 381

Related Questions