Inicjator jest niedostępny z powodu „wewnętrznego” poziomu ochrony

89

Mam kilka protokołów

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
}

i dwie klasy:

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

W moim ViewController :

Kiedy używam:

let facebookLoginProvider = LoginProvider(strategy: FacebookLoginStrategy())

To mówi:

„FacebookLoginStrategy” jest niedostępny ze względu na „wewnętrzny” poziom ochrony

appiconhero.co
źródło

Odpowiedzi:

250

Po prostu dodaj do swojej strategii FacebookLoginStrategy:

public init() {}

Dopóki nie zaimplementujesz jawnie init (), jest ona domyślnie oznaczana jako wewnętrzna. Musisz nadpisać ten poziom uprawnień, aby móc utworzyć wystąpienie spoza struktury.

jboi
źródło
13
Świetna odpowiedź! Uważaj na Swift4, to właściwie błąd, jeśli go nie zaimplementujesz.
Paul Razvan Berg,
2
Tylko do klasy.
jboi,
12
to jest tak głupie, że Szybki tego wymaga. Jeśli zadeklaruję publicznie cały typ klasy, wolna init () również powinna być publiczna
LightningStryk
3
To powinien być błąd Swift. Powinien on nie błąd kompilatora, ponieważ mieliśmy zaznaczone publicna class/struct.
lee
1
Dodałem publiczny przed inicjalizacją i nadal otrzymuję tę samą wiadomość. Czy jest inna ochrona?
AndreG,
8

Jeśli uruchamiasz to w kodzie w ramach XCTestCase, upewnij się, że dodano @testable import My-Awesome-Appna początku pliku testowego.

Alex Zavatone
źródło