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

Swipe 2011 - iOS Gems



iOS Gems

iOS Gems
Some jewels for your glory box

My talk from Swipe 2011.



Total Views
Views on SlideShare
Embed Views



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


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.

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
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?