https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Introduction/Introduction.html

String casting

1
2
int num = 1;
NSString *str = [NSString stringWithFormat:@"This is string type: %d", num];

will output

1
This is string type: 1
Reference:

Dump object in console

1
NSLog(@"%@", obj);
Reference:

Type casting

Cast bar to NSWhatEver object into foo variable

1
NSWhatEver *foo = (NSWhatEver *)bar;
Reference:

Accessing a deep element in JSON

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*
{
lvl_1_0 = {
lvl_2_0 = {
lvl_3_0 = "I'm Foo";
lvl_3_1 = "I'm Bar";
};
lvl_2_1 = 123;
};
lvl_1_1 = (
);
}
*/

NSString *foo = [[[json valueForKey:@"lvl_1_0"] valueForKey:@"lvl_2_0" ] valueForKey:@"lvl_3_0"];

Clear all cookies

1
2
3
4
5
NSString baseUrlString = @"http://yourdomain.com/";
NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL: [NSURL URLWithString:baseUrlString]];
for (NSHTTPCookie *cookie in cookies) {
[[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:cookie];
}
Reference:

Clear all NSUserDefaults

1
2
3
4
5
6
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDictionary *dict = [defaults dictionaryRepresentation];
for (id key in dict) {
[defaults removeObjectForKey:key];
}
[defaults synchronize];
Reference:

Define global constant

Create 2 files:

1
2
$ touch Constants.h
$ touch Constants.m

Add the 2 files to project, right-click the project -> Add Files to “project”…
alt text

Edit the files:

Constants.h

1
2
FOUNDATION_EXPORT NSString *const FOO;
FOUNDATION_EXPORT NSString *const BAR;

Constants.m

1
2
NSString *const FOO = @"I'm Foo";
NSString *const BAR = @"I'm Bar";

Then import to those files that you want to use these constants

1
import "Constants.h"
Reference:

Add objects into NSMutableArray

1
2
3
4
NSMutableArray *arrayObj = [[NSMutableArray alloc] init];
for (int i = 0; i < 10; i++) {
[arrayObj addObject:[NSString stringWithFormat:@"Row %d", i]];
}
Reference:

Add objects into NSMutableDictionary

1
2
3
4
NSMutableDictionary *arrayObj = [[NSMutableDictionary alloc] init];
for (int i = 0; i < 10; i++) {
[arrayObj setObject:[NSString stringWithFormat:@"Row %d", i] forKey:[NSString stringWithFormat:@"key_%d", i]];
}
Reference:

set border to image

1
2
3
4
5
#import <QuartzCore/QuartzCore.h>

UIImageView *imageView = [[UIImageView alloc] init];
[imageView.layer setBorderColor:[[UIColor blackColor] CGColor]];
[imageView.layer setBorderWidth:2.0];
Reference:

NSDate & Unix timestamp

NSDate to timestamp

1
int timestamp = [[NSDate date] timeIntervalSince1970];

timestamp to NSDate

1
2
int timestamp = 1234567890;
NSDate *theDate = [NSDate dateWithTimeIntervalSince1970:timestamp];
References:

Hide the navigation bar

Consider a situation here, a 2nd layer view is pushed on top of the root view, where root view need a navigation bar and the view just pushed no need.

In root navigation viewController.m

1
2
3
4
5
6
7
8
9
10
11
12
13
- (void)viewWillAppear:(BOOL)animated
{
# show navigation bar when the root view is shown
[self.navigationController setNavigationBarHidden:NO];
}
- (IBAction)toNextView:(id)sender
{
# push a new view in
YourViewController *controller = [[YourViewController alloc] init];
[self.navigationController pushViewController:controller animated:YES];
# hide the navigation bar
[self.navigationController setNavigationBarHidden:YES];
}
Reference:

Property creation

FooViewController.h

1
2
3
4
5
6
7
@interface FooViewController : UIViewController

@property (strong, nonatomic) NSString *fooStr;
# primitive type no need to specify strong or weak
@property (nonatomic) int fooInt;

@end

FooViewController.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@implementation FooViewController { }

@synthesize fooStr;
@synthesize fooInt;

...
- (void)viewDidUnload
{
// Deallocate object reference type
[self setFooStr:nil];
[super viewDidUnload];
}
@end
...

This can be apply in such a situation where you want to let the next view to access your property


Dismiss presentModalViewController

i.e. Cancel button is clicked, want to dismiss itself

1
[self dismissModalViewControllerAnimated:YES];
Reference:

UILabel setFont

1
[fooLabel setFont:[UIFont fontWithName:@"Arial-BoldMT" size:16]];
Reference:

UILabel center text alignment

1
fooLabel.textAlignment = UITextAlignmentCenter;
Reference:

Get device model

1
2
3
4
5
6
7
8
9
#import <sys/utsname.h>
...
- (NSString *)model
{
struct utsname systemInfo;
uname(&systemInfo);

return [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
}
Reference:

Get user location

First, add a framework named CoreLocation.framework

alt text

In FooViewController.h

1
2
3
4
5
6
7
8
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>

@interface FooViewController : UIViewController <CLLocationManagerDelegate> {
CLLocationManager *locationManager;
}

@end

In FooViewController.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
...
- (void)viewDidLoad
{
...
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
...
}

...
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(@"Old location: %f %f", oldLocation.coordinate.latitude, oldLocation.coordinate.longitude);
NSLog(@"New location: %f %f", newLocation.coordinate.latitude, newLocation.coordinate.longitude);
}
...
Reference:

Add beep sound

1
2
3
4
5
6
7
8
9
#import <AudioToolBox/AudioToolBox.h>

...
- (void)viewDidLoad
{
# more sound refer to http://iphonedevwiki.net/index.php/AudioServices
AudioServicePlaySystemSound(1000);
}
...
Reference:

Bind Return button to UITextField

In FooViewController.h

1
@interface FooViewController : UIViewController <UITextFieldDelegate>

In FooViewController.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- (void)viewDidLoad
{
...
UITextField *textField = [[UITextField alloc] initWithFrame:...];
...
textField.delegate = self;
...
}

#pragma mark - UITextFieldDelegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
// Un-focus the text field
[textField resignFirstResponder];
return YES;
}
Reference:

Change keyboard Return key to Go

1
[textField setReturnKeyType:UIReturnKeyGo];
Reference:

Delegate multiple UITextField

In FooViewController.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#import "FooViewController.h"

#define TEXTFIELD_FOO 1
#define TEXTFIELD_BAR 2

@interface FooViewController()

@end

@implementation FooViewController
...
- (void)viewDidLoad
{
...
UITextField *fooTextField = [[UITextField alloc] initWithFrame:...];
...
fooTextField.tag = TEXTFIELD_FOO;
fooTextField.delegate = self;
...
UITextField *barTextField = [[UITextField alloc] initWithFrame:...];
...
barTextField.tag = TEXTFIELD_BAR;
barTextField.delegate = self;
...
}
...
#pragma mark - UITextFieldDelegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
if (textField.tag == TEXTFIELD_FOO) {
// do something with Foo
} else if (textField.tag == TEXTFIELD_BAR) {
// do something with Bar
}
return YES;
}
Reference:

UIScrollView scroll as page

The statement below will enable the paging like what you see in iPhone menu (cannot scroll half page)

1
scrollView.pagingEnabled = YES;

Change the height of UITableViewCell

1
2
3
4
- (CGFloat)tableView:(UITableView *)theTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 100.00;
}
Reference:

Set UITableViewCell background image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = @"Cell";

UITableViewCell *cell = [theTableView dequeueReusableCellWithIdentifier:cellIdentifier];

if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
}

cell.backgroundView = [[UIView alloc] init];
cell.contentView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"imgName"]];

return cell;
}

Set background on UIButton

I was curious that why the background is always there

alt text

Finally I found the problem, is the Type, to create a button with background programmatically

1
2
3
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; // use custom instead of RoundedRect
[button setFrame:CGRectMake(position_x, position_y, width, height)];
[button setBackgroundImage:[UIImage imageNamed:@"SignInRegisterButton"] forState:UIControlStateNormal];

Remove UITableView cell separator

1
tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
Reference:

Reset UIBarButtonItem background to default

AppDelegate.m

1
[[UIBarButtonItem appearance] setBackgroundImage:nil forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];

Get Day, Month, Year from NSDate

1
2
3
4
NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:NSDayCalendarUnit|NSMonthCalendarUnit|NSYearCalendarUnit fromDate:[NSDate date]];
NSNumber *day = [NSNumber numberWithInt:[dateComponents day]];
NSNumber *month = [NSNumber numberWithInt:[dateComponents month]];
NSNumber *year = [NSNumber numberWithInt:[dateComponents year]];
Reference:

Create UITableView programmatically

In YourViewController.h

1
2
3
4
5
#import <UIKit/UIKit.h>

@interface YourViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>

@end

Tell the compiler to conform to UITableViewDelegate & UITableViewDataSource these 2 protocols

In YourViewController.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#import "YourViewController.h"

@interface YourViewController ()

@end

@implementation YourViewController {
UITableView *tableView;
}
...

- (void)viewDidLoad
{
tableView = [[UITableView alloc] initWithFrame:CGRectMake(self.view.frame.size.width * 0.55f, self.view.frame.size.height * 0.2f, self.view.frame.size.width * 0.4f, self.view.frame.size.height * 0.7f) style:UITableViewStylePlain];

// set the delegate & dataSource to self, means have to implement in YourViewController
tableView.delegate = self;
tableView.dataSource = self;

[self.view addSubview:tableView];
}

...
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)theTableView
{
// the number of section(s) in the table
return 1;
}

- (NSInteger)tableView:(UITableView *)theTableView numberOfRowsInSection:(NSInteger)section
{
// the number of row(s) in the table
return 1;
}

- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = @"Cell";

UITableViewCell *cell = [theTableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
// do some configuration like populate data to cell

return cell;
}

#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)theTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Action that you want to perform when clicked on table cell
}

Validate phone number via Regex

1
2
3
4
NSString *phoneNo = @"+6012-3456789";
NSString *regex = @"^(\\+)?\\d+(-)?\\d+";
NSPredicate *stringTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
BOOL isValid = [stringTest evaluateWithObject:phoneNo];
  • ^ Indicate beginning of the text
  • (\\+)? Is an optional + character at the beginning of the text
  • \\d+ Indicate one or more integer
  • (-)? An optional character

This will matches:

  • +6012-3456789
  • 012-3456789
  • +60123456789
  • 6012-3456789
  • 60123456789

Validate required text field

Should use

1
2
3
if (textField.text.length == 0) {
// handle error
}

rather than

1
2
3
if ([textField.text isEqualToString:@""]) {
// handle error
}

The second 1 won’t work as it’s default value is not an empty string, unless that you set

1
2
3
4
5
- (void)viewDidLoad
{
[super viewDidLoad];
textField.text = @"";
}

it’s initial value.

Reference:

Disable sleep

In your AppDelegate.m

1
2
3
4
5
6
...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[UIApplication sharedApplication].idleTimerDisabled = YES;
}
...
Reference:

Adding criteria to CoreData

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];

NSEntityDescription *entity = [NSEntityDescription entityForName:@"TableName" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];

NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"id" ascending:YES];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];

/* Add criteria here */
// for integer
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"theId == %d", 123]];
// for string
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"columnName CONTAINS[cd] %@", @"foo"]];

NSError *error;
NSArray *resultSet = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (resultSet == nil) {
FATAL_CORE_DATA_ERROR(error);
}

NSLog(@"Result: %@", resultSet);
Reference:

Sentence to CamelCase

1
2
3
4
- (NSString *)camelCaseFromString:(NSString *)str
{
return [[str capitalizedString] stringByReplacingOccurrencesOfString:@" " withString:@""];
}
Reference:

Add touch event to UIImageView

1
2
3
4
5
6
7
8
9
10
11
12
13
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(imageTouched:)];

UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
[imageView addGestureRecognizer:tap];
imageView.userInteractionEnabled = YES;
[self.view addSubview:imageView];

...

- (void)imageTouched:(UITapGestureRecognizer *)sender
{
NSLog(@"Image tapped");
}

NOTE: imageView.userInteractionEnabled = YES must be set, otherwise it won’t work


NSArray check is object in array

1
2
NSArray *foo = [NSArray arrayWithObjects:obj1, obj2, obj3, nil];
BOOL isObj1InArray = [foo containsObject:obj1];
Reference:

Set timeout interval

Set the interval to 60 seconds.

1
2
3
// must be NSMutableURLRequest, NSURLRequest doesn't has setTimeoutInterval this method
NSMutableURLRequest *request = [client requestWithMethod:@"GET" path:@"/foo" parameters:nil];
[request setTimeoutInterval:60];
Reference:

Compare CGRect

1
2
3
if (CGRectEqualToRect(someView.frame, anotherView.frame)) {
NSLog(@"They are equal");
}
Reference:

In your FooViewController.h, make sure it conform to WebView’s protocol

1
2
3
4
5
#import <UIKit/UIKit.h>

@interface FooViewController : UIViewController <UIWebViewDelegate>

@end

In FooViewController.m, implement the delegate method

1
2
3
4
5
6
7
8
9
10
#pragma mark - UIWebViewDelegate
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
// if a hyperlink is onclick, open browser
if (navigationType == UIWebViewNavigationTypeLinkClicked) {
[[UIApplication sharedApplication] openURL:request.URL];
return NO;
}
return YES;
}
Reference:

Access property variable in closure

When you see a warning Capturing ‘self’ strongly in this block is likely to lead to a retain cycle, you can’t access via self inside the block.

1
2
3
4
5
[self.coverImageView setImageWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[json valueForKeyPath:@"response.cover"]]] placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {

self.coverImageView.image = image; // warning will be appeared here
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
}];

The solution is

1
2
3
4
5
6
__weak typeof(self) weakSelf = self;
[self.coverImageView setImageWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[json valueForKeyPath:@"response.cover"]]] placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {

weakSelf.coverImageView.image = image;
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
}];
Reference:

Add a Done button to UISearchBar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// add Done button to keyboard
// dummy bar button just to make the Done button to right-hand-side
UIBarButtonItem *dummyBarButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UIBarButtonItem *doneBarButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(hideKeyboard:)];
[doneBarButton setStyle:UIBarButtonItemStyleDone];
UIToolbar *keyboardToolbar = [[UIToolbar alloc] init];
[keyboardToolbar setBarStyle:UIBarStyleBlackTranslucent];
[keyboardToolbar sizeToFit];
[keyboardToolbar setItems:[NSArray arrayWithObjects:dummyBarButton, doneBarButton, nil]];

self.searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
self.searchBar.delegate = self;
self.searchBar.placeholder = @"Search...";
// Access it subview (UITextField) and set the toolbar to it
// Since self.searchBar.inputAccessoryView = keyboardToolbar; will thrown error
for (UIView *subView in self.searchBar.subviews) {
if ([subView conformsToProtocol:@protocol(UITextInputTraits)]) {
UITextField *searchBarField = (UITextField *)subView;
searchBarField.inputAccessoryView = keyboardToolbar;
break;
}
}
[self.view addSubview:self.searchBar];
Reference:

Change UISearchBar Search button to Done

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

self.searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
self.searchBar.delegate = self;
self.searchBar.placeholder = @"Search...";
// Loop through all subviews in UISearchBar
for (UIView *searchBarSubview in [self.searchBar subviews]) {
// Check if it is UITextField
if ([searchBarSubview conformsToProtocol:@protocol(UITextInputTraits)]) {
@try {
// Change the title "Search" to "Done"
[(UITextField *)searchBarSubview setReturnKeyType:UIReturnKeyDone];
// set the style of keyboard
[(UITextField *)searchBarSubview setKeyboardAppearance:UIKeyboardAppearanceAlert];
// Enable the "Done" button eventhough no text in search bar
[(UITextField *)searchBarSubview setEnablesReturnKeyAutomatically:NO];
}
@catch (NSException * e) {
// ignore exception
}
}
}
[self.view addSubview:self.searchBar];
Reference:

Remove all subviews from UIScrollView

1
[self.scrollView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
Reference:

Calculate visible “radius” from MKMapView

1
2
3
4
5
6
7
8
9
10
11
12
13
// get the center coordinate
CLLocationCoordinate2D centerCoor = [self.mapView centerCoordinate];
// get top left coordinate
CLLocationCoordinate2D topLeftCoor = [self.mapView convertPoint:CGPointMake(0, 0) toCoordinateFromView:self.mapView];

// init locations based on coordinates
CLLocation *centerLocation = [[CLLocation alloc] initWithLatitude:centerCoor.latitude longitude:centerCoor.longitude];
CLLocation *topLeftLocation = [[CLLocation alloc] initWithLatitude:topLeftCoor.latitude longitude:topLeftCoor.longitude];

// get the distance between 2 locations
CLLocationDistance radius = [centerLocation distanceFromLocation:topLeftLocation];

NSLog(@"Distance %.9f meters", radius);
Reference:

Draw a circle image

This is basically just to draw a UIImage (circle) from code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- (UIImage *)drawCircleWithColor:(UIColor *)color andSize:(CGSize)size
{
CGRect rect = CGRectMake(0, 0, size.width, size.height);
UIGraphicsBeginImageContext(rect.size);

CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 4.0);
CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextSetFillColorWithColor(context, color.CGColor);

CGContextBeginPath(context);
CGContextAddEllipseInRect(context, rect);
CGContextDrawPath(context, kCGPathFillStroke); // Or kCGPathFill

UIImage *circle = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

return circle;
}
References:

Create rectangle UIImage programmatically

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- (UIImage *)imageWithColor:(UIColor *)color inSize:(CGSize)size withCornerRadius:(CGFloat)radius
{
CGRect rect = CGRectMake(0, 0, size.width, size.height);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, color.CGColor);
CGContextFillRect(context, rect);
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

if (radius > 0) {
UIGraphicsBeginImageContext(size);

// Add a clip before drawing anything, in the shape of an rounded rect
[[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radius] addClip];
// Draw your image
[img drawInRect:rect];
img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}

return img;
}
References:

Update text on a specific UITableViewCell

For example update, the fifth row in section 0

1
2
3
NSIndexPath *fifthRow = [NSIndexPath indexPathForRow:4 inSection:0];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:fifthRow];
cell.textLabel.text = @"the updated text";
Reference:

Remove last 2 character in NSMutableString

1
2
NSMutableString *str = [NSMutableString stringWithString:@"Item 1, Item 2, "];
[str deleteCharactersInRange:NSMakeRange([str length] - 2, 2)];

Result will be Item 1, Item 2

Reference: Removing the last character from an NSMutableString

Get all checked UITableViewCell

1
2
3
4
5
6
7
// options is the dataSource for the tableView
for (int i = 0; i < [options count]; i++) {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
// perform action here
}
}
Reference:

UIView get index of subview

Some time you might have some views is overlapping, when tapping a button, the 2 views will interchange, so you need to get the view’s index to do comparison.

1
2
3
4
5
6
7
8
9
10
11
12
UIView *superView = [[UIView alloc] init];

UITableView *listView = [[UITableView alloc] initWithFrame:superView.bounds];
[superView addSubview:listView];

UITableView *gridView = [[UITableView alloc] initWithFrame:superView.bounds];
[superView addSubview:gridView];

int listViewIndex = [superView.subviews indexOfObject:listView];
int gridViewIndex = [superView.subviews indexOfObject:gridView];

// action here
Reference:

UINavigationBar change back bar button text

Let say there are 2 viewControllers, FirstViewController and SecondViewController

In FirstViewController.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
...
- (void)viewDidLoad
{
// This must be put in FirstViewController rather than SecondViewController
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Your title"
style:UIBarButtonItemStyleBordered
target:nil
action:nil];
}
- (void)navigateToSecondView
{
SecondViewController *controller = [[SecondViewController alloc] init];
[self.navigationController pushViewController:controller animated:YES];
}
...

When you navigate to SecondViewController, you will see Your title text appear in back button.

Reference:

tableView:viewForFooterInSection VS tableView.tableFooterView

If you want the footer to keep at the end of table view (it will scroll together with table cell), then use tableView.tableFooterView

1
2
3
4
UIView *footerView = [[UIView alloc] initWithFrame:...];
[footerView addSubview:someView];

tableView.tableFooterView = footerView;

If you’re using tableView:viewForFooterInSection, then the view will stay at bottom of your visible screen for that particular section.

1
2
3
4
5
6
7
8
9

- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
UIView *footerView = [[UIView alloc] initWithFrame:...];
...
[footerView addSubview:someView];

return footerView;
}
Reference:

RSA - Convert .pem to .der format

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
NSString *startPublicKey = @"-----BEGIN PUBLIC KEY-----";
NSString *endPublicKey = @"-----END PUBLIC KEY-----";

// read .pem from file
NSString* path = [[NSBundle mainBundle] pathForResource:@"public_key"
ofType:@"pem"];
// get the content
NSString* content = [NSString stringWithContentsOfFile:path
encoding:NSUTF8StringEncoding
error:NULL];
// remove the first line & end line
NSString *publicKey;
NSScanner *scanner = [NSScanner scannerWithString:content];
[scanner scanUpToString:startPublicKey intoString:nil];
[scanner scanString:startPublicKey intoString:nil];
[scanner scanUpToString:endPublicKey intoString:&publicKey];

// now this is in .der format
NSData *data = [NSData base64DataFromString:publicKey];
References:

Storing Custom object to NSUserDefaults

Let say you have an object Foo

Foo.h

1
2
3
4
5
6
7
8
9
#import <Foundation/Foundation.h>

// conform to NSCoding
@interface Foo : NSObject <NSCoding>

@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *desc;

@end

Foo.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#import "Foo.h"

@implementation Foo

@synthesize name = _name;
@synthesize desc = _desc;

// implement this 2 methods
- (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:self.name forKey:@"Name"];
[aCoder encodeObject:self.desc forKey:@"Desc"];
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
self.name = [aDecoder decodeObjectForKey:@"Name"];
self.desc = [aDecoder decodeObjectForKey:@"Desc"];

return self;
}

Now you can save your objects to NSUserDefaults

1
2
3
4
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *arr = ... ; // set value
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:arr];
[defaults setObject:data forKey:@"theKeyInUserDefaults"];

and load it from NSUserDefaults

1
2
3
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [defaults objectForKey:@"theKeyInUserDefaults"];
NSArray *arr = [NSKeyedUnarchiver unarchiveObjectWithData:data];
Reference:

Compare NSObject

Override the hash & isEqual methods

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
- (NSUInteger)hash
{
NSUInteger prime = 31;
NSUInteger result = 1;

// for object
result = prime * result + [self.name hash];

// for primitive type
result = prime * result + self.amount;

// for 64bit
result = prime * result + (int) (self.data64bit ^ (self.data64bit >>> 32));

// for boolean
result = prime * result + (self.isCorrect) ? 1231 : 1237;

return result;
}

- (BOOL)isEqual:(id)object
{
if (![object isKindOfClass:[self class]]) {
return NO;
}
return [self hash] == [object hash];
}
Reference:

Change textLabel color of UITableViewCell in selected state

1
cell.textLabel.highlightedTextColor = [UIColor whiteColor];
Reference:

Rate Us: Open in AppStore

1
2
3
NSURL *rateUrl = [NSURL URLWithString:[NSString stringWithFormat:@"itms-apps://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?id=%@&onlyLatestVersion=true&pageNumber=0&sortOrdering=1&type=Purple+Software", @"YOUR_APP_ID_HERE"]];

[[UIApplication sharedApplication] openURL:rateUrl];
Reference:

Add shadow to view without gradient

alt text

To add a shadow to UINavigationBar like image above

1
2
3
4
5
6
// set shadow below
self.navigationController.navigationBar.layer.shadowRadius = 0;
self.navigationController.navigationBar.layer.shadowOffset = CGSizeMake(0, 4);
self.navigationController.navigationBar.layer.shadowOpacity = 1;
self.navigationController.navigationBar.layer.shadowColor = [UIColor colorWithWhite:0.8 alpha:0.8f].CGColor;
self.navigationController.navigationBar.layer.shadowPath = [UIBezierPath bezierPathWithRoundedRect:self.navigationController.navigationBar.bounds cornerRadius:self.navigationController.navigationBar.layer.cornerRadius].CGPath;
Reference:

Resign any first responder

Some time we just want to hide the keyboard when clicked on a button, but we might not know which textField is currently showing keyboard. The line below will just resign any responder.

1
[self.view endEditing:YES];
Reference:

Loop through NSDictionary

1
2
3
4
5
NSDictionary *dict = ...;
for (NSString *key in dict) {
id value = [dict objectForKey:key];
// do stuff
}
Reference:

UINavigationBar in iOS7 overlap the main content view issue

alt text
alt text

In order to fix this, just add the line below

1
navigationController.navigationBar.translucent = NO;
Reference:

Draw UIImage from text

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
- (UIImage *)imageFromText:(NSString *)text
{
// set the font type and size
UIFont *font = [UIFont fontWithName:@"Helvetica" size:12];
CGSize size = [text sizeWithFont:font];

// check if UIGraphicsBeginImageContextWithOptions is available (iOS is 4.0+)
if (UIGraphicsBeginImageContextWithOptions != NULL)
UIGraphicsBeginImageContextWithOptions(size,NO,0.0);
else
// iOS is < 4.0
UIGraphicsBeginImageContext(size);

// optional: add a shadow, to avoid clipping the shadow you should make the context size bigger
//
// CGContextRef ctx = UIGraphicsGetCurrentContext();
// CGContextSetShadowWithColor(ctx, CGSizeMake(1.0, 1.0), 5.0, [[UIColor grayColor] CGColor]);

// set text color
[[UIColor colorWithWhite:1 alpha:0.55] set];

// draw in context, you can use also drawInRect:withFont:
[text drawAtPoint:CGPointMake(0.0, 0.0) withFont:font];

// transfer image
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

return image;
}
Reference:

Change UINavigationBar style

In AppDelegate.m

1
2
3
4
5
6
7
8
9
10
11
12
13
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...

// change the font & text color
[[UINavigationBar appearance] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
[UIFont fontWithName:@"CustomFont-Bold" size:18], UITextAttributeFont,
[UIColor whiteColor], UITextAttributeTextColor,
// make the text FLAT
[UIColor clearColor], UITextAttributeTextShadowColor,
nil]];
...
}

This is same to UIBarButtonItem

Reference:

UINavigationBar bar button image color for iOS7

In iOS7, even you set an image which is white color, it will automatic become blue color. This can change it by tintColor.

1
2
3
if ([[UIDevice currentDevice].systemVersion floatValue] >= 7) {
[[UINavigationBar appearance] setTintColor:[UIColor whiteColor]];
}

Change status bar text color for iOS7

On ViewController

  1. Set the UIViewControllerBasedStatusBarAppearance to YES in the plist.
  2. Edit ViewController.m
1
2
3
4
5
6
7
8
9
10
11
12
- (void)viewDidLoad
{
[super viewDidLoad];

// ADD THIS LINE
[self setNeedsStatusBarAppearanceUpdate];
}

// ADD THIS METHOD
- (UIStatusBarStyle)preferredStatusBarStyle {
return UIStatusBarStyleLightContent;
}

OR Update the UINavigationBar color, then it will follow. Put the code below to application:didFinishLaunchingWithOptions:

1
2
3
4
// only for iOS7
if ([[UIDevice currentDevice].systemVersion floatValue] >= 7) {
[[UINavigationBar appearance] setBarTintColor:[UIColor yellowColor]];
}

On splash screen

Edit Info.plist

1
2
3
4
5
6
<dict>
...
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleLightContent</string>
...
</dict>
References:

UIView autoresizingMask to bottom left

If want to achive the result like this in programmatic way

alt text

1
2
// flexible right & flexible top
view.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin;
Reference:

Check location service enabled for this app

1
2
3
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) {
// location service is not allowed for this app
}
Reference:

A trigger of after view added to subview

A CustomView want to execute some logic once added to other view

ViewController.m

1
2
CustomView *view = [[CustomView alloc] init];
[self.view addSubview:view];

CustomView.m

1
2
3
4
- (void)didMoveToSuperview
{
NSLog(@"Just added to other view");
}
Reference:

Show static map (Google) on UIImageView

1
2
3
4
5
6
7
8
9
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(position_x, position_y, width, height)];

double latitude = 3.4005, longitude = 101.34888;
int zoomLevel = 11;

NSString *staticMapUrlString = [NSString stringWithFormat:@"http://maps.google.com/maps/api/staticmap?markers=color%%3Ared%%7C%f,%f&zoom=%d&size=%dx%d&sensor=true", latitude, longitude, zoomLevel, (int)imageView.bounds.size.width, (int)imageView.bounds.size.height];
NSURL *staticMapUrl = [NSURL URLWithString:staticMapUrlString];

imageView.image = [UIImage imageWithData: [NSData dataWithContentsOfURL:staticMapUrl]];

String encoding in URL

  • %%3A - is refer to colon (:), the double percent (%%) is to escape the string parameters
  • %%7C - is refer to the pipe line (|)
References:

Detect double tap event on UIImageView

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- (void)viewDidLoad
{
...
ImageView *imageView = [[UIImageView alloc] initWithFrame:frame];
imageView.image = image;
imageView.userInteractionEnabled = YES; // must enable

UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(imageTapped:)];
[tap setDelaysTouchesBegan:YES];
tap.numberOfTapsRequired = 2; // double tap
tap.numberOfTouchesRequired = 1;
[imageView addGestureRecognizer:tap];
}

- (void)imageTapped:(UITapGestureRecognizer *)sender
{
NSLog(@"Double tapped");
}
Reference:

Show character by give ASCII code (int) or vice versa

Integer to alphabet

1
2
int asciiCode = 97;
NSString *alphabet = [NSString stringWithFormat:@"%c", asciiCode]; // a

Alphabet to integer

1
2
NSString *alphabet = @"a";
int asciiCode = [alphabet characterAtIndex:0]; // 97
Reference:

Change UITabBarController tint color

Change the bar color

1
tabBarController.tabBar.barTintColor = [UIColor blackColor];

Change the icon & text color

1
tabBarController.tabBar.tintColor = [UIColor whiteColor];

Change the text color only

1
2
3
4
5
6
7
8
9
10
// change the selected text color
[[UITabBarItem appearance] setTitleTextAttributes:@{NSFontAttributeName: [UIFont fontWithName:@"Helvetica" size:10.0f],
NSForegroundColorAttributeName: [UIColor whiteColor]
} forState:UIControlStateSelected];


// change the unselected text color
[[UITabBarItem appearance] setTitleTextAttributes:@{NSFontAttributeName: [UIFont fontWithName:@"Helvetica" size:10.0f],
NSForegroundColorAttributeName: [UIColor whiteColor]
} forState:UIControlStateNormal];
Reference:

Fix the status bar some time not showing text on iOS7

Edit Project-Info.plist file, add the content below

1
2
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>

Or open in Property list

alt text


Extract submatch from string using regular expression

Example here shows extract date from NSDate object

The format we want is YYYY-MM-DD

1
2
3
NSLog(@"date %@", date);
// this will return (for example)
// 2014-01-27 10:17:00 +0000

So we can extract out the part using regex

1
2
3
4
5
6
7
8
9
10
11
12
13
NSDate *date = ...;

// extract 4 integers followed by a dash followed by 2 integers followed by a dash followed by 2 integers again
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"(\\d{4}-\\d{2}-\\d{2})"
options:NSRegularExpressionCaseInsensitive
error:&error];
[regex enumerateMatchesInString:date.description options:0 range:NSMakeRange(0, date.description.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
// just get the substring by the range
NSString *dateStr = [sender.date.description substringWithRange:[result rangeAtIndex:0]];
NSLog(@"Date only: %@", dateStr);
// this will show
// Date only: 2014-01-27
}];

Update

For this case, want to extract out the minutes & seconds

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
NSString *message = @"Your computer will be shutdown in 3 minutes 25 seconds";

// Only match for the minutes & seconds
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"(\\d+) minutes (\\d+) seconds"
options:NSRegularExpressionCaseInsensitive
error:&error];
[regex enumerateMatchesInString:date.description options:0 range:NSMakeRange(0, date.description.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {

// `rangeAtIndex` 0 will be "3 minutes 25 seconds, so we don't take
// `rangeAtIndex` 1 will be "3"
// `rangeAtIndex` 2 will be "25"
int minutes = [[message substringWithRange:[result rangeAtIndex:1]] intValue];
int seconds = [[message substringWithRange:[result rangeAtIndex:2]] intValue];
NSLog(@"%dm %ds", minutes, seconds); // 3m 25s
}];

It always matches the main match then only followed by submatch

Reference:

Resize UIImage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

+ (UIImage *)resizeImage:(UIImage *)image withSize:(CGSize)size retainAspectRatio:(BOOL)aspectRatio
{
CGSize newSize = size;
if (aspectRatio) {
// whether is based on width to calculate or height
BOOL baseOnWidth = size.width > size.height ? YES : NO;

if (baseOnWidth) {
newSize.height = (size.width / image.size.width) * image.size.height;
} else {
newSize.width = (size.height / image.size.height) * image.size.width;
}
}
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Reference:

UISegmentedControl deselect segment

1
[segmentedControl setSelectedSegmentIndex:UISegmentedControlNoSegment];
Reference:

UISegmentedControl change text & border color

Border color

1
segmentedControl.tintColor =[UIColor colorWithRed:50/255.0f green:150/255.0f blue:100/255.0f alpha:1];

Text color

1
[segmentedControl setTitleTextAttributes:@{UITextAttributeTextColor: [UIColor blueColor]} forState:UIControlStateSelected];

Add UISegmentedControl to UIToolbar

1
2
3
4
5
6
7
8
UISegmentedControl *nextPrevSegment = [[UISegmentedControl alloc] initWithItems:@[@"Previous", @"Next"]];
nextPrevSegment.segmentedControlStyle = UISegmentedControlStyleBar;
[nextPrevSegment addTarget:self action:@selector(nextPrevTouched:) forControlEvents:UIControlEventValueChanged];
UIBarButtonItem *segmentedControlButtonItem = [[UIBarButtonItem alloc] initWithCustomView:(UIView *)nextPrevSegment];
UIToolbar *keyboardToolbar = [[UIToolbar alloc] init];
[keyboardToolbar setTintColor:[UIColor whiteColor]];
[keyboardToolbar sizeToFit];
[keyboardToolbar setItems:[NSArray arrayWithObjects:segmentedControlButtonItem, [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil], nil]];

Use custom font in UIWebView

1
2
3
4
NSString *html = @"<p>This is a paragraph<\/p>";
NSString *htmlString =
[NSString stringWithFormat:@"<font face='GothamRounded-Bold' size='2'>%@", html];
[webView loadHTMLString:htmlString baseURL:nil];
Reference:

Set delay to perform action

1
2
3
4
5
6
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
//code to be executed on the main queue after delay
NSLog(@"Action here delayed 2 seconds.");
});
Reference:

Remove section border for iOS6

1
cell.backgroundView = [UIView new];
Reference:

UITableView grouped style change background color for iOS6

transparent background

1
tableView.backgroundView = [UIView new];

for color background

1
2
3
UIView* bview = [[UIView alloc] init];
bview.backgroundColor = [UIColor yellowColor];
[tableView setBackgroundView:bview];
Reference:

Make the UINavigationBar transparent

1
2
3
4
5
6
7
8
9
10
11
12
13
self.navigationController.navigationBar.shadowImage = [UIImage new];
// remove the inner shadow

// for iOS 7, remove the background image
if ([[UIDevice currentDevice].systemVersion floatValue] >= 7) {
[self.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
self.navigationController.navigationBar.shadowImage = [UIImage new];
self.navigationController.navigationBar.translucent = YES;
self.navigationController.view.backgroundColor = [UIColor clearColor];
} else { // for iOS 6, set the image filled with color that same as the view's background color
// see https://github.com/jslim89/js-learning-journey/tree/master/programming/objective-c#create-rectangle-uiimage-programmatically
[self.navigationController.navigationBar setBackgroundImage:[MyClass imageWithColor:[UIColor yellowColor] inSize:CGSizeMake(320, 44) withCornerRadius:0] forBarMetrics:UIBarMetricsDefault];
}
References:

Set 2 different colors in a view

This can be achieved by using CALayer

1
2
3
4
CALayer *sublayer = [CALayer layer];
sublayer.backgroundColor = [UIColor yellowColor].CGColor;
sublayer.frame = CGRectMake(0, 300, self.view.frame.size.width, 100);
[self.view.layer addSublayer:sublayer];

This will set the color of view to yellow color in (0, 300, 320, 100)


UITableView delegate after reloadData is called

1
2
3
4
5
6
-(void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.row == ((NSIndexPath*)[[tableView indexPathsForVisibleRows] lastObject]).row){
NSLog(@"Finished loaded");
}
}
Reference:

Bold certain text on UILabel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// normal font
NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys:
[UIFont fontWithName:@"Helvetica" size:20], NSFontAttributeName,
[UIColor whiteColor], NSForegroundColorAttributeName,
nil];
// bold font
NSDictionary *boldAttrs = [NSDictionary dictionaryWithObjectsAndKeys:
[UIFont fontWithName:@"Helvetica-Bold" size:20], NSFontAttributeName, nil];

NSString *text = @"The quick brown fox jumps over the lazy dog";

NSRange range = NSMakeRange(4, 15); // bold the text "quick brown fox"
// init with regular attributes
NSMutableAttributedString *textAttr = [[NSMutableAttributedString alloc] initWithString:text attributes:attrs];
[textAttr setAttributes:boldAttrs range:range]; // set specific attributes for range of text
[myLabel setAttributedText:textAttr];

NOTE: This is for iOS6 and above only

Reference:

Create class dynamically from string

1
2
NSString* className = @"MyClass";
[[NSClassFromString(className) alloc] init...];
Reference:

Check is nib exists

1
2
3
if([[NSBundle mainBundle] pathForResource:fileName ofType:@"nib"] != nil) {
// nib exists
}
Reference:

Default share on iOS 6 and above

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- (void)shareText:(NSString *)string andImage:(UIImage *)image
{
NSMutableArray *sharingItems = [NSMutableArray new];

if (string) {
[sharingItems addObject:string];
}
if (image) {
[sharingItems addObject:image];
}

UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:sharingItems applicationActivities:nil];
[self presentViewController:activityController animated:YES completion:nil];
}
Reference:

Sort CoreData children objects

In MyParent.h

1
2
3
4
5
...
@property (nonatomic, retain) NSSet *children;

// add this
- (NSArray *)sortedChildren;

In MyParent.m

1
2
3
4
5
6
...
- (NSArray *)sortedChildren
{
NSSortDescriptor *timestamp = [NSSortDescriptor sortDescriptorWithKey:@"timestamp" ascending:YES];
return [[self.conversations allObjects] sortedArrayUsingDescriptors:[NSArray arrayWithObject:timestamp]];
}

Then you can now invoked by [myparent sortedChildren]

Reference:

Long press event on table row

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- (void)viewDidLoad
{
...
// add to the tableView instead of tableViewCell
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(tableViewPressed:)];
[self.tableView addGestureRecognizer:longPress];
}

- (void)tableViewPressed:(UILongPressGestureRecognizer *)sender
{
if (sender.state == UIGestureRecognizerStateBegan) { // only take action in this state
CGPoint point = [sender locationInView:self.tableView]; // get the point (x, y)
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:point]; // look for correct indexPath
// in case you have section header
CGFloat headerHeight = [self tableView:self.tableView heightForHeaderInSection:indexPath.section];

// first row should be at the offset y which between (height of header view) and rowHeight + header for header view
if ((point.y < headerHeight || point.y > (self.tableView.rowHeight + headerHeight)) && indexPath.row == 0) return;

// do action here
}
}

Clear CoreData tables

AppDelegate.m

1
2
3
4
5
6
7
8
9
10
11
12
13
- (void)flushDatabase
{
[__managedObjectContext lock];
NSArray *stores = [__persistentStoreCoordinator persistentStores];
for(NSPersistentStore *store in stores) {
[__persistentStoreCoordinator removePersistentStore:store error:nil];
[[NSFileManager defaultManager] removeItemAtPath:store.URL.path error:nil];
}
[__managedObjectContext unlock];
__managedObjectModel = nil;
__managedObjectContext = nil;
__persistentStoreCoordinator = nil;
}
Reference:

Compare CGAffineTransform

1
2
3
if (CGAffineTransformEqualToTransform(transform, CGAffineTransformIdentity)) {
// is equal
}
Reference:

UILabel justify text to fit left & right

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
NSMutableParagraphStyle *paragraphStyles = [[NSMutableParagraphStyle alloc] init];
paragraphStyles.alignment = NSTextAlignmentJustified;
paragraphStyles.firstLineHeadIndent = 0.05; // Very IMP

NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys:
paragraphStyles, NSParagraphStyleAttributeName,
nil];

NSString *content = @"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
// Create the attributed string (text + attributes)
NSMutableAttributedString *textAttrs = [[NSMutableAttributedString alloc] initWithString:content attributes:attrs];

UILabel *justifiedLabel = [[UILabel alloc] initWithFrame:...];
justifiedLabel.numberOfLines = 0;
justifiedLabel.lineBreakMode = NSLineBreakByWordWrapping;
[justifiedLabel setAttributedText:textAttrs];
[justifiedLabel sizeToFit];
...
Reference:

application:didReceiveRemoteNotification: not called on app launching

During the first launch, this method will not be called, thus have to handle this manually

1
2
3
4
5
NSDictionary *remoteNotification = [launchOptions objectForKey: UIApplicationLaunchOptionsRemoteNotificationKey];
if (remoteNotification) {
// call the method manually
[self application:application didReceiveRemoteNotification:remoteNotification];
}
Reference:

Remove notification from banner

Both lines are required

1
2
[[UIApplication sharedApplication] setApplicationIconBadgeNumber: 0];
[[UIApplication sharedApplication] cancelAllLocalNotifications];
Reference:

Get version number

1
2
NSString *version = [[NSBundle mainBundle] objectForInfoDictionaryKey: @"CFBundleShortVersionString"];
NSString *build = [[NSBundle mainBundle] objectForInfoDictionaryKey: (NSString *)kCFBundleVersionKey];
Reference:

UISearchBar flat color

1
2
3
4
5
6
7
8
9
10
11
12
13
// only apply for iOS 6
if ([[UIDevice currentDevice].systemVersion floatValue] < 7) {
// go through the subview
for (UIView *subview in self.searchBar.subviews) {
if ([subview isKindOfClass:NSClassFromString(@"UISearchBarBackground")]) {
// add a view filled with flat color to the background view
UIView *flatView = [[UIView alloc] initWithFrame:subview.bounds];
flatView.backgroundColor = [UIColor greenColor];
[subview addSubview:flatView];
break;
}
}
}
Reference:

Add tap event to UINavigationBar title

1
2
3
4
5
6
7
8
9
10
11
UITapGestureRecognizer *titleViewTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(titleViewTapped:)];
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 40)];
// adjust to center
titleLabel.textAlignment = NSTextAlignmentCenter;
// standardize the text color, font
titleLabel.textColor = [[UINavigationBar appearance].titleTextAttributes valueForKey:UITextAttributeTextColor];
titleLabel.font = [[UINavigationBar appearance].titleTextAttributes valueForKey:UITextAttributeFont];
titleLabel.userInteractionEnabled = YES;
titleLabel.text = @"My awesome title";
[titleLabel addGestureRecognizer:titleViewTap];
self.navigationItem.titleView = titleLabel;

Then add a method

1
2
3
4
- (void)titleViewTapped:(UITapGestureRecognizer *)sender
{
NSLog(@"user tapped");
}
Reference:

UITableView separator on iOS7 show full width

1
2
3
if ([tableView respondsToSelector:@selector(setSeparatorInset:)]) {
[tableView setSeparatorInset:UIEdgeInsetsZero];
}
Reference:

Change UIImage default image color

alt text
alt text

1
2
3
4
UIImage *whiteIcon = [[UIImage imageNamed:@"WhiteIcon"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];

UIImageView *iconImageView = [[UIImageView alloc] initWithImage:whiteIcon];
iconImageView.tintColor = [UIColor grayColor];
Reference:

Detect a shake event

Add the code below to your ViewController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-(void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if (motion == UIEventSubtypeMotionShake )
{
NSLog(@"Shake begin");
}
}


-(void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if (motion == UIEventSubtypeMotionShake )
{
NSLog(@"Shake ended");
}
}
Reference:

Remove 1px gradient on top of UITabBar

1
[[UITabBar appearance] setShadowImage:[[UIImage alloc] init]];
Reference:

Vibrate device

Import this AudioToolbox.framework from Link Binary With Library

1
#import <AudioToolbox/AudioServices.h>

Then, use either 1 of the following

1
2
AudioServicesPlayAlertSound(kSystemSoundID_Vibrate);
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
Reference:

Get reference counter in ARC mode

1
NSLog(@"Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)myObject));
Reference:

Hide the UINavigationBar back button

1
[self.navigationItem setHidesBackButton:YES animated:YES];
Reference:

Change UIAlertView keyboard type to numpad

1
2
3
alert.alertViewStyle = UIAlertViewStylePlainTextInput;
[[alert textFieldAtIndex:0] setKeyboardType:UIKeyboardTypeNumberPad];
[alert show];

The sequence is important

Reference:

Bad performance after adding shadow

When adding shadow effect to tableView/collectionView cell, the performance will drop significantly.

1
view.layer.shouldRasterize = YES;

Set the property above solve the issue

Reference:

UICollectionViewCell subclass init never run

Implement in initWithFrame: instead

Reference:

Take screenshot from UIView

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (UIImage *)screenshotImageFromView:(UIView *)view {

UIGraphicsBeginImageContextWithOptions(view.bounds.size, 1, 0.0f);

[view.layer renderInContext:UIGraphicsGetCurrentContext()];

UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

return image;
}

// usage
UIImage *img = [self screenshotImageFromView:self.view];

UIColor from hex string

Add a macro in <Project>-Prefix.pch

1
2
3
4
#define UIColorFromRGB(rgbValue) [UIColor \
colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \
green:((float)((rgbValue & 0xFF00) >> 8))/255.0 \
blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0]

Then add a helper function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (unsigned int)intFromHexString:(NSString *) hexStr
{
unsigned int hexInt = 0;

// Create scanner
NSScanner *scanner = [NSScanner scannerWithString:hexStr];

// Tell scanner to skip the # character
[scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:@"#"]];

// Scan hex value
[scanner scanHexInt:&hexInt];

return hexInt;
}

Usage

1
UIColor *color = UIColorFromRGB([self intFromHexString:@"#ff3366"]);
References:

LocationService not working on iOS8

1
2
3
if ([_locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
[_locationManager requestWhenInUseAuthorization];
}

Call this method before startUpdatingLocation.

In the Info.plist, add

1
2
<key>NSLocationWhenInUseUsageDescription</key>
<string>You are required to enable the location service to get accurate results.</string>
Reference:

CLPlacemark.administrativeArea Malaysia list

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Selangor
Negri Sembilan
KL
Kedah
Pinang
Perak
Perlis
Malacca
Johore
Pahang
Terengganu
Kelantan
Sabah
Sarawak
Wilayah Persekutuan Labuan

Change UITextField placeholder color

1
2
3
4
5
6
if ([textField respondsToSelector:@selector(setAttributedPlaceholder:)]) {
UIColor *color = [UIColor colorWithWhite:1 alpha:0.7];
textField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:@"Placeholder text" attributes:@{NSForegroundColorAttributeName: color}];
} else {
TSLog(@"Cannot set placeholder text's color, because deployment target is earlier than iOS 6.0");
}
Reference:

Underline text on UIButton

1
2
3
4
5
6
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.titleLabel.textColor = [UIColor whiteColor];
button.backgroundColor = [UIColor clearColor];
NSMutableAttributedString *buttonStr = [[NSMutableAttributedString alloc] initWithString:@"or do other stuff"];
[buttonStr addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlineStyleSingle] range:NSMakeRange(3, [buttonStr length] - 3)];
[button setAttributedTitle:buttonStr forState:UIControlStateNormal];

The code above will underline do other stuff.

Reference:

Loop through NSDate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
- (void)dateRangeFrom:(NSDate *)fromDate to:(NSDate *)toDate
{
// add 1 day to them, e.g.
// fromDate = 2014-11-05 ; toDate = 2014-10-30, without adding 1 day, it will loop from 2014-11-04 to 2014-10-29
fromDate = [fromDate dateByAddingTimeInterval:24 * 60 * 60];
toDate = [toDate dateByAddingTimeInterval:24 * 60 * 60];

NSDateComponents *component = [NSDateComponents new];

// if fromDate is greater than toDate, then loop decending, ascending otherwise
NSComparisonResult compareResult;
if ([fromDate compare:toDate] == NSOrderedAscending) {
compareResult = NSOrderedAscending;
component.day = 1; // loop through day by day
} else {
compareResult = NSOrderedDescending;
component.day = -1;
}

NSCalendar *currentCalendar = [NSCalendar currentCalendar];

while ([fromDate compare:toDate] == compareResult) {
fromDate = [currentCalendar dateByAddingComponents:component toDate:fromDate options:0];
NSLog(@"Date %@", fromDate);
}
}
Reference:

Add touch event on UIStatusBar

AppDelegate.h

1
static NSString * const kStatusBarTappedNotification = @"statusBarTappedNotification";

AppDelegate.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#pragma mark - Status bar touch tracking
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
CGPoint location = [[[event allTouches] anyObject] locationInView:[self window]];
CGRect statusBarFrame = [UIApplication sharedApplication].statusBarFrame;
if (CGRectContainsPoint(statusBarFrame, location)) {
[self statusBarTouchedAction];
}
}

- (void)statusBarTouchedAction {
[[NSNotificationCenter defaultCenter] postNotificationName:kStatusBarTappedNotification
object:nil];
}

AnyViewController.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarTappedAction:) name:kStatusBarTappedNotification object:nil];
}

- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];

[[NSNotificationCenter defaultCenter] removeObserver:self name:kStatusBarTappedNotification object:nil];
}

- (void)statusBarTappedAction:(NSNotification*)notification
{
NSLog(@"StatusBar tapped");
}
Reference:

1
2
3
4
5
textView.editable = NO;
textView.dataDetectorTypes = UIDataDetectorTypeAll;
if ([textView respondsToSelector:@selector(setLinkTextAttributes:)]) {
textView.linkTextAttributes = @{NSForegroundColorAttributeName: [UIColor redColor]};
}
Reference:

Get rotation angle from CGAffineTransform

1
atan2(transform.b, transform.a);

NOTE: The value are in radian

Reference:

Update status bar background color, fade when scroll

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@implementation ViewController {
UIView *_statusBarBackgroundView;
}

- (void)viewDidLoad {
...
_statusBarBackgroundView = [[UIView alloc] initWithFrame:[[UIApplication sharedApplication] statusBarFrame]];
_statusBarBackgroundView.backgroundColor = [UIColor clearColor];
[self.view addSubview:_statusBarBackgroundView];
}

#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGFloat offset = scrollView.contentOffset.y;
CGFloat initialPoint = 40;
CGFloat endPoint = 80;

if (offset > initialPoint) {
CGFloat opacity = (offset - initialPoint) / (endPoint - initialPoint);
opacity = MIN(opacity, 1);
_statusBarBackgroundView.backgroundColor = UIColorFromRGBA(0xfc8d8d, opacity);
} else {
_statusBarBackgroundView.backgroundColor = [UIColor clearColor];
}
self.navigationController.navigationBar.backgroundColor = _statusBarBackgroundView.backgroundColor;
}
Reference:

UIWebView inject css

1
2
3
4
5
6
7
8
9
10
11
12
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
NSString* css = @"\"@font-face { font-family: 'Chalkboard'; src: local('ChalkboardSE-Regular'); } body { background-color: #F0F0FC; color: #572B00; font-family: Chalkboard;} a { color: #A00; text-decoration: none;}\"";
NSString* js = [NSString stringWithFormat:
@"var styleNode = document.createElement('style');\n"
"styleNode.type = \"text/css\";\n"
"var styleText = document.createTextNode(%@);\n"
"styleNode.appendChild(styleText);\n"
"document.getElementsByTagName('head')[0].appendChild(styleNode);\n",css];
NSLog(@"js:\n%@",js);
[self.webView stringByEvaluatingJavaScriptFromString:js];
}
Reference:

UIImagePickerControllerOriginalImage orientation issue

1
2
3
4
5
6
7
8
9
+ (UIImage*)removeOrientationForImage:(UIImage*)image {
CGSize size = image.size;
UIGraphicsBeginImageContext(size);
[image drawInRect:CGRectMake(0,0,size.width ,size.height)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

return newImage;
}
Reference:

DAKeyboardControl issue with UITabBar

1
2
3
4
5
6
7
8
9
10
[contentView addKeyboardPanningWithActionHandler:^(CGRect keyboardFrameInView, BOOL opening, BOOL closing) {

CGRect toolBarFrame = toolBar.frame;
toolBarFrame.origin.y = MIN(keyboardFrameInView.origin.y, contentView.bounds.size.height) - toolBarFrame.size.height;
toolBar.frame = toolBarFrame;

CGRect tableViewFrame = tableView.frame;
tableViewFrame.size.height = toolBarFrame.origin.y;
tableView.frame = tableViewFrame;
}];
Reference:

NSArray extract a single column into another array

e.g.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[
{
"id": "1",
"name": "Foo"
},
{
"id": "2",
"name": "Bar"
},
{
"id": "3",
"name": "Foo Bar"
},
]

After calling

1
[myArr mutableArrayValueForKey:@"name"]

New result

1
["Foo", "Bar", "Foo Bar"]

MKMapView event after dragged/zoomed

1
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated;
Reference:

Custom UIResponder trigger event

Example, create a CustomCheckbox, want to perform ValueChanged event when touched on the checkbox

CustomCheckbox.m

1
2
3
4
5
6
7
- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{
self.checked = !_checked;
// trigger value changed event
[self sendActionsForControlEvents:UIControlEventValueChanged];
return YES;
}

ViewController.m

1
[checkbox addTarget:self action:@selector(checkboxChecked:) forControlEvents:UIControlEventValueChanged];
Reference:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#import <objc/message.h>

- (NSString *)descriptionForObject:(id)objct
{
unsigned int varCount;
NSMutableString *descriptionString = [[NSMutableString alloc]init];


objc_property_t *vars = class_copyPropertyList(object_getClass(objct), &varCount);

for (int i = 0; i < varCount; i++)
{
objc_property_t var = vars[i];

const char* name = property_getName (var);

NSString *keyValueString = [NSString stringWithFormat:@"\n%@ = %@",[NSString stringWithUTF8String:name],[objct valueForKey:[NSString stringWithUTF8String:name]]];
[descriptionString appendString:keyValueString];
}

free(vars);
return descriptionString;
}

Usage: NSLog(@"obj %@", [self descriptionForObject:obj]);

Reference:

AFNetworking

Check is offline

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[[AFNetworkReachabilityManager sharedManager] startMonitoring];
[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
NSLog(@"Reachability: %@", AFStringFromNetworkReachabilityStatus(status));
switch (status) {
case AFNetworkReachabilityStatusReachableViaWWAN:
case AFNetworkReachabilityStatusReachableViaWiFi:
NSLog(@"online");
break;
case AFNetworkReachabilityStatusNotReachable:
default:
NSLog(@"offline");
break;
}
}];
Reference:

Animation

Flip animation between view controllers

Present

1
2
viewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentViewController:viewController animated:YES completion:nil];

Dismiss

1
[self dismissViewControllerAnimated:YES completion:nil];
Reference:

Move object from bottom to top

1
2
3
4
5
6
7
8
9
10
11
12
// set the initial position
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(40, 320, 240, 100)];
...

[UIView animateWithDuration:1.0 // 1 second
delay:0.0
options:UIViewAnimationOptionCurveLinear
animations:^{
// move the image to top
imageView.center = CGPointMake(imageView.center.x, 100);
}
completion:nil];

Fade in UIButton

1
2
3
4
5
6
7
8
9
10
11
UIButton *fooButton = [UIButton buttonWithType:UIButtonTypeCustom];
fooButton.frame = ...;
fooButton.alpha = 0; // set to transparent first

[UIView animateWithDuration:0.5 // 0.5 second
delay:0.0
options:UIViewAnimationOptionCurveLinear
animations:^{
fooButton.alpha = 1.0; // slowly fade in
}
completion:nil];
Reference:

Flip animation between 2 views

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.view cache:NO];

// optional: event handler after animation
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(viewFlipped)];

int listViewIndex = [self.view.subviews indexOfObject:self.tableView];
int mapViewIndex = [self.view.subviews indexOfObject:self.mapView];

if (listViewIndex > mapViewIndex)
{
sender.title = @"List";
[self.view bringSubviewToFront:self.mapView];
}
else
{
sender.title = @"Map";
[self.view bringSubviewToFront:self.tableView];
}

[UIView commitAnimations];

If you added the event handler, just add the code below

1
2
3
4
- (void)viewFlipped
{
NSLog(@"Flip animation completed.");
}
References:

Facebook

Force user to allow publish_actions permission

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
@implementation MyViewController {
NSString *fbToken;
}

...

// when tapped on facebook button
- (IBAction)facebookTouched:(UIButton *)sender
{
// We will request the user's public profile and the user's birthday
// These are the permissions we need:
NSArray *permissionsNeeded = @[@"publish_actions", @"email"];

// don't cache the token
FBSession *mySession = [[FBSession alloc] initWithAppID:nil permissions:permissionsNeeded urlSchemeSuffix:nil tokenCacheStrategy:[FBSessionTokenCachingStrategy nullCacheInstance]];

[mySession openWithCompletionHandler:^(FBSession *session,
FBSessionState status,
NSError *error) {

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Facebook Error" message:@"You must allow Facebook permissions" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];

if (error) { // user not allow "email"
[alert show];
} else {

// i don't know what is this for, if without this line, this block will be executed 2 times and get error
if (status == 258) return;

[FBSession setActiveSession:session];

// Request the permissions the user currently has
[FBRequestConnection startWithGraphPath:@"/me/permissions"
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if (!error) {
// These are the current permissions the user has:
NSDictionary *currentPermissions = [(NSArray *)[result data] objectAtIndex:0];

// We will store here the missing permissions that we will have to request
NSMutableArray *requestPermissions = [[NSMutableArray alloc] initWithArray:@[]];

// Check if all the permissions we need are present in the user's current permissions
// If they are not present add them to the permissions to be requested
for (NSString *permission in permissionsNeeded){
if (![currentPermissions objectForKey:permission]){
[requestPermissions addObject:permission];
}
}

// If we have more permissions to request
if ([requestPermissions count] > 0) { // user haven't allow publish_actions
[alert show];
} else {
fbToken = session.accessTokenData.accessToken;
}

} else {
// An error occurred, we need to handle the error
// See: https://developers.facebook.com/docs/ios/errors
NSLog(@"error %@", error.description);
}
}];
}
}];
}

Get profile picture

1
2
3
4
5
6
7
8
9
10
// set image & user name
[FBSession setActiveSession:self.session];
[[FBRequest requestForMe] startWithCompletionHandler:^(FBRequestConnection *connection, NSDictionary<FBGraphUser> *FBuser, NSError *error) {
if (error) {
NSLog(@"error %@", error.description);
} else {
self.usernameLabel.text = [FBuser name];
[self.avatarImageView setImageWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"https://graph.facebook.com/%@/picture?height=100&type=normal&width=100", [FBuser username]]]];
}
}];
Reference:

FacebookSDK 4.x

Login

ViewController.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#import <FBSDKCoreKit/FBSDKCoreKit.h>
#import <FBSDKLoginKit/FBSDKLoginKit.h>

- (void)facebookButtonTapped:(id)sender
{
FBSDKLoginManager *loginManager = [[FBSDKLoginManager alloc] init];
[loginManager logInWithReadPermissions:@[@"email"] handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
if (error) {
NSLog(@"Facebook error: %@", [error localizedDescription]);
return;
}
NSLog(@"Facebook token: %@", result.token.tokenString);
}];
}

AppDelegate.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#import <FBSDKCoreKit/FBSDKCoreKit.h>

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

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
return [[FBSDKApplicationDelegate sharedInstance] application:application
openURL:url
sourceApplication:sourceApplication
annotation:annotation];
}