Cocoa Touch: The Good, The Bad and The Ugly

Cocoa Touch: The Good, The Bad and The Ugly

This is a talk I gave at Alt Tech Talks London, as a try out for MCE.

Ade0c334ecff1448bb96f5f733bf1f83?s=128

Chris Eidhof | @chriseidhof

December 16, 2013
Tweet

Transcript

  1. None
  2. Cocoa Touch The Good, The Bad and The Ugly Chris

    Eidhof
  3. Cocoa Touch The Ugly, The Good and The Bad Chris

    Eidhof
  4. commit c416c1d259bddaa74833e6df5acd770f85622293 Author: Chris Eidhof <ce@tupil.com> Date: Wed Jan 7

    11:54:34 2009 +0100 Empty project
  5. None
  6. None
  7. I thought I was a pretty good programmer

  8. I knew PHP, Ruby and Haskell

  9. How hard can it be?

  10. None
  11. The ugly

  12. Example code @interface HiscoreTableViewCell : UITableViewCell { IBOutlet UIImageView *badge;

    IBOutlet UILabel *badgeTitle; IBOutlet UILabel *name1; IBOutlet UILabel *name2; IBOutlet UILabel *name3; IBOutlet UILabel *position1; IBOutlet UILabel *position2; IBOutlet UILabel *position3; IBOutlet UILabel *score1; IBOutlet UILabel *score2; IBOutlet UILabel *score3; }
  13. Example code (continued) @property (nonatomic,readonly) UIImageView* badge; @property (nonatomic,readonly) UILabel

    *badgeTitle; @property (nonatomic,readonly) UILabel *name1; @property (nonatomic,readonly) UILabel *name2; @property (nonatomic,readonly) UILabel *name3; @property (nonatomic,readonly) UILabel *position1; @property (nonatomic,readonly) UILabel *position2; @property (nonatomic,readonly) UILabel *position3; @property (nonatomic,readonly) UILabel *score1; @property (nonatomic,readonly) UILabel *score2; @property (nonatomic,readonly) UILabel *score3;
  14. Example code (continued) @synthesize badge; @synthesize badgeTitle; @synthesize name1; @synthesize

    name2; @synthesize name3; @synthesize position1; @synthesize position2; @synthesize position3; @synthesize score1; @synthesize score2; @synthesize score3;
  15. There's more

  16. //TODO: as of here, it is completely broken if ([gameView

    superview] != nil) { [[SoundBoard sharedSoundBoard] startMenuTune]; [menuViewController viewWillAppear:YES]; [gameViewController viewWillDisappear:YES]; [gameView removeFromSuperview]; [gameViewController viewDidDisappear:YES]; [menuViewController viewDidAppear:YES]; } else {
  17. NSURL *cgiUrl = [NSURL URLWithString:POST_SCORE_URL]; NSMutableURLRequest *p = [NSMutableURLRequest requestWithURL:cgiUrl];

    [p setTimeoutInterval:4]; [p setHTTPMethod:@"POST"]; [p setHTTPBody:requestData]; NSURLResponse *response = nil; NSError *error = nil; NSData *responseData = [NSURLConnection sendSynchronousRequest:p returningResponse:&response error:&error];
  18. Memory Management 1. Add an instance variable 2. Add a

    property 3. Add a synthesize 4. Add a dealloc call
  19. Memory Management 1. Add an instance variable 2. Add a

    property 3. Add a synthesize 4. Add a dealloc call
  20. Memory Management

  21. Animations [UIView beginAnimations:@"GameOver" context:NULL]; [UIView setAnimationDuration:0.3]; [UIView setAnimationRepeatCount:2]; [UIView setAnimationRepeatAutoreverses:YES];

    // Call animateOtherStuff when the animation is done [UIView setAnimationDelegate:self]; [UIView setAnimationDidStopSelector: @selector(afterGameOverAnimation:finished:context:)];
  22. Animations 2013 [UIView animateWithDuration:0.3 animations:^{ timesUp.alpha = 1; } completion:^(BOOL

    finished) { [self.milkGlass removeFromSuperview]; }]
  23. None
  24. The Good

  25. If there's only one thing you'll remember Write code for

    the person after you
  26. ▸ Write a lot of code ▸ Work with other

    people ▸ Write articles ▸ Read books and code
  27. Write a lot of code ▸ Lots of production code

    ▸ Lots of throwaway code
  28. Throwaway code

  29. Collaborate ▸ With people who are better than you ▸

    Or who aren't better than you
  30. Write Forces you to think.

  31. Absolute Knowledge

  32. Perceived Knowledge

  33. Strive to become better

  34. Ship

  35. Frameworks

  36. 2013 ▸ Use ARC ▸ Use properties

  37. Core Data

  38. What prevents me from using Core Data at this point

    is my concern for scalability and performance. It’s possible I’m just being thick-headed. — Brent Simmons, 27 Sep 2013
  39. So last weekend I switched from SQLite/FMDB to Core Data.

    This may come as a surprise. — Brent Simmons, 05 Oct 2013
  40. None
  41. Core Data ▸ Relationships ▸ Batching ▸ NSFetchedResultsControlle r ▸

    Speed of use
  42. Code style

  43. My model was the NSURLConnectionDelegate Model should not know about

    the webservice
  44. Using NSDictionary everywhere Create value objects

  45. Value Objects @interface Person : NSObject @property (nonatomic,copy,readonly) NSString* name;

    @property (nonatomic,strong,readonly) NSDate* birthDate; @property (nonatomic,readonly) NSUInteger numberOfKids; - (instancetype)initWithName:(NSString*)name birthDate:(NSDate*)birthDate numberOfKids:(NSUInteger)numberOfKids; @end
  46. Immutable Objects Use lots of them.

  47. Deep code paths - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { if (alertState

    == submitScore && game.score > 0) { // 20 lines if (result != nil && [resultKeys containsObject:@"position"] && [resultKeys containsObject:@"neededPoints"] && [resultKeys containsObject:@"deviceHighscore"] && [resultKeys containsObject:@"personalHighscore"]) { // 10 lines if (position == 1) {
  48. Deep code paths Pull out things into separate, well-named methods

  49. Building everything in code Use Interface Builder

  50. Writing fast code Write clear code, only optimize after measuring.

  51. None
  52. Tips and Tricks

  53. Initializers [[HiscoresViewController alloc] initWithNibName:@"HiscoresView" bundle:nil]

  54. Initializers // In HiscoresViewController.m - (id)init { self = [super

    initWithNibName:@"HiscoresView" bundle:nil]; if (self) { } return self; }
  55. Use constants if (buttonIndex == 0)

  56. Use constants if (buttonIndex == StartButton)

  57. Pull out variable names if ([game state] == running ||

    self.trainingMode)
  58. Pull out variable names BOOL shouldPauseGame = [game state] ==

    running || self.trainingMode; if (shouldPauseGame)
  59. Pulling out protocols For example: UITableViewDataSource

  60. @interface FetchedResultsControllerDataSource : NSObject <UITableViewDataSource, NSFetchedResultsControllerDelegate>

  61. - (NSInteger)numberOfSectionsInTableView:(UITableView*)t { return self.fetchedResultsController.sections.count; }

  62. - (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)sectionIndex { id<NSFetchedResultsSectionInfo> section; section = self.frc.sections[sectionIndex]; return

    section.numberOfObjects; }
  63. - (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)ip { id object = [self objectAtIndexPath:indexPath]; id

    cell = [tableView dequeueReusableCellWithIdentifier:ruI forIndexPath:ip]; [self.delegate configureCell:cell withObject:object]; return cell; }
  64. Write small files I aim for a 100 line limit

  65. Write small files 154 ./ViewControllers/THUserPrioritiesViewController.m 154 ./ViewControllers/THZoomingNavigationController.m 155 ./Extensions/NSArray+Extensions.m 155

    ./Extensions/UIView+Extensions.m 168 ./Controllers/THPriorityTimelineCollectionController.m 179 ./Controllers/THUserScreenInstancesController.m 183 ./ViewControllers/THRootViewController.m 183 ./ViewControllers/THScreenInstanceViewController.m 185 ./Model/User+Extensions.m 192 ./ViewControllers/THEditPriorityViewController.m 221 ./ViewControllers/THScreeningBarViewController.m 243 ./Views/THTimeLineView.m 263 ./ViewControllers/THCardsViewController.m 279 ./Views/THSkillboxView.m
  66. Write small files find . -name "*.m" -exec wc -l

    "{}" \; | sort -n
  67. Keep your view controllers light This is the least reusable

    code you'll write
  68. Use protocols instead of inheritance

  69. None
  70. The Bad

  71. None
  72. None
  73. About me ▸ @chriseidhof ▸ http://www.objc.io ▸ http://chris.eidhof.nl

  74. Questions?