Swift - Firebase Getting a Facebook Friends UID in Firestore - swift

For a little background - I have a 'Follow Facebook Friends' ViewController where users can view their friends who also have downloaded my app to follow on the app.
I have correctly called the FBSDK to get a list of friends that have also downloaded the app, but now I need to get these friends uid's in Firebase so I can follow/unfollow them accordingly.
Currently, when I get a FB users id - I get the numeric string as mentioned in the facebook documentation. However, the users uid in Firebase is different. Is there a way to find which firebase user correlates with a FB id? Or should I try to store a Facebook User by facebook id in firebase?
var facebookContacts = [User]()
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "facebookContactCell", for: indexPath) as! FacebookContactCell
// Configure the cell...
let user = facebookContacts[indexPath.row]
cell.contactNameLabel.text = user.name
cell.userId = user.documentId
// Set follow button state
if followingArray.contains(cell.userId) {
cell.followButton.isSelected = true
} else {
cell.followButton.isSelected = false
}
let userImageRef = storage.child("userImages/"+(user.documentId)+"/profile_pic.jpg")
// Download in memory with a maximum allowed size of 1MB (1 * 1024 * 1024 bytes)
userImageRef.getData(maxSize: 1 * 1024 * 1024) { (data, error) in
if let error = error {
// Uh-oh, an error occurred! Display Default image
print("Error - unable to download image: \(error)")
cell.contactImageView.image = UIImage(named: "userProfileGray")
} else {
// Data for "locationImages/(locationId).jpg" is returned
cell.contactImageView.image = UIImage(data: data!)
}
SVProgressHUD.dismiss()
}
return cell
}
func getFbFriends() {
let params = ["fields": "id, first_name, last_name, name, email, picture"]
let graphRequest = FBSDKGraphRequest(graphPath: "/me/friends", parameters: params)
let connection = FBSDKGraphRequestConnection()
connection.add(graphRequest, completionHandler: { (connection, result, error) in
if error == nil {
let resultdict = result as! NSDictionary
print("Result Dict: \(resultdict)")
let data : NSArray = resultdict.object(forKey: "data") as! NSArray
for i in 0..<data.count {
let valueDict : NSDictionary = data[i] as! NSDictionary
let id = valueDict.object(forKey: "id") as! String
print("the id value is \(id)")
let name = valueDict.object(forKey: "name") as! String
print("the name value is \(name)")
let picDict = valueDict["picture"] as! NSDictionary
let picData = picDict["data"] as! NSDictionary
let picURL = picData.object(forKey: "url") as! String
print("the url value is \(picURL)")
self.facebookContacts.append(User(name: name, documentId: id))
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
let friends = resultdict.object(forKey: "data") as! NSArray
print("Found \(friends.count) friends")
} else {
print("Error Getting Friends \(String(describing: error))");
}
})
connection.start()
}

I do not think that you can get the UID of your user based on their Facebook ID. It seems that you have two possibilities:
Search by email. This should allow you to pinpoint the person you are looking for.
Implement custom Facebook authentication. It requires a little extra work but is not too difficult to do.

Related

CollectionViewCell loading with nil value after reloadData func

I made a function to fetch data for an empty array that I'm using for a collectionView. I'm pulling the information from two different child nodes. The first being the "users" tree and the second being the "profile_images", using the UID from users to find the corresponding images. The cell populates when the view loads. My issue is that when the cell populates, I'm getting a nil value for one of the values.
I tried to add the array to the collectionViewCell instead of the view controller. I've also been reading the developer notes on prefetching data but it makes it seems like it's used for cells that have yet to be loaded.
var matches = [MatchData]()
// function to retrieve firebase data
private func populateInbox() {
if let uid = Auth.auth().currentUser?.uid {
// Supply Matches for users first
let match = MatchData()
Database.database().reference().child("users").observe(.childAdded) { (snapshot) in
let matichUID = snapshot.key
if matichUID != uid {
Database.database().reference().child("profile_images").child(matichUID).observeSingleEvent(of: .value, with: { (data) in
if let imageDict = data.value as? [String: AnyObject] {
match.matchImage = imageDict["imageOne"] as? String
print(match.matchImage)
}
})
if let dictionary = snapshot.value as? [String: AnyObject] {
print(uid, dictionary)
match.matchName = dictionary["firstName"] as? String
self.matches.append(match)
}
}
DispatchQueue.main.async {
self.matchList.reloadData()
print(self.matches.count)
}
}
}
}
// function to convert image url into UIImage
private func icon(_ imageURL: String, imageView: UIImageView) {
let url = URL(string: imageURL)
var image: UIImage?
var imageData:Data?
if url == nil {
print("Code failed here...")
imageView.image = #imageLiteral(resourceName: "ic_person_outline_white_2x")
} else {
URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error != nil {
print("error")
DispatchQueue.main.async {
imageView.image = UIImage(imageLiteralResourceName: "ic_person_outline_white_2x")
}
} else {
DispatchQueue.main.async {
imageData = data
image = UIImage(data: imageData!)
imageView.image = image!
}
}
}.resume()
}
}
// Data model
class MatchData: NSObject {
var matchImage: String?
var matchName: String?
}
// additional details
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "InboxCell", for: indexPath) as! InboxCell
let matchInfo = matches[indexPath.row]
cell.userLabel.text = matchInfo.matchName
icon(matchInfo.matchImage ?? "", imageView: cell.userImage)
//icon always returns nil value but Userlabel returns name value
return cell
}
The expected result is to have a cell that displays images along with the name of the user the image belongs too. The actual results is the name of the users profile and a nil value for the image.
It looks like you append match to your matchlist before your observeSingleEventOf callback completes. Match updates when the image is received, but has already been added.
if let dictionary = snapshot.value as? [String: AnyObject] {
match.matchName = dictionary["firstName"] as? String
}
if matchUID != uid {
Database.database().reference().child("profile_images").child(matichUID).observeSingleEvent(of: .value, with: { (data) in
if let imageDict = data.value as? [String: AnyObject] {
match.matchImage = imageDict["imageOne"] as? String
}
self.matches.append(match)
DispatchQueue.main.async {
self.matchList.reloadData()
}
})
} else {
self.matches.append(match)
DispatchQueue.main.async {
self.matchList.reloadData()
}
}

Swift SDWebImage in a closure block

I am attempting to use SDWebImage in a closure block after fetching userInfo from Firebase. However, doing so will result in the images and cell labels to blink as I scroll the tableView when the cells are attempting to redraw themselves.
let expiredConversationsCell = tableView.dequeueReusableCell(withIdentifier: "expiredConversationsCell", for: indexPath) as! ExpiredConversationsTableViewCell
let conversation = allConversations[0][indexPath.row]
guard let recipientID = conversation.recipientID else {return UITableViewCell()}
FirebaseClient.shared.getUserInfo(recipientID, { (results, error) in
if let error = error {
print(error.localizedDescription)
} else if let results = results {
let username = results["username"] as! String
let profileImageUrl = results["profileImageUrl"] as! String
DispatchQueue.main.async {
expiredConversationsCell.profileImageView.sd_setImage(with: URL(string: profileImageUrl), completed: nil)
expiredConversationsCell.recipientNameLabel.text = username
}
}
})
return expiredConversationsCell
Is there a way to implement SDWebImages under such circumstances? Any advice would be great. Thanks.

Get Facebook profile picture from URL

I want to upload the profile picture from Facebook to Firebase. I tried this answer: Upload Facebook image URL to Firebase Storage
However, Swift is giving me errors on the third line of code of that answer. The code is:
let dictionary = result as? NSDictionary
let data = dictionary?.object(forKey: "data")
let urlPic = (data?.objectForKey("url"))! as! String
Swift is telling me: Cannot call value of non-function type 'Any?!' after I changed the code to what Swift keeps suggesting me:
let urlPic = ((data as AnyObject).object(ForKey: "url"))! as! String
What is the code to use when I want to retrieve the profile picture from Facebook? My goal is to also store it into Firebase, but that will come after I get the profile picture first.
The answer is in Swift 1.2
I took reference here and implemented also
You can do this:
// accessToken is your Facebook id
func returnUserProfileImage(accessToken: NSString)
{
var userID = accessToken as NSString
var facebookProfileUrl = NSURL(string: "http://graph.facebook.com/\(userID)/picture?type=large")
if let data = NSData(contentsOfURL: facebookProfileUrl!) {
imageProfile.image = UIImage(data: data)
}
}
This is the way I got Facebook id:
func returnUserData()
{
let graphRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: nil)
graphRequest.startWithCompletionHandler({ (connection, result, error) -> Void in
if ((error) != nil)
{
// Process error
println("Error: \(error)")
}
else
{
println("fetched user: \(result)")
if let id: NSString = result.valueForKey("id") as? NSString {
println("ID is: \(id)")
self.returnUserProfileImage(id)
} else {
println("ID es null")
}
}
})
}

Pulling Facebook profile pic with parse using Swift

I'm trying to pull the username and profile picture for my apps profile page. I'm using Parse and the Facebook SDK.
I have a UILabel and a UIView connected as outlets.
When I try to set the profileImageView, it gives me the error "Value of type 'UIImageView' has no member 'setImageWithURL'" Is this an upgrade with Swift?
Here is my code...
func setProfilePicture() {
FBSDKGraphRequest(graphPath: "me", parameters: nil).startWithCompletionHandler({ (connection, result, error) -> Void in
if let dict = result as? Dictionary<String, AnyObject> {
let name: String = dict["name"] as! String
let facebookID: String = dict["id"] as! String
let pictureUrl = "https://graph.facebook.com/\(facebookID)/picture?type=large&return_ssl_resources=1"
self.profileImageView.setImageWithURL(NSURL(string: pictureUrl)!)
self.nameLabel.text = name
PFUser.currentUser()!.setValue(name, forKey: "name")
PFUser.currentUser()!.saveInBackground()
}
})
}
if let url = NSURL(string: "https://graph.facebook.com/\(facebookID)/picture?type=large&return_ssl_resources=1") {
if let data = NSData(contentsOfURL: url){
self.profileImageView.contentMode = UIViewContentMode.ScaleAspectFit
self.profileImageView.image = UIImage(data: data)
}
}
Try creating a function, fbProfilePicURL, that takes a Facebook ID and returns the profile picture URL as an NSURL, then change
self.profileImageView.setImageWithURL(NSURL(string: pictureUrl)!)
to
self.profileImageView.setImageWithURL(NSURL.fbProfilePicURL(facebookID))
Not 100% sure on this, but let me know if it works.

Can't pinpoint FBSDKGraphRequest crash

I'm using FB Login, and my app is crashing every now and then within that method. It works fine for me, but not for some other users. In this function, I'm setting user data in Parse with data received from the FBSDKGraphRequest.
// Sends FB Graph Request and sets user attributes in Parse
func setUserData() {
var user = PFUser.currentUser()!
let graphRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: nil)
graphRequest.startWithCompletionHandler({ (connection, result, error) -> Void in
if ((error) != nil)
{
println("Set user values error: \(error)")
}
else
{
firstName = result.valueForKey("first_name") as! NSString
lastName = result.valueForKey("last_name") as! NSString
user["name"] = "\(firstName) \(lastName)"
NSUserDefaults.standardUserDefaults().setObject("\(firstName) \(lastName)", forKey: "name")
id = result.valueForKey("id") as! NSString
user["fbID"] = id
gender = result.valueForKey("gender") as! NSString
user["gender"] = gender
email = result.valueForKey("email") as! NSString
user["email"] = email
user["score"] = 100
user.saveInBackgroundWithBlock({ (success, error) -> Void in
if success {
objID = user.objectId!
}
})
self.performSegueWithIdentifier("segue", sender: self)
}
})
}
Now, in Crashlytics, I'm getting EXC_BREAKPOINT, but can't figure out exactly where the crash is coming from or what to do about it. Looks like it may be coming from Facebook's side? Any help would be appreciated.
I've had the same issue. I forgot to put the permissions on the FBSDKLoginButton:
facebookLoginButton.readPermissions = ["public_profile", "email", "user_friends"];
Maybe you forgot it too?