Инициализатор недоступен из-за «внутреннего» уровня защиты

У меня есть протоколы

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
}

и два класса:

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

В моем ViewController:

Когда я использую:

let facebookLoginProvider = LoginProvider(strategy: FacebookLoginStrategy())

Он говорит:

FacebookLoginStrategy недоступен из-за «внутреннего» уровня защиты


person appiconhero.co    schedule 29.11.2016    source источник


Ответы (2)


Просто добавьте в свою FacebookLoginStrategy:

public init() {}

Пока вы не реализуете init () явно, он по умолчанию помечен как внутренний. Вам необходимо перезаписать этот уровень разрешений, чтобы иметь возможность создавать экземпляры извне.

person jboi    schedule 29.11.2016
comment
Отличный ответ! И следите за Swift4, на самом деле это ошибка, если вы его не реализуете. - person Paul Razvan Berg; 10.08.2017
comment
Просто в класс. - person jboi; 10.02.2018
comment
это настолько глупо, что этого требует Swift. Если я объявлю весь тип класса общедоступным, бесплатная init () также должна стать общедоступной. - person LightningStryk; 16.05.2019
comment
Это должно быть ошибкой Swift. Это не должно быть ошибкой компилятора, поскольку мы пометили public вместо class/struct. - person lee; 31.10.2019
comment
Только что узнал, что это также работает для structs. Получил сообщение об ошибке, запутался, погуглил и нашел свой ответ. В пятницу уже поздно ... - person jboi; 01.11.2019
comment
Я добавил public перед своей инициализацией и все еще получаю то же сообщение. Есть ли другая защита? - person AndreG; 13.11.2019
comment
Привет, @AndreG, можешь поделиться с нами кодом? Может просто задать свой вопрос. - person jboi; 13.11.2019

Если вы выполняете это в коде в XCTestCase, убедитесь, что вы добавили @testable import My-Awesome-App в начало тестового файла.

person Alex Zavatone    schedule 16.12.2019