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

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(@”=============================================”);   

    }

}

Can I Indent the Text in a UITextField ?

You have to subclass and override textRectForBounds: and editingRectForBounds:.

Here is a UITextfield subclass with custom background and vertical and horizontal padding:

@interface MyUITextField : UITextField 
@property (nonatomic, assign) float verticalPadding;
@property (nonatomic, assign) float horizontalPadding;
@end

#import "MyUITextField.h"
@implementation MyUITextField
@synthesize horizontalPadding, verticalPadding;
- (CGRect)textRectForBounds:(CGRect)bounds {
    return CGRectMake(bounds.origin.x + horizontalPadding, bounds.origin.y 
+ verticalPadding, bounds.size.width - horizontalPadding*2, 
bounds.size.height - verticalPadding*2);
}
- (CGRect)editingRectForBounds:(CGRect)bounds {
    return [self textRectForBounds:bounds];
}
@end

Usage:

UIImage *bg = [UIImage imageNamed:@"textfield.png"];
CGRect rect = CGRectMake(0, 0, bg.size.width, bg.size.height);
MyUITextField *textfield = [[[MyUITextField alloc] initWithFrame:rect] 
autorelease];
textfield.verticalPadding = 10; 
textfield.horizontalPadding = 10;
[textfield setBackground:bg];
[textfield setBorderStyle:UITextBorderStyleNone];
[self.view addSubview:textfield];

How to add own custom clear button in UITextField ?

 UIButton *clearButton = [UIButton buttonWithType:UIButtonTypeCustom];
        [clearButton setImage:[UIImage imageNamed:@”clearBtn.png”] forState:UIControlStateNormal];
        [clearButton setFrame:CGRectMake(0,0, 45, 45)];
        [clearButton addTarget:self action:@selector(clearTextField:) forControlEvents:UIControlEventTouchUpInside];
        
        textField.rightViewMode = UITextFieldViewModeAlways; //can be changed to UITextFieldViewModeNever,    UITextFieldViewModeWhileEditing,   UITextFieldViewModeUnlessEditing
        [textField setRightView:clearButton];

How to read and write file ?

//To Write the File.

    

    NSString *obj1=[NSString stringWithFormat:@”APPLE”];

    

    NSString *obj2=[NSString stringWithFormat:@”GOOGLE”];

    

    NSString *obj3=[NSString stringWithFormat:@”HP”];

    

    NSArray *array=[NSArray arrayWithObjects :obj1, obj2, obj3, nil];

    

    [self writeFile:@”arrayTest.txt” dataArray:array];

    

    //Read the File

    

    NSString *result=[self readFile:@”arrayTest.txt”];

    

    NSArray *outputArray=[result componentsSeparatedByString:@”\n”];

    

    for (int i=0; i<[outputArray count]; i++)

        

    {

        

      //  NSLog(@”the output=%@ index=%i”,[outputArray objectAtIndex:i], i);

        }

 

 

-(void)writeFile:(NSString *)fileName data:(id)data

{

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

    NSString *documentsDirectory = [paths objectAtIndex:0];

    NSString *appFile = [documentsDirectory stringByAppendingPathComponent:fileName];

    

    NSError *error=NULL;

    [data writeToFile:appFile atomically:YES encoding:NSUTF8StringEncoding error:&error];

 

    if (error == NULL)

    {

        //Check Error Here. if any.

    }

}

 

-(NSString *)readFile:(NSString *)fileName

{

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

    NSString *documentsDirectory = [paths objectAtIndex:0];

    NSString *appFile = [documentsDirectory stringByAppendingPathComponent:fileName];

    NSFileManager *fileManager=[NSFileManager defaultManager];

    

    if ([fileManager fileExistsAtPath:appFile])

    {

        NSError *error= NULL;

        id resultData = [NSString stringWithContentsOfFile:appFile encoding:NSUTF8StringEncoding error:&error];

        if (error == NULL)

        {

            return resultData;

        }

    }

    return NULL;

 }

 

-(void)writeFile:(NSString *)fileName dataArray:(NSArray *)data

{

    NSMutableString *dataString=[NSMutableString stringWithString:@””];

    

    for (int i=0; i<[data count]; i++)

    {

        if (i == [data count]-1)

        {

            [(NSMutableString *)dataString appendFormat:@”%@”,[data objectAtIndex:i]];

        }

        else

        {

            [(NSMutableString *)dataString appendFormat:@”%@\n”,[data objectAtIndex:i]];

        }

    }

    [self writeFile:fileName data:dataString];

}

NSPredicate with KVO-KVC

Collection Operators

  • @sum
  • @avg
  • @count
  • @max
  • @min

Object Operators

  • @distinctUnionOfObjects
  • @unionOfObjects

Array and Set Operators

  • @distinctUnionOfArrays
  • @unionOfArrays
  • @distinctUnionOfSets

NSMutableArray *ary = @[@{@”name”:@”dipak”,

                              @”state”:@”gujarat”,

                              @”city”:@”ahmedabad”,

                              @”ph”:@(9428736118),

                              @”id”:@”DPK”,

                              @”age”:@(25),

                              },

                            @{@”name”:@”swimal”,

                              @”state”:@”orissa”,

                              @”city”:@”asam”,

                              @”ph”:@(8460191763),

                              @”id”:@”SML”,

                              @”age”:@(23),

                                  },

                            @{@”name”:@”karan”,

                              @”state”:@”karnataka”,

                              @”city”:@”chennai”,

                              @”ph”:@(9724340340),

                              @”id”:@”NTR”,

                              @”age”:@(22),

                              },

                            @{@”name”:@”dipak”,

                              @”state”:@”gujarat”,

                              @”city”:@”ahmedabad”,

                              @”ph”:@(9428736118),

                              @”id”:@”DPK”,

                              @”age”:@(25),

                              },

                            @{@”name”:@”swimal”,

                              @”state”:@”orissa”,

                              @”city”:@”asam”,

                              @”ph”:@(8460191763),

                              @”id”:@”SML”,

                              @”age”:@(23),

                              },

                            @{@”name”:@”karan”,

                              @”state”:@”karnataka”,

                              @”city”:@”chennai”,

                              @”ph”:@(9724340340),

                              @”id”:@”NTR”,

                              @”age”:@(22),

                              }];

   

    NSArray *filteredItems = [ary filteredArrayUsingPredicate:                                                      [NSPredicate predicateWithFormat:@”city == %@”, @”chennai”]];

    NSLog(@”filteredItems == %@”,filteredItems);

    

    NSArray *filteredItems1 = [ary valueForKeyPath:@”name”];

    NSLog(@”filteredItems1 == %@”,filteredItems1);

    

    NSArray *filteredItems2 = [ary sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@”name” ascending:YES]]];

    NSLog(@”filteredItems2 == %@”,filteredItems2);

    

    NSNumber *total = [ary valueForKeyPath:@”@sum.age”];

    NSLog(@”total == %@”,total);

    

    NSArray *distinct = [ary valueForKeyPath:@”@distinctUnionOfObjects.name”];

    NSLog(@”distinct == %@”,distinct);

    

    NSArray *unions = [ary valueForKeyPath:@”@unionOfObjects.name”];

    NSLog(@”unions == %@”,unions);