Swipe 2011 - iOS Gems
Upcoming SlideShare
Loading in...5
×
 

Swipe 2011 - iOS Gems

on

  • 1,845 views

iOS Gems

iOS Gems
Some jewels for your glory box

My talk from Swipe 2011.

Statistics

Views

Total Views
1,845
Views on SlideShare
1,812
Embed Views
33

Actions

Likes
1
Downloads
17
Comments
0

5 Embeds 33

http://www.linkedin.com 16
https://twitter.com 8
https://www.linkedin.com 5
http://twitter.com 3
http://us-w1.rockmelt.com 1

Accessibility

Upload Details

Uploaded via as Adobe PDF

Usage Rights

CC Attribution-NonCommercial LicenseCC Attribution-NonCommercial License

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Swipe 2011 - iOS Gems Swipe 2011 - iOS Gems Presentation Transcript

  • iOS GemsSome jewels for your glory boxKevin O’NeillDelivery Manager – MobileREA Grouptwitter: @kevinoneillThis is not a con dential session — please stream, blog, tweet and take pictures :)
  • Roadmap• Enhancing NSArray• View size and layout• Simple gestures handling• Closing thoughts
  • Enhancing NSArray
  • NSArrayGreat Core Support
  • But …
  • It’s verbose- (NSIndexSet *)indexesOfObjectsWithOptions:(NSEnumerationOptions)opts passingTest:(BOOL(^)(id obj, NSUInteger idx, BOOL *stop))predicate
  • Difficult to combine- (NSIndexSet *)indexesOfObjectsAtIndexes:(NSIndexSet *)indexes options:(NSEnumerationOptions)opts passingTest:(BOOL(^)(id obj, NSUInteger idx, BOOL*stop))predicate;
  • We Can Do Better• Enumeration• Filtering• Transformation
  • Enumeration- (void)each: (void (^)(id item))block;- (void)eachWithIndex: (void (^)(id, NSUInteger))block;
  • Consider carefully
  • Results by side effect only
  • Huh?
  • Enumerations produce no ‘value’
  • They mutate state of the world around them
  • EG NSMutableSet *uniqueNames = [NSMutableSet set];[names each: ^ (id name) { [uniqueNames addObject:name];}];
  • OR[[view subviews] eachWithIndex:^ (id subview,NSUInteger position) { CGRect cell_frame = CGRectMake(subview_width * position, 0, requested_subview_size.width, requested_subview_size.height);
  • DemoEnumerationUse and implementation
  • A for loop may often be a better choice
  • Useful at the tail oftransform operations
  • Filtering- (NSArray *)filter:(BOOL (^)(id item))block;- (NSArray *)pick:(BOOL (^)(id item))block;- (id)first:(BOOL (^)(id))block;- (id)last:(BOOL (^)(id))block;
  • Filter removes matching elements
  • Filter NSArray *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"
  • Pick selects matching elements
  • 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"
  • First returns the first element matched
  • FirstNSArray *names = [NSArray arrayWithObjects: @"Kevin", @"Sue", @"Aaron", @"Jack", @"Maddie", nil];NSLog(@"%@", [names first:^BOOL(id name) { return [name length] < 5;}]);"Sue"
  • Last returns the last element matched
  • LastNSArray *names = [NSArray arrayWithObjects: @"Kevin", @"Sue", @"Aaron", @"Jack", @"Maddie", nil];NSLog(@"%@", [names last:^BOOL(id name) { return [name length] < 5;}]);"Jack"
  • DemoFilter, Pick, First and LastUse and implementation
  • Transformation- (NSArray *)map:(id (^)(id item))block;- (id)reduce:(id (^)(id current, id item))block initial:(id)initial;- (NSArray *)intersperse:(id (^) (void))separator;
  • Map applies the block to each element
  • 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"…
  • Reduce applies the blockto each element passing the result along
  • 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"
  • Place the result of theblock between elements
  • 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""<"…
  • DemoMap, Reduce, IntersperseUse and implementation
  • View size and layout
  • How to size and layoutsubviews without pain
  • I have a confession
  • I’m an interface builder muppet
  • Two methods are key
  • Two methods are key- (void)layoutSubviews;- (CGSize)sizeThatFits:(CGSize)size;
  • A diversion.Paired methods.
  • sizeThatFits: andlayoutSubviews are loosely paired
  • They must be sympathetic to one and other
  • - (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
  • - (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
  • But here’s the rub
  • The calculations used are often the same, just applied differently
  • 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;}
  • 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.]];}
  • The only real variance here is the action
  • And that’s a simple example
  • We can do better
  • DemoSize and Layout
  • The layout algorithm is coded once
  • Then applied appropriately
  • Simple gestures handling
  • Gesture recognisers rock
  • But maintaining pairing between selectors andactions is a little tedious
  • EG - (void)cancelRequest{ [self displayCancelMessage];}UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(cancelRequest)];
  • We can do better
  • Can you guess what makes gesture handling easier?
  • DemoGesture recognisers
  • Blocks make gesture setup much easier
  • Closing thoughts
  • Take from this what you will
  • Understanding blocks willmake you more productive
  • New Core API’s are taking advantage of blocks
  • So should you
  • Categories are a keymethod of partitioning behaviour
  • Blocks are a key method of partitioning algorithms
  • Associated objects should be part of your toolkit
  • But
  • Don’t use these toolsbecause they are there
  • Use them to make your code …
  • Simpler
  • Easier to maintain
  • Useful BitsOpen source libraries usedhttps://github.com/kevinoneill/Useful-Bitshttps://github.com/kevinoneill/Useful-Swipehttps://github.com/domesticcatsoftware/DCIntrospectQuestions?