swipe 2011 - ios gems

80
Some jewels for your glory box Kevin O’Neill Delivery Manager – Mobile REA Group twitter: @kevinoneill iOS Gems This is not a condential session — please stream, blog, tweet and take pictures :)

Upload: kevin-oneill

Post on 03-Jul-2015

1.682 views

Category:

Technology


2 download

DESCRIPTION

iOS GemsSome jewels for your glory boxMy talk from Swipe 2011.

TRANSCRIPT

Page 1: Swipe 2011 - iOS Gems

Some jewels for your glory box

Kevin O’NeillDelivery Manager – MobileREA Grouptwitter: @kevinoneill

iOS Gems

This is not a con!dential session — please stream, blog, tweet and take pictures :)

Page 2: Swipe 2011 - iOS Gems

Roadmap

• Enhancing NSArray

• View size and layout

• Simple gestures handling

• Closing thoughts

Page 3: Swipe 2011 - iOS Gems

Enhancing NSArray

Page 4: Swipe 2011 - iOS Gems

NSArrayGreat Core Support

Page 5: Swipe 2011 - iOS Gems

But …

Page 6: Swipe 2011 - iOS Gems

It’s verbose- (NSIndexSet *)indexesOfObjectsWithOptions:(NSEnumerationOptions)opts passingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop)) predicate

Page 7: Swipe 2011 - iOS Gems

Difficult to combine- (NSIndexSet *)indexesOfObjectsAtIndexes:(NSIndexSet *)indexes options:(NSEnumerationOptions)opts passingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate;

Page 8: Swipe 2011 - iOS Gems

We Can Do Better

• Enumeration

• Filtering

• Transformation

Page 9: Swipe 2011 - iOS Gems

Enumeration- (void)each: (void (^)(id item))block;

- (void)eachWithIndex: (void (^)(id, NSUInteger))block;

Page 10: Swipe 2011 - iOS Gems

Consider carefully

Page 11: Swipe 2011 - iOS Gems

Results by side effect only

Page 12: Swipe 2011 - iOS Gems

Huh?

Page 13: Swipe 2011 - iOS Gems

Enumerations produce no ‘value’

Page 14: Swipe 2011 - iOS Gems

They mutate state of the world around them

Page 15: Swipe 2011 - iOS Gems

EGNSMutableSet *uniqueNames = [NSMutableSet set];

[names each: ^ (id name) { [uniqueNames addObject:name];}];

Page 16: Swipe 2011 - iOS Gems

OR[[view subviews] eachWithIndex:^ (id subview, NSUInteger position) {

CGRect cell_frame = CGRectMake(subview_width * position, 0, requested_subview_size.width, requested_subview_size.height);

Page 17: Swipe 2011 - iOS Gems

DemoEnumerationUse and implementation

Page 18: Swipe 2011 - iOS Gems

A for loop may often be a better choice

Page 19: Swipe 2011 - iOS Gems

Useful at the tail of transform operations

Page 20: Swipe 2011 - iOS Gems

Filtering- (NSArray *)filter:(BOOL (^)(id item))block;

- (NSArray *)pick:(BOOL (^)(id item))block;

- (id)first:(BOOL (^)(id))block;

- (id)last:(BOOL (^)(id))block;

Page 21: Swipe 2011 - iOS Gems

Filter removes matching elements

Page 22: Swipe 2011 - iOS Gems

FilterNSArray *names = [NSArray arrayWithObjects:

@"Kevin", @"Sue", @"Aaron", @"Jack", @"Maddie", nil];

[[names filter:^BOOL(id name) { return [name length] < 5;}] each:^(id name) { NSLog(@"%@", name);}];

"Kevin""Aaron""Maddie"

Page 23: Swipe 2011 - iOS Gems

Pick selects matching elements

Page 24: Swipe 2011 - iOS Gems

PickNSArray *names = [NSArray arrayWithObjects: @"Kevin", @"Sue", @"Aaron", @"Jack", @"Maddie", nil];

[[names pick:^BOOL(id name) { return [name length] < 5;}] each:^(id name) { NSLog(@"%@", name);}];

"Sue""Jack"

Page 25: Swipe 2011 - iOS Gems

First returns the first element matched

Page 26: Swipe 2011 - iOS Gems

FirstNSArray *names = [NSArray arrayWithObjects: @"Kevin", @"Sue", @"Aaron", @"Jack", @"Maddie", nil];

NSLog(@"%@", [names first:^BOOL(id name) { return [name length] < 5;}]);

"Sue"

Page 27: Swipe 2011 - iOS Gems

Last returns the last element matched

Page 28: Swipe 2011 - iOS Gems

LastNSArray *names = [NSArray arrayWithObjects: @"Kevin", @"Sue", @"Aaron", @"Jack", @"Maddie", nil];

NSLog(@"%@", [names last:^BOOL(id name) { return [name length] < 5;}]);

"Jack"

Page 29: Swipe 2011 - iOS Gems

DemoFilter, Pick, First and LastUse and implementation

Page 30: Swipe 2011 - iOS Gems

Transformation- (NSArray *)map:(id (^)(id item))block;

- (id)reduce:(id (^)(id current, id item))block initial:(id)initial;

- (NSArray *)intersperse:(id (^) (void))separator;

Page 31: Swipe 2011 - iOS Gems

Map applies the block to each element

Page 32: Swipe 2011 - iOS Gems

MapNSArray *names = [NSArray arrayWithObjects: @"Kevin", @"Sue", @"Aaron", @"Jack", @"Maddie", nil];

[[names map:^id(id name) { return [NSNumber numberWithInteger: [name length]]; }] each:^(id length) { NSLog(@"%@", length);}];

"5""3""5"…

Page 33: Swipe 2011 - iOS Gems

Reduce applies the block to each element passing

the result along

Page 34: Swipe 2011 - iOS Gems

ReduceNSArray *names = [NSArray arrayWithObjects: @"Kevin", @"Sue", @"Aaron", @"Jack", @"Maddie", nil];

NSLog(@"%@",[names reduce:^id(id current, id item) {

NSInteger result = [current integerValue] + [item length]; return [NSNumber numberWithInteger:result];

} initial:[NSNumber numberWithInteger:0]]);

"23"

Page 35: Swipe 2011 - iOS Gems

Place the result of the block between elements

Page 36: Swipe 2011 - iOS Gems

IntersperseNSArray *names = [NSArray arrayWithObjects: @"Kevin", @"Sue", @"Aaron", @"Jack", @"Maddie", nil];

[[names intersperse:^id(id current, id next) { return [current length] > [next length] ? @">" : @"<"; }] each:^(id item) { NSLog(@"%@", item);}];

"Kevin"">""Sue""<"…

Page 37: Swipe 2011 - iOS Gems

DemoMap, Reduce, IntersperseUse and implementation

Page 38: Swipe 2011 - iOS Gems

View size and layout

Page 39: Swipe 2011 - iOS Gems

How to size and layout subviews without pain

Page 40: Swipe 2011 - iOS Gems

I have a confession

Page 41: Swipe 2011 - iOS Gems

I’m an interface builder muppet

Page 42: Swipe 2011 - iOS Gems

Two methods are key

Page 43: Swipe 2011 - iOS Gems

Two methods are key- (void)layoutSubviews;- (CGSize)sizeThatFits:(CGSize)size;

Page 44: Swipe 2011 - iOS Gems

A diversion.Paired methods.

Page 45: Swipe 2011 - iOS Gems

sizeThatFits: and layoutSubviews are loosely

paired

Page 46: Swipe 2011 - iOS Gems

They must be sympathetic to one and other

Page 47: Swipe 2011 - iOS Gems

- (void)layoutSubviews;

• Does nothing by default

• Used to position subviews

• Called when the layout is dirty

• Don’t call it manually– I’ve seen to many times

• Don’t resize self – I’ve seen to many times

Page 48: Swipe 2011 - iOS Gems

- (CGSize)sizeThatFits: (CGSize)size;

• Returns current size by default

• Return ‘best’ size to fit given size

• Doesn’t resize the view

• Don’t resize the view – I’ve seen to many times

• Don’t layout view – I’ve seen to many times

Page 49: Swipe 2011 - iOS Gems

But here’s the rub

Page 50: Swipe 2011 - iOS Gems

The calculations used are often the same, just applied differently

Page 51: Swipe 2011 - iOS Gems

EG- (CGSize)sizeThatFits:(CGSize)size;

{ float width = size.width; float height = [[[self subviews] reduce: ^ id (id current, id item) { CGSize item_size = [item sizeThatFits:CGSizeMake(width, 0.)];

return [NSNumber numberWithFloat: ceilf([current floatValue] + (item_size.height + [self spacingForSubview:item]))];

} initial:[NSNumber numberWithFloat:0.]] floatValue];

CGSize result = CGSizeMake(width, height); return result;}

Page 52: Swipe 2011 - iOS Gems

And- (void)layoutSubviews;

{ float width = [self width];

__block StackedView *block_self = self;

[[self subviews] reduce: ^ id (id current, id item) { CGSize item_size = [item sizeThatFits:CGSizeMake(width, 0.)];

[item setFrame: CGRectMake(0, [current floatValue] + [block_self spacingForSubview:item], item_size.width, item_size.height)];

return [NSNumber numberWithFloat:ceilf([item bottom])]; } initial:[NSNumber numberWithFloat:0.]];}

Page 53: Swipe 2011 - iOS Gems

The only real variance here is the action

Page 54: Swipe 2011 - iOS Gems

And that’s a simple example

Page 55: Swipe 2011 - iOS Gems

We can do better

Page 56: Swipe 2011 - iOS Gems

DemoSize and Layout

Page 57: Swipe 2011 - iOS Gems

The layout algorithm is coded once

Page 58: Swipe 2011 - iOS Gems

Then applied appropriately

Page 59: Swipe 2011 - iOS Gems

Simple gestures handling

Page 60: Swipe 2011 - iOS Gems

Gesture recognisers rock

Page 61: Swipe 2011 - iOS Gems

But maintaining pairing between selectors and

actions is a little tedious

Page 62: Swipe 2011 - iOS Gems

EG- (void)cancelRequest

{ [self displayCancelMessage];}

UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(cancelRequest)];

Page 63: Swipe 2011 - iOS Gems

We can do better

Page 64: Swipe 2011 - iOS Gems

Can you guess what makes gesture handling easier?

Page 65: Swipe 2011 - iOS Gems

DemoGesture recognisers

Page 66: Swipe 2011 - iOS Gems

Blocks make gesture setup much easier

Page 67: Swipe 2011 - iOS Gems

Closing thoughts

Page 68: Swipe 2011 - iOS Gems

Take from this what you will

Page 69: Swipe 2011 - iOS Gems

Understanding blocks will make you more productive

Page 70: Swipe 2011 - iOS Gems

New Core API’s are taking advantage of blocks

Page 71: Swipe 2011 - iOS Gems

So should you

Page 72: Swipe 2011 - iOS Gems

Categories are a key method of partitioning

behaviour

Page 73: Swipe 2011 - iOS Gems

Blocks are a key method of partitioning algorithms

Page 74: Swipe 2011 - iOS Gems

Associated objects should be part of your toolkit

Page 75: Swipe 2011 - iOS Gems

But

Page 76: Swipe 2011 - iOS Gems

Don’t use these tools because they are there

Page 77: Swipe 2011 - iOS Gems

Use them to make your code …

Page 78: Swipe 2011 - iOS Gems

Simpler

Page 79: Swipe 2011 - iOS Gems

Easier to maintain

Page 80: Swipe 2011 - iOS Gems

https://github.com/kevinoneill/Useful-Bitshttps://github.com/kevinoneill/Useful-Swipehttps://github.com/domesticcatsoftware/DCIntrospect

Open source libraries used

Useful Bits

Questions?