106 votes

L'initialisateur est inaccessible en raison du niveau de protection "interne".

J'ai quelques protocoles

Stratégie de connexion

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
}

et deux 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
    }

}

FacebookLoginStratégie

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

Dans mon ViewController :

Quand je l'utilise :

let facebookLoginProvider = LoginProvider(strategy: FacebookLoginStrategy())

C'est écrit :

FacebookLoginStrategy" est inaccessible en raison d'une protection "interne". interne

283voto

jboi Points 2810

Il suffit de l'ajouter à votre stratégie de connexion à Facebook :

public init() {}

Tant que vous n'implémentez pas explicitement init(), il est marqué comme interne par défaut. Vous devez écraser ce niveau de permission pour pouvoir l'instancier depuis l'extérieur de votre framework.

13 votes

Excellente réponse ! Et attention à Swift4, c'est en fait une erreur si vous ne l'implémentez pas.

2 votes

Juste dans la classe.

22 votes

C'est tellement stupide que Swift exige ça. Si je déclare le type de classe entier public, le init() gratuit devrait être public également.

13voto

Alex Zavatone Points 901

Si vous vous heurtez à ce problème dans le code d'un XCTestCase, assurez-vous d'avoir ajouté l'option @testable import My-Awesome-App en haut de votre fichier de test.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X