Swift Tutorial: Build a Facebook Album Browser – Part 2

Hello folks, in this latest addition of our Swift tutorial series we will take creating the Facebook album browser into a next level. I have seen a lot of request regarding my previous article ‘Build a facebook album browser using Swift‘ to update it in regard of Facebook SDK v4.4. In this tutorial, not only I have updated the Facebook iOS SDK into latest version but also used latest version of Swift and added some more features. I am sorry for keeping you guys waiting so long but finally I have squeezed out some time to respond to your requests. […]

Hello folks, in this latest addition of our Swift tutorial series we will take creating the Facebook album browser into a next level. I have seen a lot of request regarding my previous article ‘Build a facebook album browser using Swift‘ to update it in regard of Facebook SDK v4.4. In this tutorial, not only I have updated the Facebook iOS SDK into latest version but also used latest version of Swift and added some more features.

I am sorry for keeping you guys waiting so long but finally I have squeezed out some time to respond to your requests.

In my previous article, I built the Facebook album browser using Swift v1.0 and Facebook SDK v4.0. Facebook has recently launched the latest version of iOS SDK which is v4.4. A lot of changes came around this time with the version such as the SDK now targets v2.4 of the Graph API and updated Bolts to 1.2, updated header docs for FBSDKShareLinkContent to clarify parameter usage etc. You can find more details about the changes in Facebook website. Whereas Apple has also updated their programming language Swift to a latest version, v1.2.

App Improvements

  • Album thumbnail
  • Lazy loading of all images and albums
  • User can see number of likes and comments of each photo immediately
  • Full screen view of each image
  • A translucent layer over the display image where the likes and comments are shown
  • Latest Swift v1.2 implementation
  • Latest Facebook SDK v2.4 implementation

b

There are so many rooms for improvement in this application such as comment/like for each album, accessing user inbox, status update, read live feed etc. Thanks to Facebook for doing an amazing job in this latest SDK to make these tweaks fairly easy for the developers.

You need to change the following information in order to use Facebook SDK . Please use your own information in place of the following areas –

  • FacebookDisplayName
  • FacebookAppID
  • Url schemes of “Url Types”

From here, you can try to use some of the necessary sources:

AppDelegate


// AppDelegate.swift
// FBApp
//
// Created by Md. Arifuzzaman Arif on 7/4/14.
// Copyright (c) 2014 Md. Arifuzzaman Arif. All rights reserved.

import UIKit
import FBSDKCoreKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?

func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject?) -> Bool {
return FBSDKApplicationDelegate.sharedInstance().application(application, openURL: url, sourceApplication: sourceApplication, annotation: annotation)
}

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
// Override point for customization after application launch.
return FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
}

func applicationWillResignActive(application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}

func applicationDidEnterBackground(application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}

func applicationWillEnterForeground(application: UIApplication) {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}

func applicationDidBecomeActive(application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
FBSDKAppEvents.activateApp()

}

func applicationWillTerminate(application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}

}

FBHelper.swift

This is a helper class where all the Facebook related operations are composed.


// FBHelper.swift
// FBApp
//
// Created by Md. Arifuzzaman Arif on 7/4/14.
// Copyright (c) 2014 Md. Arifuzzaman Arif. All rights reserved.

import Foundation
import FBSDKLoginKit
import FBSDKCoreKit
import FBSDKShareKit
import FBAudienceNetwork

class FBHelper{
var accessToken: FBSDKAccessToken?
let baseUrl = “https://graph.facebook.com/v2.4/”
init(){
accessToken = FBSDKAccessToken.currentAccessToken()
}

func fetchFriendsPhoto(link:String, completionHandler: (img:UIImage)->()){
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), { () -> Void in

//http://graph.facebook.com/v2.4/10150192451235958/picture?type=thumbnail
let userImageURL = “(self.baseUrl)(link)/picture?type=album&access_token=(self.accessToken!.tokenString)”;

let url = NSURL(string: userImageURL);

let imageData = NSData(contentsOfURL: url!);

if let imageDataHas = imageData{
let image = UIImage(data: imageData!);

completionHandler(img: image!)
}

})
}

func fetchPhoto(link:String, addItemToTable: (album:AlbumImage)->()){

let fbRequest = FBSDKGraphRequest(graphPath: link, parameters: nil, HTTPMethod: “GET”)
fbRequest.startWithCompletionHandler { (connection:FBSDKGraphRequestConnection!, data:AnyObject!, error:NSError!) -> Void in
if let gotError = error{
println(“Error: %@”, gotError)
}
else{

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), { () -> Void in

//println(data)
var pictures:[AlbumImage] = [AlbumImage]();
let graphData = data.valueForKey(“data”) as Array;
var albums:[AlbumModel] = [AlbumModel]();

for obj:AnyObject in graphData{
//println(obj.description);
//println(obj)

let pictureId = obj.valueForKey(“id”) as String;

let smallImageUrl = “(self.baseUrl)(pictureId)/picture?type=thumbnail&access_token=(self.accessToken!.tokenString)”;
let url = NSURL(string: smallImageUrl);
let picData = NSData(contentsOfURL: url!);

var img:UIImage? = nil
if let picDataHas = picData{
img = UIImage(data: picData!);
}

let bigImageUrl = “(self.baseUrl)(pictureId)/picture?type=normal&access_token=(self.accessToken!.tokenString)”;
let sourceURL = NSURL(string: bigImageUrl)
let sourceData = NSData(contentsOfURL: sourceURL!)

var sourceImg:UIImage? = nil
if let hasSouceData = sourceData{
sourceImg = UIImage(data: hasSouceData)
}

let commentLink = “(self.baseUrl)(pictureId)/comments?access_token=(self.accessToken!.tokenString)”
let likeLink = “(self.baseUrl)(pictureId)/likes?access_token=(self.accessToken!.tokenString)”

var commentsByUser = self.executeComment(commentLink)
var likesByUser = self.executeLike(likeLink)

//println(“Comment: (commentLink)”)
//println(“Like: (likeLink)”)

//pictures.append(AlbumImage(smallImage: img!, bigImage: sourceImg!));
addItemToTable(album: AlbumImage(smallImage: img!, bigImage: sourceImg!, likes: likesByUser, comments: commentsByUser))
//NSThread.sleepForTimeInterval(2)
}
NSNotificationCenter.defaultCenter().postNotificationName(“photoNotification”, object: nil, userInfo: nil);
})

}
}

}

func executeLike(likeLink:String) -> [Like]{
let request = NSMutableURLRequest(URL: NSURL(string: likeLink)!)
request.HTTPMethod = “GET”
var likes = [Like]()

var responseObject:NSURLResponse?
var err:NSErrorPointer = NSErrorPointer()

let responseData = NSURLConnection.sendSynchronousRequest(request, returningResponse: &responseObject, error: err)
if let response = responseData{
if(err == nil){
var likeResponse: AnyObject? = NSJSONSerialization.JSONObjectWithData(response, options: NSJSONReadingOptions.AllowFragments, error: nil)

//println(likeResponse)
if let likeDict:NSDictionary = likeResponse as? NSDictionary{
let data = likeDict.objectForKey(“data”) as NSArray
//println(data)
for likeObj in data{
likes.append(Like(likeBy: likeObj.valueForKey(“name”) as? String, likeDate: “”, likeByUrl: likeObj.valueForKey(“id”) as? String, likeByImage: nil))
}

}
}
}
return likes
}

func executeComment(commentLink:String) -> [Comment]{
let request = NSMutableURLRequest(URL: NSURL(string: commentLink)!)
request.HTTPMethod = “GET”
var comments = [Comment]()

var responseObject:NSURLResponse?
var err:NSErrorPointer = NSErrorPointer()

let responseData = NSURLConnection.sendSynchronousRequest(request, returningResponse: &responseObject, error: err)
if let response = responseData{
if(err == nil){
var likeResponse: AnyObject? = NSJSONSerialization.JSONObjectWithData(response, options: NSJSONReadingOptions.AllowFragments, error: nil)

//println(likeResponse)
if let likeDict:NSDictionary = likeResponse as? NSDictionary{
let data = likeDict.objectForKey(“data”) as NSArray
//println(data)
for commentObj in data{
comments.append(Comment(commentString: commentObj.valueForKey(“message”) as? String, commentBy: commentObj.valueForKey(“from”)?.valueForKey(“name”) as? String, commentLocation: “”, commentDate: “”, commentByUrl: commentObj.valueForKey(“from”)?.valueForKey(“id”) as? String, commentByImage: nil))
}
}
}

}
return comments
}

func fetchCoverPhoto(coverLink: String, completion:(image:UIImage)->()){
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), { () -> Void in

//http://graph.facebook.com/v2.4/10150192451235958/picture?type=thumbnail
let userImageURL = “(self.baseUrl)(coverLink)?type=album&access_token=(self.accessToken!.tokenString)”;

let url = NSURL(string: userImageURL);

let imageData = NSData(contentsOfURL: url!);

if let imageDataHas = imageData{
let image = UIImage(data: imageData!);

completion(image: image!)
}

})
}

func fetchNewPhoto(link:String, completionHandler:()->()){

let fbRequest = FBSDKGraphRequest(graphPath: link, parameters: nil, HTTPMethod: “GET”)

fbRequest.startWithCompletionHandler { (connection:FBSDKGraphRequestConnection!, data:AnyObject!, error:NSError!) -> Void in
if let gotError = error{
println(“Error: %@”, gotError)
}
else{
println(data)
}
}
}

func fetchAlbum(user:User){

let userImageURL = “(self.baseUrl)(user.id)/albums?access_token=(self.accessToken!.tokenString)”;

let graphPath = “/(user.id)/albums”;
let request = FBSDKGraphRequest(graphPath: graphPath, parameters: nil, HTTPMethod: “GET”)
request.startWithCompletionHandler { (connection:FBSDKGraphRequestConnection!, result:AnyObject!, error:NSError!) -> Void in
if let gotError = error{
println(gotError.description);
}
else{
println(result)
let graphData = result.valueForKey(“data”) as Array;
var albums:[AlbumModel] = [AlbumModel]();
for obj:AnyObject in graphData{
let desc = obj.description;
//println(desc);
let name = obj.valueForKey(“name”) as String;
//println(name);
let id = obj.valueForKey(“id”) as String;
var cover = “”;

cover = “(id)/picture”;

//println(coverLink);
let link = “(id)/photos”;

let model = AlbumModel(name: name, link: link, cover:cover);
albums.append(model);

}
NSNotificationCenter.defaultCenter().postNotificationName(“albumNotification”, object: nil, userInfo: [“data”:albums]);
}
}
}

func logout(){
FBSDKLoginManager().logOut()
}

func readPermission() -> [String]{
return [“email”, “user_photos”, “user_friends”, “public_profile”]
}

func login(){

let loginManager = FBSDKLoginManager()
loginManager.logInWithReadPermissions([“email”, “public_profile”, “user_friends”, “user_photos”], handler: { (result:FBSDKLoginManagerLoginResult!, error:NSError!) -> Void in

if let gotError = error{
//got error
}
else if(result.isCancelled){
println(“login canceled”)
}
else{

println(result.grantedPermissions)
if(result.grantedPermissions.containsObject(“email”)){

let request = FBSDKGraphRequest(graphPath: “me”, parameters: nil, HTTPMethod: “GET”)
request.startWithCompletionHandler({ (connection:FBSDKGraphRequestConnection!, data:AnyObject!, error:NSError!) -> Void in

if let gotError = error{
//got error
}
else {

//println(data)

let email : String = data.valueForKey(“name”) as String;
let firstName:String = data.valueForKey(“name”) as String;
let userFBID:String = data.valueForKey(“id”) as String;
let userImageURL = “https://graph.facebook.com/(userFBID)/picture?type=small”;

let url = NSURL(string: userImageURL);

let imageData = NSData(contentsOfURL: url!);

let image = UIImage(data: imageData!);

println(“userFBID: (userFBID) Email (email) n firstName:(firstName) n image: (image)”);

var userModel = User(email: email, name: firstName, image: image!, id: userFBID);

NSNotificationCenter.defaultCenter().postNotificationName(“PostData”, object: userModel, userInfo: nil);
}
})

self.accessToken = FBSDKAccessToken.currentAccessToken();
}

}
})
}

}

Conclusion

Hope this article helps you on building custom Facebook album browsers with Swift. You can find the complete source code for download here. For Facebook SDK related configurations/API please use this link.

All the best and do let me know if you have any queries. Cheers!

newest oldest most voted
Notify of
MM
Guest
MM

Hello
Thank for this great tut
I’m using Xcode 6.4 and the app is not building giving lots of errors
I fixed some of them but I’m not able to fix FBusermodel.swift
i added fb display name and fb app id in info
but where can i get the url schemas.
awaiting your reply.
Thank you for your help.