iOS 10 – User’s Privacy revised.

A significant change in iOS 10 is that you must declare ahead of time any access to private data or your App will crash. The fix is quick but easy to overlook if the usage is not a major feature of an App so here is your reminder if you are planning an iOS 10 migration.

 

Because being forgetful can cause you a lot

Once you link with iOS 10 you must declare access to any user private data types. You do this by adding a usage key to your app’s Info.plist together with a purpose string. The list of frameworks that count as private data is a long one:

Contacts, Calendar, Reminders, Photos, Bluetooth Sharing, Microphone, Camera, Location, Health, HomeKit, Media Library, Motion, CallKit, Speech Recognition, SiriKit, TV Provider.

If you are using one of these frameworks and fail to declare the usage your app will crash when it first makes the access. The crash log helpfully tells you which key you are missing. For example, this is the result of accessing the camera without adding the key to Info.plist:

This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app’s Info.plist must contain an NSCameraUsageDescription key with a string value explaining to the user how the app uses this data.

To avoid the crash we need to add the suggested key to ‘Info.plist’ (Xcode 8 already contains the full list of possible keys):

2016-07-03-001.png

 

The system shows the purpose string when asking the user to allow access (so you may want to localize it):

2016-07-03-002.png

 

You may need to refer below links to know more about this.
https://developer.apple.com/videos/play/wwdc2016/709/
https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html

 

 

 

iOS 10 compatibility with notifications.

Step 1 : 

In your Appdelegate.h file

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000

#import <UserNotifications/UserNotifications.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate, UNUserNotificationCenterDelegate>

#else

@interface AppDelegate : UIResponder <UIApplicationDelegate>

#endif

Step 2 : 

In your Appdelegate.m file

– (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

// other code

  NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];

    if([standardDefaults objectForKey:@”NotificationDeviceToken”]) {

        // Register the supported interaction types.

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000

        {

            UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];

            center.delegate = self;

            [center requestAuthorizationWithOptions: (UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error){

                if( !error ){

                    [[UIApplication sharedApplication] registerForRemoteNotifications];

                }

            }];

        }

#else

        {

            UIUserNotificationType types = UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert;

            UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];

            [[UIApplication sharedApplication] registerUserNotificationSettings:settings];

            // Register for remote notifications.

            [[UIApplication sharedApplication] registerForRemoteNotifications];

        }

#endif

    }

return YES;

}

– (void)application:(UIApplication *)application didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo {

        NSLog( @”===%s===Notification: %@”,__FUNCTION__, userInfo );

    if (application.applicationState != UIApplicationStateActive)

    {

        // Action to be performed when you recieve push notifications.

    }

}

-(void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void(^)(UIBackgroundFetchResult))completionHandler {

    

    DLog( @”===%s===Notification: %@”,__FUNCTION__, userInfo );

    [Crittercism leaveBreadcrumb:[NSString stringWithFormat:@”%s”, __FUNCTION__]];

    // iOS 10 will handle notifications through other methods

    if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@”10.0″))

    {

        NSLog( @”iOS version >= 10. Let NotificationCenter handle this one.” );

        // set a member variable to tell the new delegate that this is background

        return;

    }

    

    if (application.applicationState != UIApplicationStateActive)

    {

        // Action to be performed when you recieve push notifications.

        completionHandler( UIBackgroundFetchResultNewData );

    }

}

#pragma mark iOS 10 UserNotification delegates

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000

– (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {

    

    NSLog( @”Handle push from foreground – %s=======Notification:%@”,__FUNCTION__,notification.request.content.userInfo);

    // custom code to handle push while app is in the foreground

    // Action to be performed when you recieve push notifications.

}

– (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {

   

    NSLog( @”Handle push from background or closed – %s=======Notification:%@”,__FUNCTION__,response.notification.request.content.userInfo);    

    // if you set a member variable in didReceiveRemoteNotification, you  will know if this is from closed or background

           // Action to be performed when you recieve push notifications.

}

#endif

Useful macros for different screen size of iOS devices.

#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
#define IS_RETINA ([[UIScreen mainScreen] scale] >= 2.0)

#define SCREEN_WIDTH ([[UIScreen mainScreen] bounds].size.width)
#define SCREEN_HEIGHT ([[UIScreen mainScreen] bounds].size.height)
#define SCREEN_MAX_LENGTH (MAX(SCREEN_WIDTH, SCREEN_HEIGHT))
#define SCREEN_MIN_LENGTH (MIN(SCREEN_WIDTH, SCREEN_HEIGHT))

#define IS_IPHONE_4_OR_LESS (IS_IPHONE && SCREEN_MAX_LENGTH < 568.0)
#define IS_IPHONE_5 (IS_IPHONE && SCREEN_MAX_LENGTH == 568.0)
#define IS_IPHONE_6 (IS_IPHONE && SCREEN_MAX_LENGTH == 667.0)
#define IS_IPHONE_6P (IS_IPHONE && SCREEN_MAX_LENGTH == 736.0)

Note: If iPhone 6 is in zoomed mode the UI is a zoomed up version of iPhone 5. This is reflected in the macros.

How to convert .caf to .wav ?

-(void) convertToWav
{

NSString *cafFilePath=[[NSBundle mainBundle]pathForResource:@"test" ofType:@"caf"];

NSURL *assetURL = [NSURL fileURLWithPath:cafFilePath];
AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL:assetURL options:nil];

NSError *assetError = nil;
AVAssetReader *assetReader = [AVAssetReader assetReaderWithAsset:songAsset
                                                           error:&assetError]
;
if (assetError) {
    NSLog (@"error: %@", assetError);
    return;
}

AVAssetReaderOutput *assetReaderOutput = [AVAssetReaderAudioMixOutput
                                          assetReaderAudioMixOutputWithAudioTracks:songAsset.tracks
                                          audioSettings: nil];
if (! [assetReader canAddOutput: assetReaderOutput]) {
    NSLog (@"can't add reader output... die!");
    return;
}
[assetReader addOutput: assetReaderOutput];

NSString *title = @"MyRec";
NSArray *docDirs = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [docDirs objectAtIndex: 0];
NSString *wavFilePath = [[docDir stringByAppendingPathComponent :title]
                         stringByAppendingPathExtension:@"wav"];
if ([[NSFileManager defaultManager] fileExistsAtPath:wavFilePath])
{
    [[NSFileManager defaultManager] removeItemAtPath:wavFilePath error:nil];
}
NSURL *exportURL = [NSURL fileURLWithPath:wavFilePath];
AVAssetWriter *assetWriter = [AVAssetWriter assetWriterWithURL:exportURL
                                                      fileType:AVFileTypeWAVE
                                                         error:&assetError];
if (assetError)
{
    NSLog (@"error: %@", assetError);
    return;
}

AudioChannelLayout channelLayout;
memset(&channelLayout, 0, sizeof(AudioChannelLayout));
channelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
NSDictionary *outputSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                                [NSNumber numberWithInt:kAudioFormatLinearPCM], AVFormatIDKey,
                                [NSNumber numberWithFloat:44100.0], AVSampleRateKey,
                                [NSNumber numberWithInt:2], AVNumberOfChannelsKey,
                                [NSData dataWithBytes:&channelLayout length:sizeof(AudioChannelLayout)], AVChannelLayoutKey,
                                [NSNumber numberWithInt:16], AVLinearPCMBitDepthKey,
                                [NSNumber numberWithBool:NO], AVLinearPCMIsNonInterleaved,
                                [NSNumber numberWithBool:NO],AVLinearPCMIsFloatKey,
                                [NSNumber numberWithBool:NO], AVLinearPCMIsBigEndianKey,
                                nil];
AVAssetWriterInput *assetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio
                                                                          outputSettings:outputSettings];
if ([assetWriter canAddInput:assetWriterInput])
{
    [assetWriter addInput:assetWriterInput];
}
else
{
    NSLog (@"can't add asset writer input... die!");
    return;
}

assetWriterInput.expectsMediaDataInRealTime = NO;

[assetWriter startWriting];
[assetReader startReading];

AVAssetTrack *soundTrack = [songAsset.tracks objectAtIndex:0];
CMTime startTime = CMTimeMake (0, soundTrack.naturalTimeScale);
[assetWriter startSessionAtSourceTime: startTime];

__block UInt64 convertedByteCount = 0;
dispatch_queue_t mediaInputQueue = dispatch_queue_create("mediaInputQueue", NULL);

[assetWriterInput requestMediaDataWhenReadyOnQueue:mediaInputQueue
                                        usingBlock: ^
 {

     while (assetWriterInput.readyForMoreMediaData)
     {
         CMSampleBufferRef nextBuffer = [assetReaderOutput copyNextSampleBuffer];
         if (nextBuffer)
         {
             // append buffer
             [assetWriterInput appendSampleBuffer: nextBuffer];
             convertedByteCount += CMSampleBufferGetTotalSampleSize (nextBuffer);
             CMTime progressTime = CMSampleBufferGetPresentationTimeStamp(nextBuffer);

             CMTime sampleDuration = CMSampleBufferGetDuration(nextBuffer);
             if (CMTIME_IS_NUMERIC(sampleDuration))
                 progressTime= CMTimeAdd(progressTime, sampleDuration);
             float dProgress= CMTimeGetSeconds(progressTime) / CMTimeGetSeconds(songAsset.duration);
             NSLog(@"%f",dProgress);
         }
         else
         {

             [assetWriterInput markAsFinished];
             //              [assetWriter finishWriting];
             [assetReader cancelReading];

         }
     }
 }];
}
Link

iOS 8 App icon sizes

Asset

iPhone 6 Plus (@3x)

iPhone 6 and iPhone 5 (@2x)

iPhone 4s (@2x)

iPad and iPad mini (@2x)

iPad 2 and iPad mini (@1x)

App icon (required for all apps)

180 x 180

120 x 120

120 x 120

152 x 152

76 x 76

App icon for the App Store (required for all apps)

1024 x 1024

1024 x 1024

1024 x 1024

1024 x 1024

1024 x 1024

Launch file or image (required for all apps)

Use a launch file (seeLaunch Images)

For iPhone 6, use a launch file (see Launch Images)

For iPhone 5, 640 x 1136

640 x 960

1536 x 2048 (portrait)

2048 x 1536 (landscape)

768 x 1024 (portrait)

1024 x 768 (landscape)

Spotlight search results icon (recommended)

120 x 120

80 x 80

80 x 80

80 x 80

40 x 40

Settings icon (recommended)

87 x 87

58 x 58

58 x 58

58 x 58

29 x 29

Toolbar and navigation bar icon (optional)

About 66 x 66

About 44 x 44

About 44 x 44

About 44 x 44

About 22 x 22

Tab bar icon (optional)

About 75 x 75 (maximum: 144 x 96)

About 50 x 50 (maximum: 96 x 64)

About 50 x 50 (maximum: 96 x 64)

About 50 x 50 (maximum: 96 x 64)

About 25 x 25 (maximum: 48 x 32)

Default Newsstand cover icon for the App Store (required for Newsstand apps)

At least 1024 pixels on the longest edge

At least 1024 pixels on the longest edge

At least 1024 pixels on the longest edge

At least 1024 pixels on the longest edge

At least 512 pixels on the longest edge

Web clip icon (recommended for web apps and websites)

180 x 180

120 x 120

120 x 120

152 x 152

76 x 76

for more information.

https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/MobileHIG/IconMatrix.html#//apple_ref/doc/uid/TP40006556-CH27-SW1

iPhone 6 and iPhone 6 Plus conspiracy for launch images and screen sizes.

Here are the few steps how to do that ?

1 2 3
I didn’t want to introduce an asset catalog.

Adding the following to info.plist worked for me. (I edited it as a “source code”.) I then named the images Default-667h@2x.png and Default-736h@3x.png

<key>UILaunchImages</key>
<array>
<dict>
<key>UILaunchImageMinimumOSVersion</key>
<string>8.0</string>
<key>UILaunchImageName</key>
<string>Default-667h</string>
<key>UILaunchImageOrientation</key>
<string>Portrait</string>
<key>UILaunchImageSize</key>
<string>{375, 667}</string>
</dict>
<dict>
<key>UILaunchImageMinimumOSVersion</key>
<string>8.0</string>
<key>UILaunchImageName</key>
<string>Default-736h</string>
<key>UILaunchImageOrientation</key>
<string>Portrait</string>
<key>UILaunchImageSize</key>
<string>{414, 736}</string>
</dict>
</array>

Apple’s website claims that the resolution is 1080p: 1920 x 1080

However, the launch screen required by Xcode (6.0.1)  is 2208 x 1242.

The iPhone 6 Plus renders internally using @3x assets at a virtual resolution of 2208×1242 (with 736×414points), then samples that down for display. The same as using a scaled resolution on a Retina MacBook — it lets them hit an integral multiple for pixel assets while still having e.g. 12pt text look the same size on the screen.

So, yes, the launch screens need to be that size.

The maths:

The 6, the 5s, the 5, the 4s and the 4 are all 326 pixels per inch, and use @2x assets to stick to the approximately 160 points per inch of all previous devices.

The 6 Plus is 401 pixels per inch. So it’d hypothetically need roughly @2.46x assets. Instead Apple uses @3x assets and scales the complete output down to about 84% of its natural size.

In practice Apple has decided to go with more like 87%, turning the 1080 into 1242. No doubt that was to find something as close as possible to 84% that still produced integral sizes in both directions — 1242/1080 = 2208/1920 exactly, whereas if you’d turned the 1080 into, say, 1286, you’d somehow need to render 2286.22 pixels vertically to scale well.

When the App is built for the new phones the resolutions available are: Retina HD 5.5 (iPhone 6 Plus) 1242 x 2208 and Retina HD 4.7 (iPhone 6) 750 x 1334. This is causing the confusion above. To build Apps that utilize the full screen size of the new phones add LaunchImages in the sizes: 1242 x 2208, 2208 x 1242 and 750 x 1334.

Size for iPhone 6 Plus with @3x scaling (Apple name: Retina HD 5.5), Coordinate space: 414 x 736 points and 1242 x 2208 pixels, 401 ppi, screen physical size is 2.7 x 4.8 in or 68 x 122 mm

    Screen bounds: {{0, 0}, {414, 736}}, Screen resolution: <UIScreen: 0x7f97fad330b0; bounds = {{0, 0}, {414, 736}}; mode = <UIScreenMode: 0x7f97fae1ce00; size = 1242.000000 x 2208.000000>>, scale: 3.000000, nativeScale: 3.000000

Size for iPhone 6 with @2x scaling (Apple name: Retina HD 4.7), Coordinate space: 375 x 667 points and750 x 1334 pixels, 326 ppi, screen physical size is 2.3 x 4.1 in or 58 x 104 mm

    Screen bounds: {{0, 0}, {375, 667}}, Screen resolution: <UIScreen: 0x7fa01b5182d0; bounds = {{0, 0}, {375, 667}};  mode = <UIScreenMode: 0x7fa01b711760; size = 750.000000 x 1334.000000>>, scale: 2.000000, nativeScale: 2.000000

And iPhone 5 for comparison is 640 x 1136, iPhone 4 640 x 960.

Here is the code I used to check this out:

UIScreen *mainScreen = [UIScreen mainScreen];

 NSLog(@”Screen bounds: %@, Screen resolution: %@, scale: %f, nativeScale: %f”,

          NSStringFromCGRect(mainScreen.bounds), mainScreen.coordinateSpace, mainScreen.scale, mainScreen.nativeScale);

It explains the differences between old iPhones, iPhone 6 and iPhone 6 Plus. You can see comparison of screen sizes in points, rendered pixels and physical pixels. You will also find answer to your question there:

iPhone 6 Plus – with Retina display HD. Scaling factor is 3 and the image is afterwards downscaled from rendered 2208 × 1242 pixels to 1920 × 1080 pixels.

The downscaling ratio is 1920 / 2208 = 1080 / 1242 = 20 / 23. That means every 23 pixels from the original render have to be mapped to 20 physical pixels. In other words the image is scaled down to approximately 87% of its original size.

Use this demo images if you want.


Custom Contact Picker.

Create a plist

<?xml version=“1.0” encoding=“UTF-8”?>

<!DOCTYPE plist PUBLIC “-//Apple//DTD PLIST 1.0//EN”http://www.apple.com/DTDs/PropertyList-1.0.dtd>

<plist version=“1.0”>

<array>

<dict>

<key>FirstName</key>

<string>Steve</string>

<key>LastName</key>

<string>Jobs</string>

<key>EmailId</key>

<string>stevejobs@apple.com</string>

<key>PhoneNo</key>

<string>+19876543210</string>

</dict>

    <dict>

<key>FirstName</key>

<string>Johnathan</string>

<key>LastName</key>

<string>Ive</string>

<key>EmailId</key>

<string>johnyive@apple.com</string>

<key>PhoneNo</key>

<string>+11876543210</string>

</dict>

    <dict>

<key>FirstName</key>

<string>Tim</string>

<key>LastName</key>

<string>Cook</string>

<key>EmailId</key>

<string>timcook@apple.com</string>

<key>PhoneNo</key>

<string>+12876543210</string>

</dict>

    <dict>

<key>FirstName</key>

<string>Bill</string>

<key>LastName</key>

<string>Gates</string>

<key>EmailId</key>

<string>bill@microsoft.com</string>

<key>PhoneNo</key>

<string>+13876543210</string>

</dict>

    <dict>

<key>FirstName</key>

<string>Douglas</string>

<key>LastName</key>

<string>Larsson</string>

<key>EmailId</key>

<string>douglas@microsoft.com</string>

<key>PhoneNo</key>

<string>+13874543210</string>

</dict>

    <dict>

<key>FirstName</key>

<string>William</string>

<key>LastName</key>

<string>Seyf</string>

<key>EmailId</key>

<string>william@microsoft.com</string>

<key>PhoneNo</key>

<string>+138745433210</string>

</dict>

    <dict>

<key>FirstName</key>

<string>Randy</string>

<key>LastName</key>

<string>Otten</string>

<key>EmailId</key>

<string>randy@lenovo.com</string>

<key>PhoneNo</key>

<string>+13467433210</string>

</dict>

    <dict>

<key>FirstName</key>

<string>Robert</string>

<key>LastName</key>

<string>Pattinsion</string>

<key>EmailId</key>

<string>robby@lenovo.com</string>

<key>PhoneNo</key>

<string>+1342356710</string>

</dict>

    <dict>

<key>FirstName</key>

<string>Andy</string>

<key>LastName</key>

<string>Smith</string>

<key>EmailId</key>

<string>andysmith@lenovo.com</string>

<key>PhoneNo</key>

<string>+1342323710</string>

</dict>

    <dict>

<key>FirstName</key>

<string>Fed</string>

<key>LastName</key>

<string>Peterson</string>

<key>EmailId</key>

<string>fedp@google.com</string>

<key>PhoneNo</key>

<string>+1345673710</string>

</dict>

    <dict>

<key>FirstName</key>

<string>Charles</string>

<key>LastName</key>

<string>Atkinson</string>

<key>EmailId</key>

<string>rov@google.com</string>

<key>PhoneNo</key>

<string>+1312355610</string>

</dict>

</array>

</plist>

 

in ViewController.h

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController<UISearchBarDelegate,UITableViewDelegate,UITableViewDataSource,UIActionSheetDelegate>

{

    BOOL isSearching;

    CGFloat width,height;

}

@property (nonatomic, weak) IBOutletUITableView *tableView;

@property (nonatomic, weak) IBOutletUIScrollView *scrlContacts;

@property (nonatomic, strong) NSMutableArray *ary_contacts;

@property (nonatomic, strong) NSMutableArray *ary_filtered;

@property (nonatomic, strong) NSMutableArray *ary_selectedContacts;

@end

 

in ViewController.m

#import “ViewController.h”

#import “DetailViewController.h”

 

#define kHeightPadding 45

#define kWidthPadding 5

#define y 64

 

@interfaceViewController ()

 

@end

 

@implementation ViewController

 

 

– (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

{

    if (self)

    {

        self.ary_selectedContacts = [NSMutableArrayarray];

        width = 0;

        height = 0;

    }

    returnself;

}

 

– (void)viewDidLoad

{

    [superviewDidLoad];

    

    [self.searchDisplayController.searchContentsController.navigationControllersetNavigationBarHidden:YES];

    

    NSString* plistPath = [[NSBundlemainBundle] pathForResource:@”Contacts”ofType:@”plist”];

    NSArray *contentArray = [NSArray arrayWithContentsOfFile:plistPath];

    NSSortDescriptor *sort = [NSSortDescriptorsortDescriptorWithKey:@”FirstName”ascending:YES];

    NSArray *aryDesc = [NSArray arrayWithObject:sort];

    self.ary_contacts = [NSMutableArrayarrayWithArray:[contentArray sortedArrayUsingDescriptors:aryDesc]];

}

 

– (void)didReceiveMemoryWarning

{

    [superdidReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}

 

# pragma mark – UISearchBarDelegate

 

– (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar

{

    returnYES;

}

 

– (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar

{

    

}

 

– (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar

{

    returnYES;

}

 

– (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar

{

    

}

 

– (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText

{

    isSearching = TRUE;

    NSPredicate *resultPredicate = [NSPredicatepredicateWithFormat:@”FirstName CONTAINS[cd] %@ or LastName CONTAINS[cd] %@”,searchText,searchText];

     NSArray *matches = [self.ary_contacts filteredArrayUsingPredicate:resultPredicate];

    

    if (matches.count>0)

        self.ary_filtered = [NSMutableArray arrayWithArray:matches];

    

    [self.tableViewreloadData];

}

 

– (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar

{

    

}

 

– (void)searchBarCancelButtonClicked:(UISearchBar *) searchBar

{

    isSearching = FALSE;

    [self.tableViewreloadData];

}

 

#pragma mark – UITableViewDataSource & UITableViewDelegate

 

– (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

{

    if (isSearching)

        return self.ary_filtered.count;

    else

        return self.ary_contacts.count;

}

 

– (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

    static NSString *cellIdentifier = @”cell”;

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

    if (cell == nil)

    {

        cell = [[UITableViewCellalloc] initWithStyle:UITableViewCellStyleDefaultreuseIdentifier:cellIdentifier];

    }

    

    NSString *text;

    if (!isSearching)

        text = [[[self.ary_contactsobjectAtIndex:indexPath.row] valueForKey:@”FirstName”] stringByAppendingFormat:@” %@”,[[self.ary_contactsobjectAtIndex:indexPath.row] valueForKey:@”LastName”]];

    else

        text = [[[self.ary_filteredobjectAtIndex:indexPath.row] valueForKey:@”FirstName”] stringByAppendingFormat:@” %@”,[[self.ary_filteredobjectAtIndex:indexPath.row] valueForKey:@”LastName”]];

    

    cell.textLabel.text = text;

    return cell;

}

 

– (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

{

    self.scrlContacts.hidden = FALSE;

    NSString *text;

    if (!isSearching)

        text = [[[self.ary_contactsobjectAtIndex:indexPath.row] valueForKey:@”FirstName”] stringByAppendingFormat:@” %@”,[[self.ary_contactsobjectAtIndex:indexPath.row] valueForKey:@”LastName”]];

    else

        text = [[[self.ary_filteredobjectAtIndex:indexPath.row] valueForKey:@”FirstName”] stringByAppendingFormat:@” %@”,[[self.ary_filteredobjectAtIndex:indexPath.row] valueForKey:@”LastName”]];

    

    if ([self.ary_selectedContactscontainsObject:text])

    {

        UIAlertView *alerView = [[UIAlertViewalloc] initWithTitle:@”Information !!!”message:@”Contact has already added.”delegate:nilcancelButtonTitle:@”Ok”otherButtonTitles:nil];

        [alerView show];

    }

    else

        [UIViewanimateWithDuration:0.4delay:0options:UIViewAnimationOptionCurveEaseInanimations:^{

            [self.ary_selectedContacts addObject:text];

            [selfsetUpViewForContactSelection:text WithTag:indexPath.row];

        } completion:^(BOOL finished) {

           

        }];

}

 

– (void)setUpViewForContactSelection:(NSString *)text WithTag:(int)tag

{

    NSDictionary *attributes = @{NSFontAttributeName: [UIFont fontWithName:@”HelveticaNeue” size:14]};

    CGSize size = [text sizeWithAttributes:attributes];

    

    if (width >=200)

    {

        height = height + kHeightPadding;

        width = 0;

    }

    

    if (self.scrlContacts.frame.size.height >= 200)

    {

        [self.scrlContacts setFrame:CGRectMake(0, y, 320, 200)];

        self.scrlContacts.contentSizeCGSizeMake(320, (height>40)?(height + 50):50);

        [self.tableView setFrame:CGRectMake(0, y + self.scrlContacts.frame.size.height, 320, [UIScreen mainScreen].bounds.size.height – (y + self.scrlContacts.frame.size.height))];

    }

    else

    {

        [self.scrlContacts setFrame:CGRectMake(0, y, 320, (height>40)?(height + 50):50)];

        [self.tableView setFrame:CGRectMake(0, y + self.scrlContacts.frame.size.height, 320, [UIScreen mainScreen].bounds.size.height – (y + height + 50))];

    }

    

    UIButton *btn = [UIButtonbuttonWithType:UIButtonTypeCustom];

    btn.frame = CGRectMake(width, height, size.width + 50, 35);

    btn.layer.cornerRadius = 0;

    btn.layer.borderColor = [UIColorblackColor].CGColor;

    btn.backgroundColor = [UIColor greenColor];

    btn.layer.borderWidth = 2;

    btn.tag = tag;

    [btn setTitle:text forState:UIControlStateNormal];

    [btn setTitleColor:[UIColorblackColor] forState:UIControlStateNormal];

    

    UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizeralloc] initWithTarget:selfaction:@selector(btnPressed:)];

    longPressGesture.minimumPressDuration = 0.5;

    

    [btn addGestureRecognizer:longPressGesture];

    

    [self.scrlContacts addSubview:btn];

    

    width = width + kWidthPadding + size.width + 50;

}

 

– (void)btnPressed:(UILongPressGestureRecognizer *)sender

{

    if (sender.state == UIGestureRecognizerStateEnded)

    {

        UIActionSheet *actionsheet = [[UIActionSheetalloc] initWithTitle:nildelegate:selfcancelButtonTitle:@”Cancel”destructiveButtonTitle:@”Delete”otherButtonTitles:@”Show Detail”, nil];

        actionsheet.tag = sender.view.tag;

        [actionsheet showInView:self.view];

    }

}

 

– (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex

{

    if (buttonIndex == 0)

    {

        for (UIView *subView in self.scrlContacts.subviews)

        {

            if ([subView isKindOfClass:[UIButton class]])

            {

                if(subView.tag == actionSheet.tag)

                {

                    [subView removeFromSuperview];

                    [self.ary_selectedContacts removeObject:[(UIButton *)subView titleLabel].text];

                }

            }

        }

        

        width = 0;

        height = 0;

        for (UIView *subView in self.scrlContacts.subviews)

        {

            if ([subView isKindOfClass:[UIButton class]])

            {

                if (width >=200)

                {

                    height = height + kHeightPadding;

                    width = 0;

                }

                

                NSDictionary *attributes = @{NSFontAttributeName: [UIFont fontWithName:@”HelveticaNeue” size:14]};

                CGSize size = [[(UIButton *)subView titleLabel].text sizeWithAttributes:attributes];

                

                [self.scrlContacts setFrame:CGRectMake(0, y, 320, (height>40)?(height + 50):50)];

                [self.tableView setFrame:CGRectMake(0, y + self.scrlContacts.frame.size.height, 320, [UIScreen mainScreen].bounds.size.height – (y + height + 50))];

                [(UIButton *)subView setFrame:CGRectMake(width, height, size.width + 50, 35) ];

                

                width = width + kWidthPadding + size.width + 50;

            }

        }

        if (self.ary_selectedContacts.count == 0)

        {

            [self.scrlContacts setFrame:CGRectZero];

            [self.tableView setFrame:CGRectMake(0, y, 320, 504)];

        }

    }

    else if (buttonIndex == 1)

    {

        DetailViewController *obj_DetailViewController = [[DetailViewController alloc] initWithNibName:@”DetailViewController” bundle:nil];

        NSPredicate *predicate = [NSPredicatepredicateWithFormat:@”FirstName matches %@”,[[[self.ary_selectedContactsobjectAtIndex:actionSheet.tag] componentsSeparatedByString:@” “] objectAtIndex:0]];

        NSArray *array = [self.ary_contacts filteredArrayUsingPredicate:predicate];

        obj_DetailViewController.dictionary = [array objectAtIndex:0];

        [self.navigationController pushViewController:obj_DetailViewController animated:YES];

    }

}

Customise your own Edit-Done UINavigationBarButton

First, create two properties on your class for your two UIBarButtonItems.

@property (nonatomic, retain) UIBarButtonItem *editButton;
@property (nonatomic, retain) UIBarButtonItem *doneButton;

 

– (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

{

self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];

if (self) {

UIButton *editBtn = [UIButton buttonWithType:UIButtonTypeCustom];

[editBtn setImage:[UIImage imageNamed:@”edit.png”] forState:UIControlStateNormal];

[editBtn setFrame:CGRectMake(3, 5, 30, 30)];

[editBtn addTarget:self action:@selector(editButtonPressed) forControlEvents:UIControlEventTouchUpInside];

editButton = [[UIBarButtonItem alloc] initWithCustomView:editBtn];

UIButton *doneBtn = [UIButton buttonWithType:UIButtonTypeCustom];

[doneBtn setImage:[UIImage imageNamed:@”done.png”] forState:UIControlStateNormal];

[doneBtn setFrame:CGRectMake(3, 5, 30, 30)];

[doneBtn addTarget:self action:@selector(doneButtonPressed) forControlEvents:UIControlEventTouchUpInside];

doneButton = [[UIBarButtonItem alloc] initWithCustomView:doneBtn];

[self.navigationItem setRightBarButtonItem:self.leftBarButtonItem animated:YES];

}

return self;

}

- (UIBarButtonItem *)leftBarButtonItem
{
    if (self.tableView.editing)
        return self.doneButton;

    return self.editButton;
}

– (void)editButtonPressed

{

self.StoreTblView.editing = TRUE;

[self.navigationItem setRightBarButtonItem:self.leftBarButtonItem animated:YES];

}

– (void)doneButtonPressed

{

self.StoreTblView.editing = FALSE;

[self.navigationItem setRightBarButtonItem:self.leftBarButtonItem animated:YES];

}

How to get country names and codes ?

NSArray *countryCodes = [NSLocale ISOCountryCodes];

    NSMutableArray *countries = [NSMutableArray arrayWithCapacity:[countryCodes count]];

    

    for (NSString *countryCode in [NSLocale ISOCountryCodes])

    {

        NSString *identifier = [NSLocale localeIdentifierFromComponents: [NSDictionary dictionaryWithObject: countryCode forKey: NSLocaleCountryCode]];

        NSString *country = [[NSLocale currentLocale] displayNameForKey: NSLocaleIdentifier value: identifier];

        [countries addObject: country];

    }

    

    NSDictionary *codeForCountryDictionary = [[NSDictionary alloc] initWithObjects:countryCodes forKeys:countries];

   

        NSLog(@”%@”,codeForCountryDictionary);

How to get contacts list ?

First of all import AddressBook framework to your project and then 

#import <AddressBook/AddressBook.h>

– (IBAction)getContacts:(id)sender

{

    CFErrorRef *error = NULL;

    ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);

    CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);

    CFIndex numberOfPeople = ABAddressBookGetPersonCount(addressBook);

    

    for(int i = 0; i < numberOfPeople; i++) {

        

        ABRecordRef person = CFArrayGetValueAtIndex( allPeople, i );

        

        NSString *firstName = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonFirstNameProperty));

        NSString *lastName = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonLastNameProperty));

        NSLog(@”Name:%@ %@”, firstName, lastName);

        

        ABMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty);

        

        for (CFIndex i = 0; i < ABMultiValueGetCount(phoneNumbers); i++) {

            NSString *phoneNumber = (__bridge_transfer NSString *) ABMultiValueCopyValueAtIndex(phoneNumbers, i);

            NSLog(@”phone:%@”, phoneNumber);

        }

        NSLog(@”=============================================”);   

    }

}