Sunday, December 23, 2012

[IPHONE] Saving data created by the user

Click here...
http://cocoadevcentral.com/articles/000084.php

In a nutshell: saving data created by the user
Most applications need a way to save data to disk and bring it back later. In many cases, the best built-in class to use for this is NSKeyedArchiver. It doesn't provide the scalability of a SQL database, but it is incredibly easy to use.
In this tutorial, you'll add saving support to the MailDemo application, which was originally used in the Cocoa Bindings tutorial. It's not necessary to read that tutorial first, but you do need to understand Objective-C and general Cocoa concepts.
Download the project so you can follow along and make the changes as they're described. Note that this is not the finished project, just the starting point. Mac OS X 10.3 (Panther) is required to use this project.
> Download the MailDemo Xcode project 56k
Most Cocoa applications are typically either "regular" or multi-document. TextEdit, for example, is a multi-documentation application, whereas AddressBook is not. This tutorial does not discuss multi-document applications, though the concepts are very similar.
1 of 9

NSKeyedArchiver in a Nutshell

The NSKeyedArchiver class accepts data objects from your application and stores them on disk. It stores the objects in a file as binary data.
Encoding Diagram
You can open a binary data file in a text editor, but it's quite hard to make any sense of the contents that way. Binary files are designed to be easily read by the computer, not a person. As a result, binary files take up less space on disk than plain text files and can be loaded by an application very quickly.
Interface Builder, for example, typically stores NIB files in a binary format.
2 of 9

Adding Saving Support to Mailbox

The process of converting objects into binary data is called encoding. Your job is to tell Cocoa how your data should be encoded. Here's the code to add to Mailbox.m to do that:
Mailbox.m
- (void) encodeWithCoder: (NSCoder *)coder { [coder encodeObject: properties forKey:@"properties"]; [coder encodeObject: emails forKey:@"emails"]; }
This method adds the Mailbox's data to the NSCoder object that's passed in, using the -encodeObject:forKey: message to store each item. You can choose whatever names you like for the keys, but they must mirror those used in -initWithCoder.
The -initWithCoder: method is called when data is being loaded back from disk. Here's the version of that method to put in Mailbox.m:
- (id) initWithCoder: (NSCoder *)coder { if (self = [super init]) { [self setProperties: [coder decodeObjectForKey:@"properties"]]; [self setEmails: [coder decodeObjectForKey:@"emails"]]; } return self; }

Finally, change Mailbox.h to indicate that the Mailbox class now conforms to the NSCoding protocol:
Mailbox.h
@interface Mailbox : NSObject <NSCoding>
That's all we need to do in this file.
3 of 9

Adding Saving Support to Email

Here's the code to add to Email.m to enable saving for the Email class:
Email.m
- (void) encodeWithCoder: (NSCoder *)coder { [coder encodeObject: properties forKey:@"properties"]; }
Here's the code to enable loading from disk:
- (id) initWithCoder: (NSCoder *)coder { if (self = [super init]) { [self setProperties: [coder decodeObjectForKey:@"properties"]]; } return self; }
This code is nearly identical to the methods added to Mailbox. The difference is that there's one less instance variable to store.
Just as before, add NSCoding to Email.h:
Email.h
@interface Email : NSObject <NSCoding>
We're now done with this file.
4 of 9

Declare New Methods in MyController.h

We'll create three new methods to MailDemo's MyController class to support saving. Add these declarations to the MyController.h file:
MyController.h
- (NSString *) pathForDataFile; - (void) saveDataToDisk; - (void) loadDataFromDisk;
The first method returns the destination path of the data file. The other two methods are used to save and load the data, respectively.
5 of 9

Choosing the File Location

Before an application can save, the developer must select a location for the data. Mac OS X applications generally store such things in ~/Library/Application Support/<Application>/. The application must create that directory if it doesn't already exist.
Here's the code to add to MyController.m to do all of this:
MyController.m
- (NSString *) pathForDataFile { NSFileManager *fileManager = [NSFileManager defaultManager]; NSString *folder = @"~/Library/Application Support/MailDemo/"; folder = [folder stringByExpandingTildeInPath]; if ([fileManager fileExistsAtPath: folder] == NO) { [fileManager createDirectoryAtPath: folder attributes: nil]; } NSString *fileName = @"MailDemo.cdcmaildemo"; return [folder stringByAppendingPathComponent: fileName]; }
On the first line of this method, we set up an instance of NSFileManager. Many of the file-related tasks that you would typically do by hand with the Finder can be accomplished using NSFileManager.
Next, we create an NSString named folder, and set it to the path of the destination folder.
The next line is a bit tricky in that it re-assigns the folder variable to a different version of the same string. The -stringByExpandingTildeInPath method returns a version of the folder path with the tilde replaced by the user's home directory, such as "/Users/scott".
On the next line, we ask NSFileManager if the folder already exists. If it doesn't, we request that it is created by sending the -createDirectoryAtPath:attributes: message.
Finally, we append the file name to the folder path and return the complete path.
6 of 9

Archiving the Data

Now that you have added the NSCoding methods to the data classes, you can ask NSKeyedArchiver to write your objects to disk. You only need to tell the archiver about your top-level objects. In this case, the term "top level" just means the objects which are listed as instance variables in MyController.h.
The only top-level object for the MyController class is the "mailboxes" array. Here's the code to add to MyController.m to save the array (and everything it contains) to disk:
MyController.m
- (void) saveDataToDisk { NSString * path = [self pathForDataFile]; NSMutableDictionary * rootObject; rootObject = [NSMutableDictionary dictionary]; [rootObject setValue: [self mailboxes] forKey:@"mailboxes"]; [NSKeyedArchiver archiveRootObject: rootObject toFile: path]; }
On the first line, we retrieve the destination file path. After that, we create an NSMutableDictionary and place the mailboxes array in it. If you have other top-level objects, add them to this dictionary.
This dictionary is considered the "root object" -- a master object which contains a tree of all other data objects. We pass this dictionary to NSKeyedArchiver in the +archiveRootObject:toFile: class method.
7 of 9

How Archiving Works

Once NSKeyedArchiver receives the +archiveRootObject:toFile: message, it recursively calls -encodeWithCoder on the entire tree of objects inside the root object. Each instance of Mailbox and Email adds its own bit of data to the archiver.
Archiving Diagram
After all of the objects have added their encoded data, the archiver automatically creates an NSData object and writes its contents to the file path we supplied.
8 of 9

Reloading Data at Startup

Now we will implement a method in MyController.m to load the data from disk:
MyController.m
- (void) loadDataFromDisk { NSString * path = [self pathForDataFile]; NSDictionary * rootObject; rootObject = [NSKeyedUnarchiver unarchiveObjectWithFile:path]; [self setMailboxes: [rootObject valueForKey:@"mailboxes"]]; }
This is essentially the reverse of the saving method. Once again, we retrieve the path to the file and create a dictionary which will serve as the root object.
This time, though, we're talking to the NSKeyedUnarchiver class, which is similar to NSKeyedArchiver, but specializes in loading data from disk. We send it the -unarchiveObjectWithFile message, which will read the data file, un-encode the contents, and return the root object.
After that, it's just a matter of using -setMailboxes to repopulate the mailboxes array with the saved data.
9 of 9

Automating Save and Reload

MailDemo can now save and reload data, but the process should ideally be transparent to the user. We only need to add a few lines of code to MyController.m to make that happen:
MyController.m
- (void) awakeFromNib { [NSApp setDelegate: self]; [self loadDataFromDisk]; }
The -setDelegate message registers MyController to be the application delegate. It's possible to do this in Interface Builder as well.
The next line of code simply calls -loadDataFromDisk. Since MailDemo uses Cocoa bindings, the table views are automatically updated after the data is loaded.
To complete the cycle, we need to make sure the data is saved when the application quits. To do this, add the -applicationWillTerminate delegate method show below:
- (void) applicationWillTerminate: (NSNotification *)note { [self saveDataToDisk]; }
We're all set! Build and run the project. You should see that your data stays intact between sessions. If you encountered any difficulties, go back and repeat the steps above.

Wrap Up

We've added NSCoding support to the data classes and saving support to the application. Implementing encoding also sets your application up to support copy/paste and drag-and-drop. Both are typically accomplished by writing encoded objects to the pasteboard.
> Download the Finished MailDemo Xcode project 57k
As always, let us know what you think about the tutorial.

Programming iOS 5

http://www.apeth.com/iOSBook/

How to Add Splash Screen in Your iOS App?

http://www.appcoda.com/how-to-add-splash-screen-in-your-ios-app/

For those who are new to programming and haven’t heard of the term “Splash Screen”, let me first give a brief explanation about it. Splash screen is commonly found in iOS apps, as well as, other desktop applications. This is the first screen you see when launching an application. Usually, splash screen is an image covering the entire screen and disappears after the main screen is loaded. Below figure shows you a few samples of splash screen:


Sample iOS Splash Screen
Sample Splash Screens / Launch Images
The primary purpose of splash screen is to let user know your app is loading and give user an introductory screen showing your brand. Splash screen is especially important for apps that take longer time to launch. Perceptually, it gives a better user experience.

Adding Splash Screen in Your App

As mentioned earlier, it’s not required to write any code to display the splash screen. iOS comes with a built-in function called launch image. This image is automatically displayed when user opens the app and disappeared until the app is fully ready to use. You can simply specify your splash screen as launch image in Xcode and it will handle the rest for you.

Preparing Your Splash Screen

As you know, iPhone 4/4S supports a higher screen resolution (what so called Retina Display). In order to support both screen resolution of older iPhone models and latest models, you have to prepare two versions of splash screen images of these sizes:
  • 320 x 480 (for iPhone 2G / 3G / 3GS)
  • 640 x 960 (for iPhone 4 / 4S)
For the sake of simplicity, I’ll show you how to add splash screen in iPhone app. In case you’re building an iPad app, you can refer to Apple’s iOS Human Interface Guideline about the launch image size and naming convention.
The splash screen image should be in PNG format. By default, you should name the image file for lower screen resolution as “Default.png”. For the image intended for Retina Display (i.e. 640 x 960 screen resolution), name the file as “Default@2x.png”. The “@2x” is a standard scale modifier used in iOS. All image files designated for displaying in Retina Display should name with the optional string “@2x”.
Instead of using “Default” as the file name of launch image, you may change it to your preferred one. The name of the launch image is defined in your app’s Info.plist file. Use our Simple Table app as an example, you can add a new property called “Launch image” in the SimpleTable-Info.plist and specify the preferred file name (say, MyLaunchImage). Xcode Change Launch Image Name
The change instructs iOS to pick “MyLaunchImage.png” and “MyLaunchImage@2x.png” as launch image.
You can design your own splash screen. For testing purpose, you may download the sample splash screens.
Default Splash Screen
Splash Screen for Our Simple Table App

Add Your Launch Image in Xcode

After preparing the launch image, go back to Xcode and open your Xcode project. Here we’ll continue to use our Simple Table project. Right click the “SimpleTable” project and select “Add Files to SimpleTable”. Add both “Default.png” and “Default@2x.png” to your project.
Add file to Xcode Project
Add File to Xcode Project
If you’ve done everything correctly, you’ll see both files in your project and Xcode automatically recognizes the files as launch images.
Launch Image Added in Xcode
Launch Image added in Xcode

Test it Out!

Simply run your app again. This time you’ll see a splash screen shown up instantly as it runs. For now, there is not much thing to load during application startup. (Note: the splash screen only shows up for a second and disappears.)






Simple Table App Splash Screen

Wednesday, December 19, 2012

[IPHONE] How to create More App Screen for your app?

Step 1:

Go to link: https://www.chartboost.com/support/sdk_download/?os=ios and add Chartboost folder to your project.

Step 2:

Add framework to your project: QuartzCore, SystemConfiguration,CoreGraphics,
 AdSupport and StoreKit frameworks.
Note: AdSupport is Optional
Step 3:
//-----> Add follow code to your - (void)applicationDidBecomeActive:(UIApplication *)application <-----//
Chartboost *cb = [Chartboost sharedChartboost];
    
    // Add your own app id & signature. These can be found on App Edit page for your app in the Chartboost dashboard
    cb.appId = @"YOUR_CHARTBOOST_APP_ID";
    cb.appSignature = @"YOUR_CHARTBOOST_APP_SIGNATURE";
    
    cb.delegate = self;
    
    // Begin a user session. This should be done once per boot
    [cb startSession];
    
    // Cache an interstitial at the default location
    [cb cacheInterstitial];
    
    // Cache an interstitial at some named locations -- recommended!!
    [cb cacheInterstitial:@"Main Menu"];
    [cb cacheInterstitial:@"After level 1"];
    
    // Once cached, you can use showInterstitial at any point in your app to display the interstitial immediately
    
    
    // Cache the more apps page so it's ready & loaded
    [cb cacheMoreApps];

Dont't forget.. 
//--> At AppDelegate.h <--
#import "Chartboost.h"
@interface AppDelegate : UIResponder <UIApplicationDelegate, ChartboostDelegate>

Step 4: At method action for button "More App",  add code:

//------------

[[Chartboost sharedChartboost ] setDelegate:self];
    [[Chartboost sharedChartboost] showMoreApps];
//------------

Don't forget: (At ViewController contain button More App --> Example: MoreAppViewController

//----->   MoreAppViewController.h <-------
#import "Chartboost.h"
@interface MoreAppViewController : UIViewController<ChartboostDelegate>

//-----> Add two method to  MoreAppViewController.m <-------
- (BOOL)shouldDisplayMoreApps
{
    [[UIApplication sharedApplication] setStatusBarHidden:YES];
    return YES;
}

- (void)didCloseMoreApps
{
    [[UIApplication sharedApplication] setStatusBarHidden:NO];
}

==>>>> Enjoy it!



Sunday, November 18, 2012

Vấn đề về delegate??

Click here...
Delegate dịch nghĩa ra thì là người được ủy nhiệm.
Ví dụ thế này, sếp bạn cử bạn đi công tác nước ngoài. Nhưng quyền quyết định mọi việc ko phải ở bạn mà là ở sếp. Ví dụ như bạn muốn ký hợp đồng, phá vỡ hợp đồng hay ko thì phải là do sếp quyết định. Vấn đề nảy sinh ra là khi bạn ra nước ngoài, sếp bạn sẽ ko biết có chuyện gì nảy sinh ra hay ko để biết lúc nào mà ra quyết định. Còn nếu sếp cứ phải kè kè bên cạnh bạn thì việc cử bạn đi là vô ích. Để giải quyết vấn đề, sếp ủy nhiệm 1 vật đi theo bạn, và khi có việc gì, bạn chỉ cần thông báo qua vật này thì sếp sẽ biết. Ở đây vật này có thể là 1 số điện thoại liên lạc. số điện thoại liên lạc này chính là vật được ủy nhiệm, delegate.
Viết kiểu code thì thế này
Trong class ông chủ:

Nhanvien* a=[self luachonNhanVien];
a.solienlac_delegate=self;
[a dicongtac];

//---->Example-----
protocolTest = [[ClassWithProtocol alloc] init];
    [protocolTest setDelegate:self];
    //or--> protocolTest.delegate=self;
    [protocolTest startSomeProcess];

//-------------------

Trong class nhanvien:
-(void) dicongtac{
//Lam gi thi lam,
//lam xong thi thong bao ve cho ong chu de ong chu quyet dinh
[self.solienlac_delegate baocaosep:ketqua]
}



//------Example------
-(void)startSomeProcess
{
    NSLog(@"---->startSomeProcess!");
   
    [self.delegate processSuccessful:@"HELLO OBJC"]; //Bao cao lai cho sep!
 }
//----------------------

ông chủ sẽ phải comfort cái protocol của delegate, nghĩa là đảm bảo khi được gọi thì sẽ xử lý, nghĩa là cần có function này:
-(void) baocaosepint) ketqua{
if(ketqua==1)
[self goinhanvienve];
if(ketqua==2)
[self ralenhmoichonhanvien];
}
//-----Tai class ong chu, ong chu se quyet dinh lam di voi cai bao cao do cua nhan vien-----
- (void) processSuccessful:(NSString *) success
{
    NSLog(@"Process completed-->%@", success);
}
//---------------------------

Cốt lõi của vấn đề ở đây là CallBack function, hàm gọi ngược, chứ ko phải là trao đổi dữ liệu gì như 1 số bạn nói. Ở đây nhân viên có thể gọi ngược lại, yêu cầu sếp ra quyết định vì nhân viên đã có vật ủy nhiệm của sếp.
Trong C, C++, để thực hiện việc gọi ngược, người ta dùng function pointer.
Trong C#, người ta cũng gọi nó là delegate nhưng delegate này vai trò tương đương với function pointer của C, C++.
Trong java, người ta ko gọi là delegate, nhưng thực chất cũng là truyền 1 object ủy nhiệm tương tự như delegate của objective C mà thôi. Khác biệt với C,C++,C# ở chỗ delegate của Objective C sẽ có thể chứa nhiều functions

The Basics of Protocols and Delegates

Source: http://mobiledevelopertips.com/objective-c/the-basics-of-protocols-and-delegates.html

Apple offers a good overview of working with protocols in their Objective-C Programming Reference. However, sometimes a simple working example can go a long ways…
Introduction
Protocols can be helpful in a number of scenarios, a common usage is to define methods that are to be implemented by other classes. A familiar example is when using a tableview, your class implements the cellForRowAtIndexPath method which asks for cell content to insert into a table – the cellForRowAtIndexPath method is defined within the UITableViewDataSource protocol.
Let’s walk through a very simple example of defining and adopting a protocol.

Protocol Definition
Here is an example of a protocol which includes one method, notice the instance variable delegate is of type id, as it will be unknown at compile time the type of class that will adopt this protocol.
#import <Foundation/Foundation.h>
 
@protocol ProcessDataDelegate <NSObject>
@required
- (void) processSuccessful: (BOOL)success;
@end
 
@interface ClassWithProtocol : NSObject 
{
 id <ProcessDataDelegate> delegate;
}
 
@property (retain) id delegate;
 
-(void)startSomeProcess;
 
@end
Protocol Implementation
Inside the implementation section for the interface defined above we need to do two things at a minimum – first synthesize the delegate instance variable and second, call the method defined in the protocol as needed (more on that in a moment).
Let’s look at a bare bones implementation of the ClassWithProtocol.m:
#import "ClassWithProtocol.h"
 
@implementation ClassWithProtocol
 
@synthesize delegate;
 
- (void)processComplete
{
  [[self delegate] processSuccessful:YES];
}
 
-(void)startSomeProcess
{
  [NSTimer scheduledTimerWithTimeInterval:5.0 target:self 
    selector:@selector(processComplete) userInfo:nil repeats:YES];
}
 
@end
Understand this is a rather contrived example – the intention is to show how/where one might use a protocol. For the sake of discussion assume you have a class that is processing (or downloading) some type of data. Further, assume this class is called from another class to begin the processing. Chances are, at some point the caller will want to be notified that the class processing the data is done, this is where the protocol comes in.
In the calling class, the method defined in the protocol, processSuccessful, will be implemented and will be called from the object doing the processing, once it is complete.
For this example, inside the class where the protocol is defined, I have one method, startSomeProcess, which simply starts a timer and calls processComplete after 5 seconds. Inside processComplete the calling object will be notified through its delegate that the process is done.
Adopting the Protocol
To keep the example short, I am using the applicaton delegate as the class that adopts the protocol. Here is how the app delegate looks:
#import <UIKit/UIKit.h>
#import "ClassWithProtocol.h"
 
@interface TestAppDelegate : NSObject <UIApplicationDelegate, ProcessDataDelegate>
{
  UIWindow *window;
  ClassWithProtocol *protocolTest;
}
 
@property (nonatomic, retain) UIWindow *window;
 
@end
A few things to note – ProcessDataDelegate is defined as part of the interface, which signifies that this class will adhere to the protocol. Looking back to the code for defining the protocol, notice that I added @required to the definition, which means that any class that adopts the protocol must implement the processSuccessful method (you will receive a compile warning if you don’t).
Here is the implementation of the app delegate and the required method for the protocol:
#import "TestAppDelegate.h"
#import "ClassWithProtocol.h"
 
@implementation TestAppDelegate
 
@synthesize window;
 
 UITableViewDelegate
 
- (void)processSuccessful:(BOOL)success;
{
  NSLog(@"Process completed");
}
 
- (void)applicationDidFinishLaunching:(UIApplication *)application 
{   
  // Create and initialize the window
  window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
 
  protocolTest = [[ClassWithProtocol alloc] init];
  [protocolTest setDelegate:self];
  [protocolTest startSomeProcess];
 
  [window makeKeyAndVisible];
}
 
- (void)dealloc 
{
  [window release];
  [super dealloc];
}
 
@end
How it all works
Things goes as follows: the app delegate will create a new instance of the ClassWithProtocol object. It sets itself as the delegate and then calls the startSomeProcess method. At some point in the future, when the protocolTest object has completed its work – after the 5 second timer has fired – it will call the processSuccessful method in the app delegate to let it know it is done processing.
Download Xcode Project
You can find a complete (albeit trivial) working example here: Protocol Xcode Project

Tuesday, October 30, 2012

Facebook Login


Facebook Login

Facebook Login for iOS allows you to obtain an access token to access Facebook services on behalf of a user. You can use this feature in place of building your own account system or to add Facebook services to your existing accounts.
Facebook Login với iOS cho phép bạn obtain một access token để truy cập Facebook services với tư cách là một người dùng. Bạn có thể sử dụng những tính năng trong place of building your own account system hay để thêm Facebook serviecs đến những tài khoản đã tồn tại.
Click here...
Today there are three ways a user can login to Facebook. Originally using Facebook Login in your iOS app would show an in-app web view where the user could connect. In late 2010 we introduced a faster technique called Single Sign On, or SSO, that enabled one-click access for user using the native Facebook for iOS app. In iOS 6, Apple is introducing Facebook integration built into iOS directly, which further simplifies the process.
Hôm nay có 3 cách để người sử dụng có thể đăng nhập vào Facebook. Cách truyền thống là sử dụng Facebook Login trong iOS app, nó sẽ show một in-app web view mà ở đó người dùng có thể connect. Sau năm 2010 chúng tôi đã giới thiệu một kỹ thuật nhanh hơn được gọi là Single Sign On, hay SSO, điều này cho phép one-click access cho người dùng bằng cách sử dụng native Facebook for iOS app. Ở iOS 6, Apple đang giới thiệu sự tích hợp Facebook được xây dựng trực tiếp trong iOS, tương lai nó sẽ làm đơn giản hoá quá trình.
The Facebook SDK for iOS will automatically choose the best option when you attempt to use Facebook login. If a user previously gave your app permissions, the SDK will immediately return an OAuth 2 access token back to your app, possibly without even showing the user a prompt. For this reason, we recommend you always use the Facebook SDK for iOS to obtain Facebook access tokens.
Facebook SDK cho iOS sẽ tự động chọn tuỳ chọn tốt nhất khi bạn cố găng sử dụng Facebook login. Nếu một người dùng trước đây gave your app permissions, SDK sẽ ngay lập tức reuturn một OAuth 2 access token back to app của bạn, possibly without even hiển thị user a prompt. Vì lý do này, chúng tôi khuyên bạn luôn luôn sử udngj Facebook SDK cho iOS để obtain Facebook access tokens.
This article walks through the following topics:

Login Setup

In order to use Facebook Login you will first need to add the Facebook SDK to your project. The next few steps will help you through that. If you have already added the Facebook SDK to your project, skip to step 4.
Để sử dụng Facebook Login đầu tiên bạn sẽ cần add the Facebook SDK đến dự án của bạn. Một vài bước tiếp theo sẽ giúp bạn through that. Nếu bạn đã add Facebook SDK đến dự án của bạn, hãy bỏ qua bước 4.

Step 1: Get Started

Follow the Getting Started with the iOS SDK document to get up and running on the basics. Follow the steps in that guide to complete the following tasks:
  • Install the Prerequisites
  • Install the Facebook iOS SDK
  • Create a Facebook App

Step 2: Set Up your Xcode Project

The Getting Started with the iOS SDK document has a ''Start a new Xcode Project'' section that walks you through setting up your Xcode project for Facebook integration. If you have an existing Xcode project, you can skip over the step that asks you to create a new project. Follow all the other steps in that section.
The Getting Started với iOS SDK document có một phấn là "Start a new Xcode Project"  mà walks you through setting up dự án Xcode của bạn cho sự tích hợp Facebook. Nếu bạn có một dự án Xcode đã tồn tại, bạn có thể skip over bước này mà yêu cầu bạn tạo một dự án mới. 

Step 3: Include the Facebook SDK

In your app delegate header, add code to include the Facebook SDK:
#import <FacebookSDK/FacebookSDK.h>

Step 4: Implement the Login Flow

The flow involves adding a login button that when clicked initiates Facebook Login. The FBSession class has properties you use to open and check the state of the Facebook session object. The FBSession method that handles opening the session can be passed a completion handler that can be used to detect session changes. We will make use of notifications to broadcast session changes that your classes can then use to control their UI.
Những dòng dưới đây bao gồm việc thêm một nút login mà khi click nó sẽ khởi tạo Facebook Login. The FBSession class có những thuộc tính mà bạn sử dụng để mở và kiểm tra trạng thái của đối tượng Facebook session. Phương thức FBSession nó sẽ xử lý việc mở session có thể được truyền một completion handler mà có thể được sử dụng để phát hiện ra session đã thay đổi. Chúng tôi sẽ dùng notifications để broadcast session changes mà những lớp của bạn có thể sau đó sử dụng để điều khiển UI của chúng.
First, add a button to your view controller and set up the button to initiate the login flow. Let's assume that you wired this button to an action method called authButtonAction:.
Đầu tiên, add một button đến your view controller và thiết lập button để khởi tạo login flow. Bạn phải nối button này đến một action method được gọi là authButtonAction:
Next, open up your app delegate header file and define a global variable that is used for notifications:
extern NSString *const FBSessionStateChangedNotification;
Then open up your app delegate implementation file and define the notification string:
NSString *const FBSessionStateChangedNotification =
    @"com.example.Login:FBSessionStateChangedNotification";
You should make the notification string unique. For example, you can change com.example.Login to your app's Bundle Identifier.
Bạn nên tạo notification string là duy nhất. Ví dụ, bạn có thẻ thay đổi com.example.Login đến app's Bundle Identifier.
Next, open up your app delegate implementation file and add two methods. The first method calledopenSessionWithAllowLoginUI: is invoked when the login button is clicked or when a check is made for an active session when the main view is initially loaded. This method calls theopenActiveSessionWithReadPermissions:allowLoginUI:completionHandler: method of FBSession class to open a Facebook session. The second method called sessionStateChanged:state:error: defines the completion handler. The completion handler for the session open method handles all the session state change functions, including checking the authorization callback and monitoring any subsequent session state changes. Add these two new methods:
Tiếp theo, mở file app delegate implementation của bạn và add 2 phương thức. Phương thức đầu tiên được gọi là openSessionWithAllowLoginUI:  được gọi khi button login được click hoặc khi một check được tạo cho một active session khi main view được initially loaded. Phương thức này gọi  phương thức openActiveSessionWithReadPermissions:allowLoginUI:completionHandler: của lớp FBSession để mở một Facebook session. Phương thức thư 2 được gọi là sessionStateChanged:state:error: định nghĩa completion handler. Completion handler for session mở method handles all the session state change functions, bao gồm việc kiểm tra authorization callback và giám sát bất kì subsequent session state bị thay đổi. Thêm 2 method mới:
/*
 * Callback for session changes.
 */
- (void)sessionStateChanged:(FBSession *)session
                      state:(FBSessionState) state
                      error:(NSError *)error
{
    switch (state) {
        case FBSessionStateOpen:
            if (!error) {
                // We have a valid session
                NSLog(@"User session found");
            }
            break;
        case FBSessionStateClosed:
        case FBSessionStateClosedLoginFailed:
            [FBSession.activeSession closeAndClearTokenInformation];
            break;
        default:
            break;
    }
    
    [[NSNotificationCenter defaultCenter]
     postNotificationName:FBSessionStateChangedNotification
     object:session];
    
    if (error) {
        UIAlertView *alertView = [[UIAlertView alloc]
                                  initWithTitle:@"Error"
                                  message:error.localizedDescription
                                  delegate:nil
                                  cancelButtonTitle:@"OK"
                                  otherButtonTitles:nil];
        [alertView show];
    }
}

/*
 * Opens a Facebook session and optionally shows the login UX.
 */
- (BOOL)openSessionWithAllowLoginUI:(BOOL)allowLoginUI {
    return [FBSession openActiveSessionWithReadPermissions:nil
                                          allowLoginUI:allowLoginUI
                                     completionHandler:^(FBSession *session,
                                                         FBSessionState state,
                                                         NSError *error) {
                                         [self sessionStateChanged:session
                                                             state:state
                                                             error:error];
                                     }];
}
Now, add the openSessionWithAllowLoginUI: to the app delegate header file, so your view controller can invoke it:
- (BOOL)openSessionWithAllowLoginUI:(BOOL)allowLoginUI;
If you want to ask for additional permissions, modify the FBSession initialization in theopenSessionWithAllowLoginUI: method. For example, to ask for email and user_likes permissions, use the following code:

Nếu bạn muốn thêm những permission thì chỉnh sửa khai báo FBSession trong openSessionWithAllowLoginUI: method. Ví dụ, để thêm email và user_likes permissions, sử dụng code sau:
- (BOOL)openSessionWithAllowLoginUI:(BOOL)allowLoginUI {
    NSArray *permissions = [[NSArray alloc] initWithObjects:
        @"email", 
        @"user_likes",
        nil];
    return [FBSession openActiveSessionWithReadPermissions:permissions
                                              allowLoginUI:allowLoginUI
                                         completionHandler:^(FBSession *session,
                                                         FBSessionState state,
                                                         NSError *error) {
                                         [self sessionStateChanged:session
                                                             state:state
                                                             error:error];
                                     }];
}
You can only ask for read permissions when opening the session. If you need write permissions, ex: publish_actionsthen you would call the reauthorizeWithPermissions:defaultAudience:completionHandler: method in theFBSession class. As a best practice you should ask for write permissions in context, so it is clear to the user why you are requesting that access. As an example, you would ask for publish_actions when the user chooses to publish an action to their timeline. Refer to the permissions guide for more information on permissions.
The login flow differs if the user is using iOS6+ or earlier OS versions. For pre iOS6, during the login flow, your app will pass control to the Facebook iOS app or Facebook in mobile Safari. After the user authenticates, control will pass back your app with the session information in a specially encoded URL. To properly record this information, you need to give the Facebook SDK a chance to process incoming URLs. In iOS6+, the login flow gets the user's credentials from iOS and the user is not transitioned to the Facebook app. The Facebook SDK takes care of these interactions under the hood and all you have to do is call the required FBSession methods.
In the app delegate, implement the application:openURL:sourceApplication:annotation: delegate method to call the Facebook session object:
/*
 * If we have a valid session at the time of openURL call, we handle
 * Facebook transitions by passing the url argument to handleOpenURL
 */
- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication
         annotation:(id)annotation {
    // attempt to extract a token from the url
    return [FBSession.activeSession handleOpenURL:url];
}
The flow back to your app may be interrupted (for ex: if the user clicks the Home button if authenticating via the Facebook for iOS app). If this happens, the Facebook SDK can take care of any cleanup that may include starting a fresh session. To enable this, in the applicationDidBecomeActive: delegate method call the active session'shandleDidBecomeActive method:
// We need to properly handle activation of the application with regards to SSO
// (e.g., returning from iOS 6.0 authorization dialog or from fast app switching).
[FBSession.activeSession handleDidBecomeActive];
You should also take care of closing the session if the app is about to terminate. Do this by adding the following code to the user applicationWillTerminate: app delegate method:
[FBSession.activeSession close];
Now that you have set up the authentication code in the app delegate, go back to your view controller implementation file to invoke the authentication methods. First, include the app delegate header file:
#import "AppDelegate.h"
Next, in the authButtonAction method fill out the implementation to invoke the openSessionWithAllowLoginUI:method you defined in the app delegate:
- (IBAction)authButtonAction:(id)sender {
    AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
    // The user has initiated a login, so call the openSession method
    // and show the login UX if necessary.
    [appDelegate openSessionWithAllowLoginUI:YES];
}
Build and run the project. When the login button is clicked, you should see something like this:

You should also see an NSLog showing that a valid user session has been found:
2012-08-10 18:02:24.529 TestLogin[47133:c07] User session found
Once you've verified the login flow, you can remove the NSLog statement in the sessionStateChanged:state:error:method defined in your app delegate implementation file.
You'll notice that even though you've logged in the login button is still labeled ''Login''. You'll take care of this in the next step.

Step 5: Implement the Logout Flow

For simplicity, we we'll assume you'll use the same button for logging the user in and out. Add an outlet named ''authButton'' to the login button you set up previously. Use this to control the button text when the user is logged in versus logged out.
Now, set up a new method in the app delegate implementation file that handles logging out:
- (void) closeSession {
    [FBSession.activeSession closeAndClearTokenInformation];
}
Next, add this new method to the app delegate header file:
- (void) closeSession;
Now, make the following changes to your view controller. Modify the authButtonAction: method to detect the session validity and log the user in or out:
- (IBAction)authButtonAction:(id)sender {
    AppDelegate *appDelegate =
        [[UIApplication sharedApplication] delegate];
    
    // If the user is authenticated, log out when the button is clicked.
    // If the user is not authenticated, log in when the button is clicked.
    if (FBSession.activeSession.isOpen) {
        [appDelegate closeSession];
    } else {
        // The user has initiated a login, so call the openSession method
        // and show the login UX if necessary.
        [appDelegate openSessionWithAllowLoginUI:YES];
    }


}
Then, in the viewDidLoad method, register for the session change notification you defined in the app delegate by adding this code to the end of the method:
[[NSNotificationCenter defaultCenter]
     addObserver:self
     selector:@selector(sessionStateChanged:)
     name:FBSessionStateChangedNotification
     object:nil];
Unregister for the notifications by adding the following code to the end of the didReceiveMemoryWarning the method:
[[NSNotificationCenter defaultCenter] removeObserver:self];
Next, define a new private method sessionStateChanged: to change the button text:
- (void)sessionStateChanged:(NSNotification*)notification {
    if (FBSession.activeSession.isOpen) {
        [self.authButton setTitle:@"Logout" forState:UIControlStateNormal];
    } else {
        [self.authButton setTitle:@"Login" forState:UIControlStateNormal];
    }
}
Finally, modify the viewDidLoad method to show the logged in versus logged out button by calling the app delegateopenSessionWithAllowLoginUI: method to check for a cached token. While checking the cached token, you are setting a flag to open a session while avoiding a login UI flow. Add this code to the end of the method:
// Check the session for a cached token to show the proper authenticated
// UI. However, since this is not user intitiated, do not show the login UX.
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
[appDelegate openSessionWithAllowLoginUI:NO];
Build and run the project. Since the session should be active from your first run, the button should be set to ''Logout''.
Click on the button to log out the user. The button text should change to ''Login''. Clicking the button again should switch you to the Facebook app (iOS or mobile Safari) and show you an interstitial screen with an ''OK'' button. We'll talk about how to get rid of this interstitial screen in the Best Practices section.

Best Practices

Pro-tip 1: Include Facebook Login at User Registration

Apps often only use Facebook Login when asking the user to enable Facebook features in the app. You should also include Facebook Login anywhere you prompt the user to register for your app, which usually shows up the first time a user launches an app. Users can enjoy a simplified registration process and you can request the same information that you would normally collect manually (ex: email address).

Pro-tip 2: Request Only the Permissions Your App Needs

Because so much personal information is stored by users in Facebook, we have a very extensive permission system to protect their privacy. In particular, certain permissions (called extended permissions) are shown separately to the user during login, where they are given an opportunity to opt-out of them individually.
In general, you will get the best login rate from users if you only request the permissions you need to register them and use your basic features. If you need additional permissions later, you can always request them at a time when the user is better informed about your app and why you might need them.
More information about our privacy system can be found in this blog post.

Pro-tip 3: Do not request offline_access or publish_stream

In the past, using Facebook services when a user was not actively interacting with your application required a special permission called 'offline_access'. This permission is no longer required and will soon be deactivated.
If you have an older application that was using this permission you can learn more about how to upgrading access tokens.
Also, many apps incorrectly ask for 'publish_stream' to add content to a user's News Feed. This permission tends to hurt conversion for your users and is almost never needed. Instead, consider publishing Open Graph actions or using our Feed Dialog - which does not require this permission.

Pro-tip 3: Complete all iOS App Settings

Fill out every field related to your app in the Native iOS App section of the Basic Settings in the App Dashboard. If these fields are not configured, we can't drive traffic to your app or the iOS App Store.
In addition, we use the iOS Bundle ID to streamline authentication for users who already authenticated your app.