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

Swipe 2011 - iOS Gems

on

  • 1,826 views

iOS Gems

iOS Gems
Some jewels for your glory box

My talk from Swipe 2011.

Statistics

Views

Total Views
1,826
Slideshare-icon Views on SlideShare
1,794
Embed Views
32

Actions

Likes
1
Downloads
17
Comments
0

5 Embeds 32

http://www.linkedin.com 16
https://twitter.com 8
https://www.linkedin.com 4
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?