Swipe 2011 - iOS Gems

1,939 views
1,797 views

Published on

iOS Gems
Some jewels for your glory box

My talk from Swipe 2011.

Published in: Technology, Business
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,939
On SlideShare
0
From Embeds
0
Number of Embeds
48
Actions
Shares
0
Downloads
18
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Swipe 2011 - iOS Gems

  1. 1. 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 :)
  2. 2. Roadmap• Enhancing NSArray• View size and layout• Simple gestures handling• Closing thoughts
  3. 3. Enhancing NSArray
  4. 4. NSArrayGreat Core Support
  5. 5. But …
  6. 6. It’s verbose- (NSIndexSet *)indexesOfObjectsWithOptions:(NSEnumerationOptions)opts passingTest:(BOOL(^)(id obj, NSUInteger idx, BOOL *stop))predicate
  7. 7. Difficult to combine- (NSIndexSet *)indexesOfObjectsAtIndexes:(NSIndexSet *)indexes options:(NSEnumerationOptions)opts passingTest:(BOOL(^)(id obj, NSUInteger idx, BOOL*stop))predicate;
  8. 8. We Can Do Better• Enumeration• Filtering• Transformation
  9. 9. Enumeration- (void)each: (void (^)(id item))block;- (void)eachWithIndex: (void (^)(id, NSUInteger))block;
  10. 10. Consider carefully
  11. 11. Results by side effect only
  12. 12. Huh?
  13. 13. Enumerations produce no ‘value’
  14. 14. They mutate state of the world around them
  15. 15. EG NSMutableSet *uniqueNames = [NSMutableSet set];[names each: ^ (id name) { [uniqueNames addObject:name];}];
  16. 16. OR[[view subviews] eachWithIndex:^ (id subview,NSUInteger position) { CGRect cell_frame = CGRectMake(subview_width * position, 0, requested_subview_size.width, requested_subview_size.height);
  17. 17. DemoEnumerationUse and implementation
  18. 18. A for loop may often be a better choice
  19. 19. Useful at the tail oftransform operations
  20. 20. Filtering- (NSArray *)filter:(BOOL (^)(id item))block;- (NSArray *)pick:(BOOL (^)(id item))block;- (id)first:(BOOL (^)(id))block;- (id)last:(BOOL (^)(id))block;
  21. 21. Filter removes matching elements
  22. 22. 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"
  23. 23. Pick selects matching elements
  24. 24. 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"
  25. 25. First returns the first element matched
  26. 26. FirstNSArray *names = [NSArray arrayWithObjects: @"Kevin", @"Sue", @"Aaron", @"Jack", @"Maddie", nil];NSLog(@"%@", [names first:^BOOL(id name) { return [name length] < 5;}]);"Sue"
  27. 27. Last returns the last element matched
  28. 28. LastNSArray *names = [NSArray arrayWithObjects: @"Kevin", @"Sue", @"Aaron", @"Jack", @"Maddie", nil];NSLog(@"%@", [names last:^BOOL(id name) { return [name length] < 5;}]);"Jack"
  29. 29. DemoFilter, Pick, First and LastUse and implementation
  30. 30. Transformation- (NSArray *)map:(id (^)(id item))block;- (id)reduce:(id (^)(id current, id item))block initial:(id)initial;- (NSArray *)intersperse:(id (^) (void))separator;
  31. 31. Map applies the block to each element
  32. 32. 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"…
  33. 33. Reduce applies the blockto each element passing the result along
  34. 34. 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"
  35. 35. Place the result of theblock between elements
  36. 36. 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""<"…
  37. 37. DemoMap, Reduce, IntersperseUse and implementation
  38. 38. View size and layout
  39. 39. How to size and layoutsubviews without pain
  40. 40. I have a confession
  41. 41. I’m an interface builder muppet
  42. 42. Two methods are key
  43. 43. Two methods are key- (void)layoutSubviews;- (CGSize)sizeThatFits:(CGSize)size;
  44. 44. A diversion.Paired methods.
  45. 45. sizeThatFits: andlayoutSubviews are loosely paired
  46. 46. They must be sympathetic to one and other
  47. 47. - (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
  48. 48. - (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
  49. 49. But here’s the rub
  50. 50. The calculations used are often the same, just applied differently
  51. 51. 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;}
  52. 52. 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.]];}
  53. 53. The only real variance here is the action
  54. 54. And that’s a simple example
  55. 55. We can do better
  56. 56. DemoSize and Layout
  57. 57. The layout algorithm is coded once
  58. 58. Then applied appropriately
  59. 59. Simple gestures handling
  60. 60. Gesture recognisers rock
  61. 61. But maintaining pairing between selectors andactions is a little tedious
  62. 62. EG - (void)cancelRequest{ [self displayCancelMessage];}UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(cancelRequest)];
  63. 63. We can do better
  64. 64. Can you guess what makes gesture handling easier?
  65. 65. DemoGesture recognisers
  66. 66. Blocks make gesture setup much easier
  67. 67. Closing thoughts
  68. 68. Take from this what you will
  69. 69. Understanding blocks willmake you more productive
  70. 70. New Core API’s are taking advantage of blocks
  71. 71. So should you
  72. 72. Categories are a keymethod of partitioning behaviour
  73. 73. Blocks are a key method of partitioning algorithms
  74. 74. Associated objects should be part of your toolkit
  75. 75. But
  76. 76. Don’t use these toolsbecause they are there
  77. 77. Use them to make your code …
  78. 78. Simpler
  79. 79. Easier to maintain
  80. 80. Useful BitsOpen source libraries usedhttps://github.com/kevinoneill/Useful-Bitshttps://github.com/kevinoneill/Useful-Swipehttps://github.com/domesticcatsoftware/DCIntrospectQuestions?

×