Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
The Evolution of a Cocoa Programmer
Search
Chris Eidhof | @chriseidhof
January 11, 2014
Technology
790
8
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
The Evolution of a Cocoa Programmer
Chris Eidhof | @chriseidhof
January 11, 2014
More Decks by Chris Eidhof | @chriseidhof
See All by Chris Eidhof | @chriseidhof
Dutch FP Day 2015
chriseidhof
2
410
Tiny Networking in Swift
chriseidhof
2
19k
Functional Swift - Brooklyn
chriseidhof
3
1.3k
Functional Swift - SF
chriseidhof
6
26k
Functional Swift
chriseidhof
6
1.3k
Functional Swift
chriseidhof
1
180
Functional Programming in Swift
chriseidhof
40
19k
Lighter View Controllers
chriseidhof
4
220
Parsing with Blocks
chriseidhof
2
260
Other Decks in Technology
See All in Technology
ASTを使って影響範囲を特定する
nealle
0
180
Gitは怖い?共有ワークスペースから始めるSnowflakeチーム開発
coco_se
0
190
Amazon Quick on DesktopがIAM Identity Centerで動かない理由
yukiogawa
0
180
OpenTelemetry eBPF Instrumentationの舞台裏 / Behind the Scenes of OpenTelemetry eBPF Instrumentation
ymotongpoo
4
1.2k
新機種発売前に見直そう!端末移行で再ログインが要るアプリ・要らないアプリは何が違うのか 〜シームレスに再開できる設計と実装〜
zozotech
PRO
0
130
2026/09/10 Spring Bootから Jakarta EE/MicroProfileへの移行
megascus
0
350
Deployment の 先にある AI Agent 基盤 - kagent vNext、Agent Substrate、Hermes から読み解く Agent Runtime の現在地 / k8s-matsuri-2-ai-agent-platform-amsy810
masayaaoyama
3
180
コーディングエージェントでM5Stack系の開発を少し試した時の話 / M5 Japan Tour 2026 Autumn 東京
you
PRO
0
190
目の前の楽しいが人生を変える - コミュニティの螺旋の歩き方と楽しむコツ / change your life
soudai
PRO
4
540
フルカイテン株式会社 エンジニア向け採用資料
fullkaiten
0
12k
ペアプロの価値はコードを書くことだけじゃない
codmoninc
PRO
0
210
Slack上でインフラをトラブルシュートする! Agentic Platform Engineeringの第一歩
teru0x1
4
1.5k
Featured
See All Featured
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.8k
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
490
Color Theory Basics | Prateek | Gurzu
gurzu
0
460
Code Reviewing Like a Champion
maltzj
528
40k
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
280
Dominate Local Search Results - an insider guide to GBP, reviews, and Local SEO
greggifford
PRO
0
330
How to Think Like a Performance Engineer
csswizardry
28
2.8k
Exploring anti-patterns in Rails
aemeredith
3
500
Google's AI Overviews - The New Search
badams
0
1.6k
How to build a perfect <img>
jonoalderson
1
6k
Technical Leadership for Architectural Decision Making
baasie
3
560
Are puppies a ranking factor?
jonoalderson
2
3.9k
Transcript
The evolution of a Cocoa Programmer Chris Eidhof Mobile Central
Europe 2014
Hashtags #mceconf #mce-evolution
None
None
commit c416c1d259bddaa74833e6df5acd770f85622293 Author: Chris Eidhof <
[email protected]
> Date: Wed Jan 7
11:54:34 2009 +0100 Empty project
I thought I was a pretty good programmer
I knew PHP, Ruby and Haskell
How hard can it be?
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; }
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;
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;
There's more
//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 {
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];
How did I get better?
If there's only one thing you'll remember Write code for
the person after you
EDD Embarassment-Driven Development
—Write a lot of code —Work with other people —Write
articles —Read books and code
Write a lot of code —Lots of production code —Lots
of throwaway code
None
Collaborate —With people who are better than you —Or who
aren't better than you
Write Forces you to think.
Learn your frameworks —Use Core Data —Use UITableViewController —Use NSURLSession
Absolute Knowledge
2014 1986 1988 1990 1992 1994 1996 1998 2000 2002
2004 2006 2008 2010 2012 1 2 3 4 5 Time How much I know
Perceived Knowledge
2014 1986 1988 1990 1992 1994 1996 1998 2000 2002
2004 2006 2008 2010 2012 1 2 3 4 5 Time How much I know
Strive to become better
Ship
Writing better code —Quick wins —Value Objects —Lighter View Controllers
Quick Wins
I used to do this: if (buttonIndex == 0)
I used to do this: if (buttonIndex == 0) instead,
now I write if (buttonIndex == StartButton)
I used to write this: if ([game state] == running
|| self.trainingMode)
I used to write this: if ([game state] == running
|| self.trainingMode) Now I write this: BOOL shouldPauseGame = game.state == running || self.trainingMode; if (shouldPauseGame)
Write small files I aim for 100-150 lines
Write small files 325 ./THStyleSheet.m 279 THSkillboxView.m 263 THCardsViewController.m 243
THTimeLineView.m 221 THScreeningBarViewController.m 192 THEditPriorityViewController.m 185 User+Extensions.m 183 THScreenInstanceViewController.m 183 THRootViewController.m 179 THUserScreenInstancesController.m 168 THPriorityTimelineCollectionController.m 155 UIView+Extensions.m 155 NSArray+Extensions.m 154 THZoomingNavigationController.m
Write small files find . -name "*.m" -exec wc -l
"{}" \; | sort -n
Use protocols instead of class inheritance They are much more
flexible and make for clearer code.
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
Deep code paths Pull out things into separate, well-named methods
Don't write fast code Optimize for readability
Really learn Interface Builder This makes prototyping much faster
Learn your frameworks
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
So last weekend I switched from SQLite/FMDB to Core Data.
This may come as a surprise. — Brent Simmons, 05 Oct 2013
Core Data —Relationships —Batching —NSFetchedResultsController —Speed of use
Value Objects
I used NSDictionary for everything NSDate* birthDate = [NSDate dateWithTimeIntervalSince1970:131855*3600];
NSDictionary* person = @{ @"name": @"Chris", @"birthdate": birthDate, @"numberOfKids": @0 };
Problems with NSDictionary —It's not typechecked —It might be mutated
A first step @interface Person : NSObject @property (nonatomic,copy) NSString*
name; @property (nonatomic) NSDate* birthDate; @property (nonatomic) NSUInteger numberOfKids; @end
Mutation Sometimes mutation is very handy. Most of the times
it will bite you.
@interface Person : NSObject @property (nonatomic,readonly) NSString* name; @property (nonatomic,readonly)
NSDate* birthDate; @property (nonatomic,readonly) NSUInteger numberOfKids; - (instancetype) initWithName:(NSString*)name birthDate:(NSDate*)birthDate numberOfKids:(NSUInteger)numberOfKids; @end
Value Objects —Use lots of them. —Make them immutable.
Lighter View Controllers
Keep your view controllers light This is the least reusable
code you'll write
What can you do? —Smarter views —Smarter models —Use view
controller transitions —Use categories to populate views —Pull out protocols
Use categories to populate views - (UITableViewCell*)tableView:(UITableView*)tv cellForRowAtIndexPath:(NSIndexPath*)ip { User
*user = [self userAtIndexPath:ip]; MyCell *cell = [tv dequeueReusableCellWithIdentifier:ruI forIndexPath:ip]; cell.textLabel.text = user.name; cell.imageView.image = user.avatar; .... }
Use categories to populate views @interface MyCell (ConfigureForUser) - (void)configureForUser:(User
*)user; @end
Use categories to populate views - (void)configureForUser:(User *)user { cell.textLabel.text
= user.name; cell.imageView.image = user.avatar; ... }
Use categories to populate views —Your view controller is a
bit simpler —Your population code can be reused ... —But now your view knows about your model. Sort of.
Pulling out protocols
Pulling out protocols For example: UITableViewDataSource
Creating a separate data source object @interface FetchedResultsControllerDataSource : NSObject
<UITableViewDataSource, NSFetchedResultsControllerDelegate>
Creating a separate data source object - (NSInteger)numberOfSectionsInTableView: (UITableView*)t {
return self.fetchedResultsController.sections.count; }
Creating a separate data source object - (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)sectionIndex {
id<NSFetchedResultsSectionInfo> section; section = self.frc.sections[sectionIndex]; return section.numberOfObjects; }
Creating a separate data source object Working with the delegate
- (UITableViewCell*)tableView:(UITableView*)tv cellForRowAtIndexPath:(NSIndexPath*)ip { id object = [self objectAtIndexPath:indexPath]; id cell = [tv dequeueReusableCellWithIdentifier:ruI forIndexPath:ip]; [self.delegate configureCell:cell withObject:object]; return cell; }
Advantages of a separate data source —Lighter view controller —Testable
—Reusable And you can do this for other protocols, too
A separate data source —NSArrayDataSource —NSFRCollectionViewController —...
So.... —Write for the person after you —Know your frameworks
—Keep your view controllers light
Commercial Break
None
Questions? @chriseidhof