Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Diet View Controllers
Search
Gustavo Barbosa
November 05, 2014
Technology
0
220
Diet View Controllers
Cocoatalk given at CocoaHeads - Barra da Tijuca
Gustavo Barbosa
November 05, 2014
Tweet
Share
More Decks by Gustavo Barbosa
See All by Gustavo Barbosa
Arquitetura de Apps em Cenários Offline
barbosa
2
340
CocoaPods: The dependency manager for Objective-C projects
barbosa
0
59
Parse
barbosa
0
130
Introduction to Object
barbosa
0
56
git-flow: a successful branching model
barbosa
4
94
Git: The fast version control system
barbosa
0
240
Clean Code
barbosa
0
130
Other Decks in Technology
See All in Technology
AWSが好きすぎて、41歳でエンジニアになり、AAIを経由してAWSパートナー企業に入った話
yama3133
2
230
今日から使える AWS Step Functions 小技集 / AWS Step Functions Tips
kinunori
2
220
Design and implementation of "Markdown to Google Slides" / phpconfuk 2025
k1low
1
170
어떤 개발자가 되고 싶은가?
arawn
1
450
戦えるAIエージェントの作り方
iwiwi
22
11k
AIで急増した生産「量」の荒波をCodeRabbitで乗りこなそう
moongift
PRO
0
560
プロダクト開発と社内データ活用での、BI×AIの現在地 / Data_Findy
sansan_randd
1
830
AIでデータ活用を加速させる取り組み / Leveraging AI to accelerate data utilization
okiyuki99
6
1.8k
GPUをつかってベクトル検索を扱う手法のお話し~NVIDIA cuVSとCAGRA~
fshuhe
0
390
[Journal club] Thinking in Space: How Multimodal Large Language Models See, Remember, and Recall Spaces
keio_smilab
PRO
0
120
Playwrightで始めるUI自動テスト入門
devops_vtj
0
170
ソフトウェアエンジニアとデータエンジニアの違い・キャリアチェンジ
mtpooh
1
330
Featured
See All Featured
Testing 201, or: Great Expectations
jmmastey
46
7.7k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
34
2.5k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
10
910
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
10
640
Measuring & Analyzing Core Web Vitals
bluesmoon
9
650
Context Engineering - Making Every Token Count
addyosmani
8
330
Thoughts on Productivity
jonyablonski
72
4.9k
RailsConf 2023
tenderlove
30
1.3k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
359
30k
The Illustrated Children's Guide to Kubernetes
chrisshort
51
51k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
285
14k
Build your cross-platform service in a week with App Engine
jlugia
234
18k
Transcript
Diet View Controllers
We need to talk...
None
MODEL VIEW CONTROLLERS
MASSIVE VIEW CONTROLLERS
MISUSED VIEW CONTROLLERS
MISTREATED VIEW CONTROLLERS
Um belo dia...
XCODE > NEW > PROJECT
Eu preciso de... UM dataSource PARA MINHA UITableView
Eu preciso de... UNS dados VINDOS DO servidor
Eu preciso de... ALGO PARA validar MEUS UITextFields
Eu preciso de... um CLLocationManagerDelegate
Eu preciso de... uma última coisinha BEM PEQUENA
None
THE 900-LINE PROBLEM
"Using #pragma mark is indicative of a failure to adhere
to the Single Responsibility Principle and is a signpost for poor code." -- Brad Grzesiak, Bendyworks
None
1. DATASOURCES E DELEGATES
- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section { return photos.count; } - (UITableViewCell *)tableView:(UITableView
*)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { PhotoCell *cell = [tableView dequeueReusableCellWithIdentifier:PhotoCellIdentifier forIndexPath:indexPath]; Photo *photo = [self photoAtIndexPath:indexPath]; cell.label.text = photo.name; return cell; } - (Photo *)photoAtIndexPath:(NSIndexPath *)indexPath { return photos[indexPath.row]; }
@interface ArrayDataSource <UITableViewDataSource> @property (nonatomic, strong) NSArray *items; @property (nonatomic,
strong) NSString *cellIdentifier; @property (nonatomic, copy) void(^cellConfigurationBlock)(id cell, id item); - (instancetype)initWithItems:(NSArray *)items cellIdentifier:(NSString *)cellIdentifier cellConfigurationBlock:(void(^)(id cell, id item))cellConfigurationBlock; @end
@implementation ArrayDataSource - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.items.count; }
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { id cell = [tableView dequeueReusableCellWithIdentifier:self.cellIdentifier forIndexPath:indexPath]; if (self.cellConfigurationBlock) { id item = [self itemAtIndexPath:indexPath]; self.cellConfigurationBlock(cell, item); } return cell; } - (id)itemAtIndexPath:(NSIndexPath *)indexPath { return self.items[indexPath.row]; } @end
configurationBlock = ^(PhotoCell *cell, Photo *item) { cell.label.text = item.name;
}; _dataSource = [[ArrayDataSource alloc] initWithItems:self.photos cellIdentifier:@"PhotoCellIdentifier" cellConfigurationBlock:configurationBlock]; _tableView.dataSource = _dataSource;
2. LÓGICAS DE DOMÍNIO
VIEWCONTROLLER - (Folder *)getRootFolder:(Folder *)folder { if (folder.parent == nil)
return folder; return [self getRootFolder:folder]; }
FOLDER+EXTENSIONS - (Folder *)rootFolder { if (self.parent == nil) return
self; return [self rootFolder]; }
FOLDER @property (nonatomic, readonly) Folder *rootFolder; - (Folder *)rootFolder {
if (self.parent == nil) return self; return self.parent.rootFolder; }
3. LÓGICAS DE SERVIÇO
VIEWCONTROLLER AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; [manager GET:@"http://example.com/profiles.json" parameters:nil success:^(AFHTTPRequestOperation
*operation, id responseObject) { NSLog(@"JSON: %@", responseObject); } failure:^(AFHTTPRequestOperation *operation, NSError *error) { NSLog(@"Error: %@", error); }];
STORES OU REPOSITORIES
CANDIDATOS À STORE WEB SERVICES DATABASES FILESYSTEM LOCATION/MOTION SERVICES CAMERA
PROFILE STORE - (void)fetchAllProfilesWithCallback:(void(^)(NSArray *, NSError *))callbackBlock { [_manager GET:[self
urlForPath:@"profiles.json"] parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) { NSArray *objects = // serialize from responseObject if (callbackBlock) callbackBlock(objects, nil); } failure:^(AFHTTPRequestOperation *operation, NSError *error) { if (callbackBlock) callbackBlock(@[], error); }]; }
PROFILE STORE [[ProfileStore store] fetchAllProfilesWithCallback:^(NSArray *objects, NSError *error){ [_loadingView removeFromSuperview];
if (error) { // log or show error message } else { _tableView.dataSource.items = objects; [_tableView reloadData]; } }];
PROFILE+REPOSITORY + (void)allProfilesWithCallback:(void(^)(NSArray *, NSError *)); + (void)profileForId:(NSUInteger)identifier callback:(void(^)(Profile *,
NSError *)); - (void)deleteWithCallback:(void(^)(NSError *)); - (void)saveWithCallback:(void(^)(NSError *));
4. HIERARQUIA DE VIEWS
None
+ (UIAppearance *)appearance; [UIActivityIndicatorView appearance].color = [UIColor blueColor];
@implementation MyCustomView - (void)awakeFromNib { [super awakeFromNib]; // Customization self.layer.cornerRadius
= 3.0f; self.layer.borderWidth = 1.0f; self.layer.borderColor = [UIColor yellowColor].CGColor; self.layer.masksToBounds = YES; } @end
OBJECTIVE-C IB_DESIGNABLE @interface EllipseView : UIView @property (nonatomic, retain) IBInspectable
UIColor *fillColor; @end
SWIFT @IBDesignable class StarView : UIView { @IBInspectable var starColor:UIColor
required init(coder aDecoder: NSCoder) { starColor = UIColor.yellowColor(); super.init(coder: aDecoder) } override init(frame: CGRect) { starColor = UIColor.yellowColor(); super.init(frame: frame) } }
5. CHILD VIEW CONTROLLERS
None
None
[self addChildViewController:otherViewController]
VIEWCONTROLLER LIFECYCLE - (void)viewDidLoad; - (void)viewWillAppear:(BOOL)animated; - (void)viewDidAppear:(BOOL)animated; - (void)viewWillDisappear:(BOOL)animated;
- (void)viewDidDisappear:(BOOL)animated;
ORIENTATION CHANGES - (void)willRotateToInterfaceOrientation:duration:
STATUS BAR - (UIViewController *)childViewControllerForStatusBarHidden; - (UIViewController *)childViewControllerForStatusBarStyle;
6. INTENTIONS
VIEWCONTROLLER @interface ViewController() <UITextFieldDelegate> @property (nonatomic, weak) IBOutlet UITextField *textField;
@end
VIEWCONTROLLER - (void)viewDidLoad { [super viewDidLoad]; self.person = [[Person alloc]
init]; self.person.name = @"John"; [self updateTextField]; } - (void)updateTextField { self.textField.text = self.person.name; }
VIEWCONTROLLER - (IBAction)reverse:(id)sender { self.person.name = self.textField.text.reversedString; [self updateTextField]; }
- (IBAction)uppercase:(id)sender { self.person.name = self.textField.text.uppercaseString; [self updateTextField]; }
VIEWCONTROLLER - (BOOL)textFieldShouldReturn:(UITextField *)textField { [textField resignFirstResponder]; return NO; }
INTENTION @implementation DismissOnEnterIntention - (BOOL)textFieldShouldReturn:(UITextField *)textField { [textField resignFirstResponder]; return
NO; } @end
INTENTION @interface PersonContainer : NSObject @property (nonatomic, strong) Person *person;
@end @interface UppercaseIntention : NSObject @property (nonatomic, weak) IBOutlet UITextField *textField; @property (nonatomic, weak) IBOutlet PersonContainer *personContainer; @end
@implementation UppercaseIntention - (IBAction)uppercase:(id)sender { self.person.name = self.textField.text.uppercaseString; [self updateTextField];
} - (void)updateTextField { self.textField.text = self.personContainer.person.name; } @end
None
OUTRAS LEITURAS ▸ https://bendyworks.com/single- responsibility-principle-ios/ ▸ http://jaythrash.com/blog/2014/08/25/ building-better-viewcontrollers/ ▸ http://chris.eidhof.nl/posts/intentions.html
▸ http://www.objc.io/issue-1/lighter-view- controllers.html
@GUSTAVOCSB