In the current version of FacebookLogin (0.2.0) for Swift, the delegate property of LoginButton is defined as a strong property:
public class LoginButton: UIView { ... /// Delegate of the login button that can handle the result, logout events. public var delegate: LoginButtonDelegate? ... }
If you add the login button following the instructions of Facebook and you set the child class of the UIViewController as the delegate of the button ...
import FacebookLogin func viewDidLoad() { let loginButton = LoginButton(readPermissions: [ .PublicProfile ]) loginButton.center = view.center loginButton.delegate = self view.addSubview(loginButton) }
... a reference cycle will be created. The view will contain a strong link to the button, the button will contain a strong link to the controller, and the controller will have a strong link to its view, see this post .
My solution was to use a weak member variable to have a link to the login button, and when the view disappears, the button delegate is set to zero, for example:
import UIKit import FacebookCore import FacebookLogin import RxSwift class LoginViewController: UIViewController, LoginButtonDelegate { private weak var facebookLoginButton: LoginButton? = nil override func viewDidLoad() { super.viewDidLoad() // Add the Facebook login button let loginButton = LoginButton(readPermissions: [ .publicProfile, .email, .userFriends ]) loginButton.center = view.center // WARNING!: Facebook login button delegate property is defined currently as STRONG. // Therefore, it must be set to nil before leaving the view to avoid reference cycles loginButton.delegate = self view.addSubview(loginButton) // Store the login button as a weak reference, since it is holded by the main view with a // strong reference facebookLoginButton = loginButton } override func willMove(toParentViewController parent: UIViewController?) { super.willMove(toParentViewController:parent) if parent == nil { // The back button was pressed, interactive gesture used, or programatically pop view // was executed // Do not forget to set delegate in Facebook button to nil to break reference cycle. facebookLoginButton?.delegate = nil } } // MARK: - Facebook login /** Called when the button was used to login and the process finished. - parameter loginButton: Button that was used to login. - parameter result: The result of the login. */ func loginButtonDidCompleteLogin(_ loginButton: LoginButton, result: LoginResult) { switch result { case .failed(let error): // Action on failed case .cancelled: // Action on cancelled case .success(let grantedPermissions, let declinedPermissions, let accessToken): // Action on success } } /** Called when the button was used to logout. - parameter loginButton: Button that was used to logout. */ func loginButtonDidLogOut(_ loginButton: LoginButton) { // Action on logout } }
Do not use the viewWillDissapear() function to set the delegate to nil , because the Facebook login page will be displayed on top of your application, running this function, and you will not get the login result, since you will not be a delegate. Note that this solution works great for views inside the navigation controller. Another solution should be found for modal windows.
Hope this helps, Xavi