Initializer ไม่สามารถเข้าถึงได้เนื่องจากระดับการป้องกัน "ภายใน"


92

ฉันมีโปรโตคอลบางอย่าง

เข้าสู่ระบบกลยุทธ์

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
}

และสองคลาส:

เข้าสู่ระบบ

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
    }

}

Facebook เข้าสู่ระบบกลยุทธ์

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' ไม่สามารถเข้าถึงได้เนื่องจากระดับการป้องกัน 'ภายใน'

คำตอบ:


258

เพียงเพิ่ม FacebookLoginStrategy ของคุณ:

public init() {}

ตราบเท่าที่คุณไม่ได้ใช้ init () อย่างชัดเจนระบบจะทำเครื่องหมายเป็นภายในโดยค่าเริ่มต้น คุณต้องเขียนทับระดับสิทธิ์นั้นจึงจะสามารถสร้างอินสแตนซ์จากภายนอกกรอบงานของคุณได้


13
ตอบโจทย์มาก! และระวัง Swift4 จริงๆแล้วมันเป็นข้อผิดพลาดหากคุณไม่ได้ใช้มัน
Paul Razvan Berg

2
เพียงแค่เข้าสู่ชั้นเรียน
jboi

15
มันโง่มากที่ Swift ต้องการสิ่งนี้ ถ้าฉันประกาศประเภททั้งคลาสเป็นสาธารณะ, init () ฟรีควรเป็นแบบสาธารณะเช่นกัน
LightningStryk

3
นี่ควรเป็นจุดบกพร่องของ Swift. ไม่ควรเป็นข้อผิดพลาดของคอมไพเลอร์เนื่องจากเราได้ทำเครื่องหมายpublicสำหรับclass/struct.
lee

1
ฉันได้เพิ่มสาธารณะก่อนเริ่มต้นและฉันยังคงได้รับข้อความเดียวกัน มีความคุ้มครองอื่นอีกหรือไม่?
AndreG

8

หากคุณกำลังเรียกใช้โค้ดภายใน XCTestCase ตรวจสอบให้แน่ใจว่าคุณได้เพิ่ม@testable import My-Awesome-Appไว้ที่ด้านบนสุดของไฟล์ทดสอบแล้ว

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.