Tuesday 31 July 2012

iCloud Integration


Configuring iCloud in iOS 5

The first time you install iOS 5, you’ll be asked to configure an iCloud account by providing or creating an Apple ID. Configuration steps will also allow you to set which services you want to synchronize (calendar, contacts, etc.). Those configurations are also available under Settings\iCloud on your device.
Before you proceed any further with this tutorial, make sure that you have iOS 5 installed on two test devices, and that iCloud is working properly on both devices.

Enabling iCloud in your App

There are three steps to use iCloud in an app, so let’s try them out as we start this new project.
1. Create an iCloud-enabled App ID
Push Notifications and Game Center are automatically enabled, but iCloud requires you to manually enable it. Click the Configure button to continue.
configureicloud
On the next screen, click the checkbox next to Enable for iCloud and click OK when the popup appears. If all works well, you will see a green icon next to the word Enabled. Then just click Done to finish.
enableforicloud
2) Create a provisioning profile for that App ID
Still in the iOS Provisioning Portal, switch to the Provisioning tab, and click New Profile. Select the App ID you just created from the dropdown.
After creating the profile, refresh the page until it is ready for download, and then download it to your machine. Once it’s downloaded, double click it to bring it into Xcode, and verify that it is visible in Xcode’s Organizer:
3) Configure your Xcode project for iCloud
Once you’ve finished creating the project, select your project in the Project Navigator and select the project target. Select the Summary tab, and scroll way down to the Entitlements section.
Once you’re there, click the Enable Entitlements checkbox, and it will auto-populate the other fields based on your App ID, as shown below:
entitlements
This is what the fields here mean:
→ The Entitlements File points to a property list file which, much like the info.plist file, includes specifications about application entitlements.
→ The iCloud Key-Value Store represents the unique identifier which points to the key-value store in iCloud.
→ The iCloud Containers section represents “directories” in the cloud in which your application can read/write documents. Yes, you have read correctly, I said applications (plural), for a user’s container can be managed by more than one application. The only requirement is that applications have to be created by the same team (as set up in the iTunes Developer Center).
→ The Keychain Access Groups includes keys needed by applications which are sharing keychain data.

Checking for iCloud Availability

When building an application which makes use of iCloud, the best thing to do is to check the availability of iCloud as soon as the application starts. Although iCloud is available on all iOS 5 devices, the user might not have configured it.
To avoid possible unattended behaviors or crashes, you should check if iCloud is available before using it. Let’s see how this works.
Open up AppDelegate.m, and add the following code at the bottom of application:didFinishLaunchingWithOptions (before the return YES):
NSURL *ubiq = [[NSFileManager defaultManager]
URLForUbiquityContainerIdentifier:nil];
if (ubiq) {
NSLog(@”iCloud access at %@”, ubiq);
// TODO: Load document…
} else {
NSLog(@”No iCloud access”);
}

iCloud API Overview

n iCloud UIDocument acts as middleware between the file itself and the actual data. In your apps, you’d usually create a subclass of UIDocument and override a few methods on it that we’ll discuss below.
UIDocument implements the NSFilePresenter protocol for you and does its work in the background, so the application is not blocked when opening or saving files, and the user can continue working with it. Such a behavior is enabled by a double queue architecture.
The first queue, the main thread of the application, is the one where your code is executed. Here you can open, close and edit files. The second queue is on the background and it is managed by UIKit.
When we want to open a file stored in iCloud. We’d send a message like the following:
[doc openWithCompletionHandler:^(BOOL success) {
// Code to run when the open has completed
}];
This triggers a ‘read’ message into the background queue. You can’t call this method directly, for it gets called when you execute openWithCompletionHandler. Such an operation might take some time.Once the reading is done we are free to load the data returned by the read operation.
This is exactly where UIDocument comes in handy, because you can override the loadFromContents:ofType:error method to read the data into your UIDocument subclass.
- (BOOL)loadFromContents:(id)contents ofType:(NSString *)typeName
error:(NSError **)outError{
self.noteContent = [[NSString alloc]
initWithBytes:[contents bytes]
length:[contents length]
encoding:NSUTF8StringEncoding];
return YES;
}
This method is called by the background queue whenever the read operation has been completed.
After loadFromContents:ofType:error completes, you’ll receive the callback you provided in the openWithCompletionHandler: block,To sum up, when you open a file you receive two callbacks: first in your UIDocument subclass when data has been read, and secondly when open operation is completely finished.
The write operation is pretty similar and it exploits the same double queue. The difference is that when opening a file we have to parse an NSData instance, but while writing we have to convert our document’s data to NSData and provide it to the background queue.
To save a document, you can either manually initiate the process by writing code, or via the autosaving feature implemented in UIDocument.
If you want to save manually, you’d call a method like this:
[doc saveToURL:[doc fileURL]
forSaveOperation:UIDocumentSaveForCreating
completionHandler:^(BOOL success) {
// Code to run when the save has completed
}];
Here you should return an NSData instance which describes the current model to be saved.
write the background queue accomplished by overriding another method of UIDocument – contentsForType:error.
- (id)contentsForType:(NSString *)typeName error:(NSError **)outError {
return [NSData dataWithBytes:[self.noteContent UTF8String]
length:[self.noteContent length]];
}
The rest is taken care of in the background queue, which manages the storing of data. Once done the code in the completion handler will be executed.

Subclassing UIDocument

Create a new file with the class template. Name the class, and make it a subclass of UIDocument.
#import “AppDelegate.h”
@interface iCloudDoc : UIDocument{
}
@end
As we have learned above we have two override points, one when we read and one when we write. Add the implementation of these by replacing iCloudDoc.m with the following:
#import “iCloudDoc.h”
@implementation iCloudDoc
- (NSString *) GetDatabasePath:(NSString *)dbName{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
return [documentsDir stringByAppendingPathComponent:dbName];
}
// Called whenever the application reads data from the file system
- (BOOL)loadFromContents:(id)contents ofType:(NSString *)typeName error:(NSError **)outError{
if ([contents length] > 0) {
NSData *data = [NSData dataWithBytes:[contents bytes] length:[contents length]];
NSString *filePath = [self GetDatabasePath:@"LeadRunnerDB.db"];
[data writeToFile:filePath atomically:YES];
}
return YES;
}
When we load a file we get the NSData contents returned by the background queue. Conversely, when we save we have to save file into an NSData object.
// Called whenever the application (auto)saves the content of a note
- (id)contentsForType:(NSString *)typeName error:(NSError **)outError {
NSString *filePath = [self GetDatabasePath:@"LeadRunnerDB.db"];
NSData *data = [NSData dataWithContentsOfFile:filePath];
return data;
}
@end
Believe it or not, the code we need to model the document is already over! Now we can move to the code related to loading and updating.

Opening an iCloud File

let’s extend the application delegate to keep track of our data, and a metadata query to look up the document in iCloud. Modify AppDelegate.h to look like the following:
@interface AppDelegate : UIResponder <UIApplicationDelegate>{
}
@property (nonatomic,retain) NSMetadataQuery *query;
@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) UINavigationController *navigationController;
- (void)loadNotes;
@end
Then switch to AppDelegate.m and synthesize the new properties:
@synthesize query = _query;
We’ve already added code into application:didFinishLaunchingWithOptions to check for the availability of iCloud. If iCloud is available, we want to call the new method we’re about to write to load our document from iCloud, so add the following line
[self loadDocument];
If you ever worked with Spotlight on the Mac, you’ll be familiar with the class NSMetadataQuery. It is a class to represent results of a query related to the properties of an object, such as a file.
In building such a query you have the possibility to specify parameters and scope, i.e. what you are looking for and where. In the case of iCloud files the scope is always NSMetadataQueryUbiquitousDocumentsScope.
You can have multiple scopes, so we have to build an array containing just one item.
Now you can provide the parameters of the query. Basically, you build a predicate and set it as parameter of a query/search.
When you use %@ in predicates, it wraps the value you provide in quotes. You don’t want this for keypaths, so you use %K instead to avoid wrapping it in quotes.
Now the query is ready to be run, but since it is an asynchronous process we need to set up an observer to catch a notification when it completes.
NSMetadataQueryDidFinishGatheringNotification. This is posted when the query has finished gathering info from iCloud.
- (void)loadNotes {
NSURL *ubiq = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
if (ubiq) {
self.query = [[NSMetadataQuery alloc] init];
[self.query setSearchScopes:[NSArray arrayWithObject:NSMetadataQueryUbiquitousDocumentsScope]];
NSPredicate *pred = [NSPredicate predicateWithFormat: @"%K like 'LeadRunnerDB.db*'", NSMetadataItemFSNameKey];
[self.query setPredicate:pred];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(queryDidFinishGathering:)
name:NSMetadataQueryDidFinishGatheringNotification
object:self.query];
[self.query startQuery];
} else {
NSLog(@”No iCloud access”);
}
}
Now that this is in place, add the code for the method that will be called when the query completes:
- (void)queryDidFinishGathering:(NSNotification *)notification {
NSMetadataQuery *query = [notification object];
[query disableUpdates];
[query stopQuery];
[self loadData:query];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:NSMetadataQueryDidFinishGatheringNotification
object:query];
self.query = nil;
}
if you don’t stop it it runs forever or until you quit the application. Especially in a cloud environment things can change often. It might happen that while you are processing the results of a query, due to live updates, the results change! So it is important to stop this process by calling disableUpdates and stopQuery. In particular the first prevents live updates and the second allows you to stop a process without deleting already collected results.
We then remove ourselves as an observer to ignore further notifications, and finally call a method to load the document, passing the NSMetadataQuery as a parameter.
Add the starter implementation of this method next (add this above queryDidFinishGathering):
- (void)loadData:(NSMetadataQuery *)query {
for (NSMetadataItem *item in [query results]) {
NSURL *url = [item valueForAttribute:NSMetadataItemURLKey];
iCloudDoc *doc = [[iCloudDoc alloc] initWithFileURL:url];
[doc openWithCompletionHandler:^(BOOL success) {
if (success) {
NSLog(@"database to open from iCloud");
} else {
NSLog(@"failed to open from iCloud");
}
}];
}
}
When you create a UIDocument (or a subclass of UIDocument like iCloudDoc), you always have to use the initWithFileURL initializer and give it the URL of the document to open. We call that here, passing in the URL of the located file, and store it away in an instance variable.
Now we are ready to open the Document. As explained previously you can open a document with the openWithCompletionHandler method, so continue loadData as follows:
You can run the app now, and it seems to work… except it never prints out either of the above messages! This is because there is currently no document in our container in iCloud, so the search isn’t finding anything (and the result count is 0).
When the query returns zero results, we should:
→ Retrieve the local iCloud directory
→ Initialize an instance of document in that directory
→ Call the saveToURL method
→ When the save is successful we can call openWithCompletionHandler.
Compile and run your app, and you should see the “database to open from iCloud” message arrive the first time you run it, and “iCloud document opened” in subsequent runs.
You can even try this on a second device, and you should see the “database to open from iCloud ” message show up on the second device (because the document already exists on iCloud now!)

Data Sharing on iCloud from iPhone/iPad with iOS 5.0


In Apple's recent release iOS 5.0, major feature is iCloud service. iCloud is the service for sharing data of your application which is running in different devices. iCloud service can be use in application many different ways i.e. data sharing (where you can set values on key like for application NSUserDefaults), Document sharing and database sharing by using core data.

For iCloud integration, you must have Xcode 4.2 with iOS 5.0 device. You can not test this feature in iPhone/iPad Simulator.

Here is the some easier steps for data sharing :
  1. Create application specific (i.e. com.your company.applicationname) apple id from Apple Developer Portal.
  2. Enable iCloud service for that App ID and create provisioning profile and install it on your mac.
  3. Create new project in Xcode with same app Id earlier created.
  4. Select target of application, click on summary and scroll down to Entitlement section. Click on custom entitlements.




  5. Above action will add "$ProjectName.Entitlement" file in your project. Add following keys in entitlement.
    com.apple.developer.ubiquity-container-identifiers as array
    com.apple.developer.ubiquity-kvstore-identifier as string




  6.  Now add valur for key with $TeamID.com.yourcompany.applicationName. Don't bother about TeamID. There are two ways to find Team ID. First, open provisioning profile into "TextEdit", you will find as below image. You can also find Team Id from member center -> Account Info.


  7. Provisioning Profile


    Member Center




  8. That's it from configuration side, Now you can add code

    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSURL *iCloudURL = [fileManager URLForUbiquityContainerIdentifier:@"$TeamID.com.yourcompany.applicationname"];
    NSLog(@"%@", [iCloudURL absoluteString]);

    //iCloudURL == nil if iCloud is not supported or enable.

    if(iCloudURL){
           NSUbiquitousKeyValueStore *iCloudStore = [NSUbiquitousKeyValueStore defaultStore];
          [iCloudStore setString:@"Success" forKey:@"iCloudStatus"];
          [iCloudStore synchronize]; // For Synchronizing with iCloud Server
          NSLog(@"iCloud status : %@", [iCloudStore stringForKey:@"iCloudStatus"]);
    }
  9. You can also verify data storage from iPhone Settings -> iCloud -> Storage & Backup -> Manage Storage. Also, In Mac -> System Preference -> iCloud -> Manage Storage.




    Monday 30 July 2012

    Dropbox Integration in iPhone


    Requirements:


    1. You need the 4.0 version of the iPhone SDK. The version of your XCode should
    be at least 3.2.3.
    2. You need to have registered as a Dropbox application with mobile access at 
    http://dropbox.com/developers. You should have a consumer key and secret.
    3. You need to download the dropbox sdk from https://www.dropbox.com/developers/releases

    A. Adding DropboxSDK to your project


    1. Open your project in XCode
    2. Right-click on your project in the group tree in the left pane
    3. Select Add -> Existing Files...
    4. Navigate to where you uncompressed the Dropbox SDK and select the DropboxSDK
    subfolder
    5. Select "Copy items into destination group's folder"
    6. Make sure "Recursively create groups for any added folders" is selected
    7. Press Add button
    8. Find the Frameworks folder in your app's group tree in the left pane
    9. Make sure the framework Security.framework is added to your project
    10. If not, right-click on Frameworks and select Add -> Existing Frameworks...
    11. Select Security.framework from the list and select Add
    12. Build your application. At this point you should have no build failures or
    warning

    B. Login successfully in your app


    1. In your application delegate's application:didFinishLaunchingWithOptions:
    method, add the following code:
    DBSession* dbSession = [[[DBSession alloc] initWithConsumerKey:@"<YOUR CONSUMER KEY>" consumerSecret:@"<YOUR CONSUMER SECRET>"] autorelease];
    [DBSession setSharedSession:dbSession];

    Note: you will need to #import "DropboxSDK.h" at the top of this file

    2. Somewhere in your app, add an event to launch the login controller, which
    should look something like this:
    - (void)didPressLink {
    DBLoginController* controller = [[DBLoginController new] autorelease];
    [controller presentFromController:self];
    }

    Note: you will need to #import "DropboxSDK.h" at the top of this file

    C. Creating folder in your dropbox using your App


    1. In your .m file add the below code,
    @interface DropBoxViewController () < DBLoginControllerDelegate, DBRestClientDelegate>
    
    @property (nonatomic, readonly) DBRestClient* restClient;
    @end
    #pragma mark -
    #pragma mark DBLoginControllerDelegate methods
    - (void)loginControllerDidLogin:(DBLoginController*)controller
    {
    restClient = [self restClient];
    [restClient setDelegate:self];
    [def setBool:YES forKey:@"userLoggedToDropboxAccnt"];
    [NSUserDefaults resetStandardUserDefaults];
    [restClient loadMetadata:@"" withHash:photosHash];
    }
    - (void)loginControllerDidCancel:(DBLoginController*)controller {
    }
    - (DBRestClient*)restClient {
    if (restClient == nil) {
    restClient = [[DBRestClient alloc] initWithSession:[DBSession sharedSession]];
    restClient.delegate = self;
    }
    return restClient;
    }
    #pragma mark -
    #pragma mark DBRestClientDelegate methods
    - (void)restClient:(DBRestClient*)client loadedMetadata:(DBMetadata*)metadata {
    [photosHash release];
    photosHash = [metadata.hash retain];
    NSMutableArray* newPhotoPaths = [NSMutableArray new];
    for (DBMetadata* child in metadata.contents) {
    [newPhotoPaths addObject:child.path];
    }
    [photoPaths release];
    photoPaths = newPhotoPaths;
    self.contentArray = photoPaths;
    if([photoPaths containsObject:folderNmTxtField.text]){
    }
    else{
    [restClient createFolder:folderNmTxtField.text];
    }
    }

    photosHash is of type NSString defined in .h file
    photoPaths is an NSArray defined in .h file 

    D.Uploading file in yur dropbox using your app


    if restClient not initialized earlier, add the below code
    restClient=[self restClient];
    [restClient setDelegate:self];
    [restClient loadMetadata:@"" withHash:photosHash];

    for uploading,

    [restClient uploadFile: filename toPath: (folder in which file is to be uploaded) fromPath: (path of the file to be uploaded);

    Friday 27 July 2012

    Drop Down Custom View For iPhone applications.


    Wanted to have a drop-down view like we have in html element, allows user to select one option form list of option.
    Have created sample application that demonstrates the use of this custom view.
    Sample project available to download athttp://code.google.com/p/dropdowndemo/downloads/list.
    Adding instruction how to use view in you application.
    1. Import QuartzCore.framework in your application.
    2. Import DropDownView.h file in the view controller.
    3. Have an class variable dataArray to store data to be put into the table and make a class variable of DropDownView. Making DropDownView variable allows you to control the DropDownView.
    4. Use the DropDownViewDelgate and declare the delegate method in your application.
    5. Initialize the DropdownView variable and add the view in your current view, andy your ready to go.
    Below a demo sample classes.

    FirstController.h

    --------------------
    #import <UIKit/UIKit.h>
    
    #import "DropDownView.h"
    
    @interface FirstController : UIViewController<DropDownViewDelegate> {
    
     UIButton *button;
    
     NSArray *arrayData;
    
     DropDownView *dropDownView;
    
    }
    
    @property (nonatomic,retain) IBOutlet UIButton *button;
    
    -(IBAction)actionButtonClick;
    
    @end
    
    --------------
    

    FirstController.m

    -----------
    #import "FirstController.h"
    
    @implementation FirstController
    
    @synthesize button;
    
    - (void)viewDidLoad {
    
     [super viewDidLoad];
    
     arrayData = [[NSArray alloc] initWithArray:[NSArray arrayWithObjects:@"Test1",@"Test2",nil]];
    
     dropDownView = [[DropDownView alloc] initWithArrayData:arrayData cellHeight:30 heightTableView:200 paddingTop:-8 paddingLeft:-5 paddingRight:-10 refView:button animation:BLENDIN openAnimationDuration:2 closeAnimationDuration:2];
    
     dropDownView.delegate = self;
    
     [self.view addSubview:dropDownView.view];
    
     [button setTitle:[arrayData objectAtIndex:0] forState:UIControlStateNormal];
    
    }
    
    - (void)didReceiveMemoryWarning {
     [super didReceiveMemoryWarning];
    }
    
    - (void)viewDidUnload {
     [super viewDidUnload];
    
    }
    
    - (void)dealloc {
    
     [button release];
    
     [super dealloc];
    
    }
    
    #pragma mark -
    #pragma mark DropDownViewDelegate
    
    -(void)dropDownCellSelected:(NSInteger)returnIndex{
    
     [button setTitle:[arrayData objectAtIndex:returnIndex] forState:UIControlStateNormal];
    
    }    
    
    #pragma mark -
    #pragma mark Class methods
    
    -(IBAction)actionButtonClick{
    
     [dropDownView openAnimation];
    
    }    
    
    @end
    
    ------------


    DropDownView Class File are available in above linked ProjectDemo.

     

    Thursday 26 July 2012

    How and when to use NSAssert ?


    If you want to write a code

    1. Which is easier to debug(for you as well as others :P)
    2. is a standard piece of code

    Don't forget to include NSAssert in your code.

    Here is an example of how you can use it:

    //Assertion Code  
    NSAssert((count <= 4)&&(count >= 3),@"colorString components count should be in range(3,5)"); 

    Whenever the condition given above becomes false, it raises NSInternalInconsistencyException along with description message. 
    Result in Console:

    *** Assertion failure in +[ColorClass colorWithComponent:], /Users/mac/Desktop/ChartLib/Lib Files/Colors/ColorClass.m:66
    *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'colorString components count should be in range(3,5)'


    Note:Please make sure that your XCode should be running in debug mode.

    How does UITableViewCell reorder, expand/shrink work ?



    So you spent way too much time in figuring out how to make UITableview collapsible, you are at the right tutorial.This sample code, I have written is a more like a template which developers can take and use in their own application customize it according to their need. It basically deals with TableView property of reordering, expanding and shrinking.

    Here are some screenshots which display the work on UITableview collapse expand process.


    You can either expand them OR                 Fold them up to see the UITableview collapsed section.


    While reordering the cells in editing mode(Press Edit button on top of Tableview on the tool bar to go into editing mode of table), you can move the cells with in the same Section like Row 4 is being moved around(You have to press on the "list icon" (the icon with 3 tiny horizontal lines) which is present in the cells and then drag the cell around.) You don't have to give specific image, this is inbuilt image of reordering which comes with Apple API.






    You can move the cell from one section to another section entirely.As you can see here that Cell 5 is being moved from Section 1 to Section 2.



























    Then in  MainController.m >


    cellArray  is the array which stores  title which will be displayed on each cell in various sections.
    Its structure is as following

    cellArray{
    {@"row1",@"row2",@"row3", @"row4",@"row5"}, // Titles  for cells in section 1
    {@"row1",@"row2",@"row3", @"row4",@"row5"},// Titles  for cells in section 2
    {@"row1",@"row2",@"row3", @"row4",@"row5"},// Titles  for cells in section 3
    {@"row1",@"row2",@"row3", @"row4",@"row5"},// Titles  for cells in section 4
    {@"row1",@"row2",@"row3", @"row4",@"row5"},// Titles  for cells in section 5
    nil
    }

    So its an array of arrays. When you move cells around on your screen, these title strings will move in the array as well.




    - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath


    I am finally printing the reordered cell array(which has strings stored presented on each cell) in the given above method. Now its your job to save the updated cellArray into somewhere so that changes can be reflected back when you open the app next time and when it loads up the cellArray again on the screen.
    Hope this code helps save someone lots of time.

    Download the code HERE

    Wednesday 25 July 2012

    Save NSDate in CoreData

    1. In your model file.
    Create an entity MyDate with attribute datestring of datatype date(select it from dropdown).


    2. Save your date


        //Create date from the string
        NSDateFormatter *dateFormatter = [[NSDateFormatter allocinit];
        [dateFormatter setDateFormat:@"dd-MM-yyyy"];
        NSDate *date=[dateFormatter dateFromString:dateString_];
        [dateFormatter release];
        dateFormatter=nil;
        
        
        
        //Save the auditDate Now    
        MyDate *obj = [NSEntityDescription insertNewObjectForEntityForName:@"MyDate"inManagedObjectContext:context];
        [obj setValue:date forKey:@"datestring"];
        
        NSError* error = nil;
        [context save:&error];
        if (error)
        {
            NSLog(@"%@", error);
        }




    3. Retrieve your date

    When you  retrieve  MyDate objects, accessing value of key datestring will return NSDate, you can convert that to NSString to display it on your screen.

    Tuesday 24 July 2012

    How to use inbuilt Facebook/Twitter API in iOS6.


    You need to add Social.framework in your project.
    Add to your file following #import "Social/Social.h"

    You can create 3 type of service:


    SLServiceTypeTwitter;
    SLServiceTypeFacebook;
    SLServiceTypeSinaWeibo;

    I have created service of Facebook.


    SLComposeViewController *fbController=[SLComposeViewControllercomposeViewControllerForServiceType:SLServiceTypeFacebook];


    if([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook])
    {
            SLComposeViewControllerCompletionHandler __block completionHandler=^(SLComposeViewControllerResultresult){
            
            [fbController dismissViewControllerAnimated:YES completion:nil];
            
            switch(result){
            case SLComposeViewControllerResultCancelled:
            default:
            {
                NSLog(@"Cancelled.....");
                
            }
                break;
            case SLComposeViewControllerResultDone:
            {
                NSLog(@"Posted....");
            }
                break;
        }};
        
        [fbController addImage:[UIImage imageNamed:@"1.jpg"]];
        [fbController setInitialText:@"Check out this article."];
        [fbController addURL:[NSURL URLWithString:@"http://soulwithmobiletechnology.blogspot.com/"]];
        [fbController setCompletionHandler:completionHandler];
        [self presentViewController:fbController animated:YES completion:nil];
    }



    I have added image which will be posted with the message and URL on the Facebook page. Here is what the message looks like on FB.









    Following are some screenshots of the app running.


    If the Facebook account is not set up on device, it gives you this pop up.

    SLComposeViewController with added URL and Image.

    SLComposeViewController with added text,URL and image,
    Also location has been set on the post
    just like we can do on our Facebook page.

    You can change the album in which you want to post this image.

    You can choose which group you want to display this post to.





    Link to download the sample code.