Make UIImageView act as Facebook Login Button - ios

Within my main.storyboard I have a UIImage view which is just a generic Facebook Login Button. However, I am confused because using these generic steps
override func viewDidLoad(){
{
super.viewDidLoad()
var imageView = <# imageView #>
let tapGestureRecognizer = UITapGestureRecognizer(target:self, action:Selector("imageTapped:"))
imageView.userInteractionEnabled = true
imageView.addGestureRecognizer(tapGestureRecognizer)
}
func imageTapped(img: AnyObject)
{
// The Action
}
I am a little lost as to what The Action would be in this scenario as I need to link everything through the Facebook SDK.

In your imageTapped
func imageTapped() {
let manager = FBSDKLoginManager()
manager.logInWithReadPermissions(["public_profile"], fromViewController: self, handler: { result, error in
if error != nil {
print("process error")
} else if result.isCancelled {
print("cancelled log in")
} else {
print("logged in")
}
})
}

Related

Issue with FB Login

Hellos developers,
who anyone can help me with one issue , I try to make a Facebook login and after that I want to go to another view.
But I can't make that happens, could some one can help me with that?
I put my code below:
import UIKit
import FBSDKLoginKit
import FBSDKCoreKit
class ViewController: UIViewController , LoginButtonDelegate{
func loginButton(_ loginButton: FBLoginButton, didCompleteWith result: LoginManagerLoginResult?,
error: Error?) {
loginButton.permissions = ["public_profile","email"]
if error != nil {
print("Something is Wrong... \(String(describing: error))")
return
}
print("Succesful loged in !")
}
func loginButtonDidLogOut(_ loginButton: FBLoginButton) {
loginButton.titleLabel?.text = "Adios"
print("GoodBye ")
}
override func viewDidLoad() {
super.viewDidLoad()
let loginButton = FBLoginButton()
loginButton.center = view.center
view.addSubview(loginButton)
loginButton.permissions = ["public_profile", "email"]
loginButton.addTarget(self, action: #selector(getUserFBInfo), for: .touchUpOutside)
}
#objc func getUserFBInfo(){
print("se logro ")
let token = AccessToken.current
if token == AccessToken.current {
performSegue(withIdentifier: "secondActivity", sender: self)
}else if token!.isExpired{
print("no sucede nada")
}
}
}
If you want the LoginButtonDelegate to call your delegate function (e.g. loginbutton:didCompleteWithResult:error:), remember to assign the delegate to the FBLoginButton.
In the above code, since the delegate is the UIViewController itself (not a must), you will need to add loginButton.delegate = self

Only instance methods can be declared #IBAction error?

I am facing this error on build for the function shown in the code
Only instance methods can be declared #IBAction
this error is coming up only after I introduced google sign in method for similar functionality , earlier it not an error
#IBAction func SignInButtonAction(_ sender: Any) {
guard let email = emailField.text else { return }
guard let pass = passwordField.text else { return }
Auth.auth().signIn(withEmail: email, password: pass) { user, error in
if error == nil && user != nil {
let setupcheckref = Firestore.firestore().collection("users").document(Auth.auth().currentUser!.uid)
setupcheckref.getDocument{(document, error) in
if let document = document, document.exists{
let dataDescription = document.data().map(String.init(describing:)) ?? "nil"
self.checksetup = document.get("setupComplete") as! Bool
if self.checksetup == true {
if Auth.auth().currentUser!.isEmailVerified {
self.performSegue(withIdentifier: "toLoginFeed", sender: self)
}
else{
print("please verify your email")
try! Auth.auth().signOut()
}
}
else{
self.view.makeToast("Please Setup Your Account!", duration: 2.5)
self.performSegue(withIdentifier: "fromlogintosetup", sender: self)
SVProgressHUD.dismiss()
} }
}
// self.dismiss(animated: false, completion: nil)
} else {
print("Error logging in: \(error!.localizedDescription)")
// self.resetForm()
// SVProgressHUD.dismiss()
}
}
}
That means you can create #IBActions only as instance methods of a class.
You might be creating it of a class.
class VC: UIViewController {
#IBAction func SignInButtonAction(_ sender: Any) {
//your code...
}
}

I can't execute functions from a ViewController in an different one

Can someone help me execute functions from one VC in another VC.
The function from the first VC needs to be executed once I press a button in the second VC.
Im trying with "viewcontroller().function()" function but it's not working properly, printing and basic stuff works but when it comes to stuff like drawing direction it's not working.
The function that draws directions is:
func directionToPin() {
guard let currentPlacemark = currentPlacemark else {
print("Error, the current Placemark is: \(self.currentPlacemark)")
return
}
let directionRequest = MKDirections.Request()
let destinationPlacemark = MKPlacemark(placemark: currentPlacemark)
directionRequest.source = MKMapItem.forCurrentLocation()
directionRequest.destination = MKMapItem(placemark: destinationPlacemark)
directionRequest.transportType = .walking
//calculate route
let directions = MKDirections(request: directionRequest)
directions.calculate{ (directionsResponse, error) in
guard let directionsResponse = directionsResponse else {
if let error = error {
print("error getting directions: \(error.localizedDescription)")
}
return
}
let route = directionsResponse.routes[0]
if self.drawedDriection == false {
self.drawedDriection = true
if self.didSelectAnnotation == true {
self.mapView.addOverlay(route.polyline, level: .aboveRoads)self.navigationBarController.directionButtonOutlet.setImage(UIImage(named: "navigationBarDirectionButtonRed")?.withRenderingMode(.alwaysOriginal), for: .normal)
self.mapView.setRegion(MKCoordinateRegion(routeRect), animated: true)
}
} else {
self.drawedDriection = false
self.mapView.removeOverlays(self.mapView.overlays)
if self.didSelectAnnotation == true {
self.navigationBarController.directionButtonOutlet.setImage(UIImage(named: "navigationBarDirectionButtonBlue")?.withRenderingMode(.alwaysOriginal), for: .normal)
} else {
self.navigationBarController.directionButtonOutlet.setImage(UIImage(named: "navigationBarDirectionButtonGray")?.withRenderingMode(.alwaysOriginal), for: .normal)
}
}
}
}
I'm calling the function in the second VC once I press a button:
#IBAction func directionButton(_ sender: Any) {
MapViewController().directionToPin()
}
When I run the app and press the button the currentPlacemark is nil, if I run the same function via a button in my first VC (the VC with the directionToPin function inside)
here is my repo if you need it: https://github.com/octavi42/xCodeMapsApp
Thanks!
I think that you need to use Protocols and Delegates to achieve what you desire.
#IBAction func directionButton(_ sender: Any) {
MapViewController().directionToPin()
}
In the above code snippet, you are instantiating a new instance of MapViewController which upon initialization resets currentPlacemark and hence you've encountered nil.
My suggestion is to create a new protocol to communicate from MapViewController to CardViewController just like this
Add these in MapViewController.swift
protocol MapNavigationDelegate: AnyObject {
func didTapDirectionButton()
}
class MapViewController: UIViewController {
// .... Some code ....
override func viewDidLoad() {
// . .... Some more code .......
navigationBarController.mapNavigationDelegate = self
}
}
extension MapViewController: MapNavigationDelegate {
func didTapDirectionButton() {
self.directionToPin()
}
}
Add these in CardViewController.swift
class CardViewController: UIView {
// .... Some Code ....
weak var mapNavigationDelegate: MapNavigationDelegate!
#IBAction func directionButton(_ sender: Any) {
self.mapNavigationDelegate.didTapDirectionButton()
}
}

removeFromSuperview() not working

I wanted to blur the background when the touch id is asked and once the authorization is successfull, the viewcontroller needs to be visible.But this is not happening.The viewcontroller is still blurred even if authorization is successfull.Can anyone help me on how to solve this?
import UIKit
import LocalAuthentication
class TabBarViewController: UITabBarController {
#IBOutlet weak var noteTabBar: UITabBar!
override func viewDidLoad() {
super.viewDidLoad()
self.authenticateUser()
self.tabBar.hidden = false
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
let userDefaults = NSUserDefaults.standardUserDefaults()
userDefaults.setObject(false, forKey: "sendModeToggle")
userDefaults.setObject("Avenir-Medium", forKey: "font")
userDefaults.setObject(13, forKey:"fontSize")
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
// MARK: Touch ID Authentication
func authenticateUser()
{
let context = LAContext()
var error: NSError?
let reasonString = "Authentication is needed to access your app! :)"
let blurEffect = UIBlurEffect(style: .Light)
let blurVisualEffectView = UIVisualEffectView(effect: blurEffect)
blurVisualEffectView.frame = view.bounds
self.view.addSubview(blurVisualEffectView)
if context.canEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, error: &error)
{
context.evaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, localizedReason: reasonString, reply: { (success, policyError) -> Void in
if success
{
print("Authentication successful! :) ")
blurVisualEffectView.removeFromSuperview()
}
else
{
switch policyError!.code
{
case LAError.SystemCancel.rawValue:
print("Authentication was cancelled by the system.")
/*case LAError.UserCancel.rawValue:
print("Authentication was cancelled by the user.")
*/
case LAError.UserFallback.rawValue:
print("User selected to enter password.")
NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
self.showPasswordAlert()
blurVisualEffectView.removeFromSuperview()
})
default:
print("Authentication failed! :(")
NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
self.showPasswordAlert()
blurVisualEffectView.removeFromSuperview()
})
}
}
})
}
else
{
print(error?.localizedDescription)
NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
self.showPasswordAlert()
})
}
}
}
Since you are removing view in closure, you probably not in main thread. Try to dispatch removing code to main thread:
if success {
print("Authentication successful! :) ")
dispatch_async(dispatch_get_main_queue()) {
blurVisualEffectView.removeFromSuperview()
}
}

Possible Facebook documentation error that stops swift code from compiling?

So I am following the Facebook documentation on how to add a custom login button in iOS but I am not sure if this is a documentation error or something is up with what I had written into my project. I have followed it for verbatim.
I get errors at these lines:
"Extra argument in call ["public_profile", "user_friends", "email"]"
func loginButtonClicked() {
var login: FBSDKLoginManager = FBSDKLoginManager()
FBSDKLoginManager.logInWithReadPermissions(["public_profile", "user_friends", "email"], fromViewController: self) { (result, error) -> Void in
if let result = result where error == nil && !result.isCancelled {
// Successful login
} else {
// Canceled or error
}
}
};
}
Here below is what the rest of the ViewController looks like:
class LogInViewController: UIViewController {
#IBOutlet weak var loginButton: FBSDKLoginButton!
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
}
override func viewDidLoad() {
["public_profile", "email", "user_friends"]
super.viewDidLoad()
// Add a custom login button to your app
let myLoginButton: UIButton = UIButton(type: .Custom)
myLoginButton.backgroundColor = UIColor.darkGrayColor()
myLoginButton.frame = CGRectMake(0, 0, 180, 40)
myLoginButton.center = self.view.center
myLoginButton.setTitle("My Login Button", forState: .Normal)
// Handle cliks on the button
myLoginButton.addTarget(self,action: "loginButtonClicked", forControlEvents: .TouchUpInside)
// Add the button to the view
self.view!.addSubview(myLoginButton)
}
// Once the button is clicked, show the login dialogue.
func loginButtonClicked() {
var login: FBSDKLoginManager = FBSDKLoginManager()
FBSDKLoginManager.logInWithReadPermissions(["public_profile", "user_friends", "email"] /*Extra argument in call is here */, fromViewController: self) { (result, error) -> Void in
if let result = result where error == nil && !result.isCancelled {
// Successful login
} else {
// Canceled or error
}
}
};
}
TL;DR what is the exact problem and what is Xcode trying to tell me?
The Error is very simple that you are not parsing Object of FBSDKLoginManager that you are creating with following line:
var login: FBSDKLoginManager = FBSDKLoginManager()
So do the code like following:
func loginButtonClicked() {
let login: FBSDKLoginManager = FBSDKLoginManager()
login.logInWithReadPermissions(["public_profile", "email", "user_friends"], fromViewController: self) { (result, error) -> Void in
if let result = result where error == nil && !result.isCancelled {
// Successful login
} else {
// Canceled or error
}
}
}
Seems like the problem is the way you call the loginWithPermissions method. You could try writing it again, let xcode autocomplete for you and then press enterfor all the parameters, so that the right code is filled in for you.
However, this is an example of how calling the method should look like
loginManager.logInWithReadPermissions(["public_profile", "user_friends", "email"], fromViewController: self) { (result, error) -> Void in
if let result = result where error == nil && !result.isCancelled
// Successful login
} else {
// Canceled or error
}
}
Hope this helps you figure out your error. Let me know if it worked out :)

Resources