No se puede acceder al inicializador debido al nivel de protección 'interno'

89

Tengo algunos protocolos

Iniciar sesión

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
}

y dos clases:

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
    }

}

FacebookIniciar sesiónEstrategia

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)
    }
}

En mi ViewController :

Cuando uso:

let facebookLoginProvider = LoginProvider(strategy: FacebookLoginStrategy())

Dice:

'FacebookLoginStrategy' no es accesible debido al nivel de protección 'interno'

appiconhero.co
fuente

Respuestas:

250

Simplemente agregue a su FacebookLoginStrategy:

public init() {}

Siempre que no implemente init () explícitamente, se marca como interno de forma predeterminada. Debe sobrescribir ese nivel de permiso para poder crear una instancia desde fuera de su marco.

jboi
fuente
13
¡Gran respuesta! Y tenga cuidado con Swift4, en realidad es un error si no lo implementa.
Paul Razvan Berg
2
Solo en la clase.
jboi
12
esto es tan tonto que Swift lo requiere. Si declaro público todo el tipo de clase, el init () gratuito también debería ser público
LightningStryk
3
Esto debería ser un error de Swift. No debería ser un error de compilador, ya que lo habíamos marcado publicpara class/struct.
lee
1
Agregué público antes de mi inicio y sigo recibiendo el mismo mensaje. ¿Existe otra protección?
AndreG
8

Si está ejecutando esto en código dentro de un XCTestCase, asegúrese de haberlo agregado @testable import My-Awesome-Appal principio de su archivo de prueba.

Alex Zavatone
fuente