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
はてなにおけるモダンiOSアプリ開発入門
Search
cockscomb
November 27, 2013
Programming
29
18k
はてなにおけるモダンiOSアプリ開発入門
Hatena Engineer Seminar #2 で発表した際のスライドです。
はてなにおけるiOSアプリ開発を説明しました。
cockscomb
November 27, 2013
Tweet
Share
More Decks by cockscomb
See All by cockscomb
jq at the Shortcuts
cockscomb
1
1.8k
GraphQL放談
cockscomb
4
1.9k
GraphQL Highway
cockscomb
28
8.3k
吉田を支える技術
cockscomb
0
2.2k
コーポレートサイトを静的化してAmplify Consoleにデプロイする
cockscomb
0
3.4k
ユーザインターフェイスと非同期処理
cockscomb
5
1.8k
GUIアプリケーションの構造と設計
cockscomb
10
10k
イカリング2におけるシングルページアプリケーション
cockscomb
2
7.4k
あなたの知らない UIKit の世界 — UITableView に UITextView を置きたい
cockscomb
1
7.4k
Other Decks in Programming
See All in Programming
LINE messaging APIを使ってGoogleカレンダーと連携した予約ツールを作ってみた
takumakoike
0
120
Boost Performance and Developer Productivity with Jakarta EE 11
ivargrimstad
0
900
新宿駅構内を三人称視点で探索してみる
satoshi7190
2
120
sappoRo.R #12 初心者セッション
kosugitti
0
280
PHPカンファレンス名古屋2025 タスク分解の試行錯誤〜レビュー負荷を下げるために〜
soichi
1
710
Unity Android XR入門
sakutama_11
0
180
AIプログラミング雑キャッチアップ
yuheinakasaka
19
4.7k
CSS Linter による Baseline サポートの仕組み
ryo_manba
1
150
Introduction to kotlinx.rpc
arawn
0
770
dbt Pythonモデルで実現するSnowflake活用術
trsnium
0
260
CI改善もDatadogとともに
taumu
0
200
技術を改善し続ける
gumioji
0
130
Featured
See All Featured
Automating Front-end Workflow
addyosmani
1368
200k
Making Projects Easy
brettharned
116
6k
Side Projects
sachag
452
42k
Fashionably flexible responsive web design (full day workshop)
malarkey
406
66k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
330
21k
Designing on Purpose - Digital PM Summit 2013
jponch
117
7.1k
VelocityConf: Rendering Performance Case Studies
addyosmani
328
24k
Gamification - CAS2011
davidbonilla
80
5.2k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
40
2k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
27
1.6k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
46
2.3k
Stop Working from a Prison Cell
hatefulcrawdad
267
20k
Transcript
None
ͯͳʹ͓͚Δ ϞμϯiOSΞϓϦ։ൃೖ Hatena Engineer Seminar #2
cockscomb
גࣜձࣾͯͳ ΞϓϦέʔγϣϯΤϯδχΞ ͯͳϒϩάνʔϜ/ͯͳεϖʔενʔϜ ͯͳαϚʔΠϯλʔϯ2013ࢀՃޙ͙͢ʹೖࣾ cockscomb
ͯͳͷΞϓϦ
None
None
None
None
ͯͳϒοΫϚʔΫ iOS SDK
ΞδΣϯμ 1. ͯͳʹ͓͚ΔΞϓϦ։ൃ 2. ͯͳαϚʔΠϯλʔϯ2013 3. ͯͳͷiOS։ൃΛࢧ͑Δٕज़
ͯͳʹ͓͚Δ ΞϓϦ։ൃ
։ൃ HTML5 Titanium RubyMotion ωΠςΟϒ + WebView
ΞϓϦͷํੑΛܾఆ ϖʔύʔϓϩτλΠϐϯά Ϣʔβʔςετ ࣾͷiOSϢʔβʔʹTestFlight ΞϓϦϦϦʔε ϢʔβʔͷಉҙΛಘͯτϥοΩϯά
ͯͳϒϩάΞϓϦ ͔ͬ͠ΓͱϒϩάΛॻ͚Δ͜ͱ ॻ͖͍͢͜ͱ Ͳ͜ʹ͍ͯॻ͚Δ͜ͱ ϑΟʔυόοΫ͕ಘΒΕΔ͜ͱ
None
None
ܭଌ
Web APIΛར༻͢ΔiOSΞϓϦ։ൃ ͯͳαϚʔΠϯλʔϯγοϓ2013
ͯͳΠϯλʔϯ2013 ͯͳαϚʔΠϯλʔϯ ϨϙʔταΠτ ͯͳڭՊॻ J04ߨٛαϯϓϧίʔυ https://github.com/hatena/
–id:murakaming lJ04ଆͬ͟ͱݟ͚ͨͲɺ͜͏͍͏ حྷͳίʔυ͕খ͍͞αϯϓϧͰͳ͘ Ұࣜἧ͍ͬͯΔͷຊʹوॏͩ͠ ༗Γ͗͢Δɻz
–id:griffin-stewie lͦΕͳΓʹ࣮ઓܦݧ͕͋ΔਓͰ ͬͯͳͦ͞͏ͩͬͨΓΒͳͦ͏ͳ͜ͱΛ αϥοͱݟͤͯ͘Ε͍ͯΔz
࣮ફతͳαϯϓϧίʔυ CocoaPods AFNetworking UIStoryboard Auto Layout NSLayoutConstraint Key Value Observation
blocks UITableViewController NSNotification Center isEqual: overriding appledoc …
ͯͳͷiOS։ൃΛ ࢧ͑Δٕज़
CocoaPods platform :ios, '7.0' ! pod 'AFNetworking' pod install
UIStoryboard
- (IBAction)newBookmark:(id)sender { IBKMBookmarkViewController *bookmarkViewController = [[IBKMBookmarkViewController alloc] init]; [self.navigationController
pushViewController:bookmarkViewController animated:YES]; } Before After
Auto Layout
None
@property (weak, nonatomic) IBOutlet UITextView *textView; ! ! ! -
(void)keyboardWillChangeFrame:(NSNotification *)notification { CGRect keyboardRect = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue]; keyboardRect = [self.view convertRect:keyboardRect fromView:nil]; double animationDuration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; ! CGFloat keyboardHeight = self.view.bounds.size.height - keyboardRect.origin.y; CGRect newRect = self.view.bounds; newRect.size.height -= keyboardHeight; ! [UIView animateWithDuration:animationDuration animations:^{ self.textView.frame = newRect; }]; } Before
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *keyboardHeight; ! ! ! -
(void)keyboardWillChangeFrame:(NSNotification *)notification { ... ! CGFloat keyboardHeight = self.view.bounds.size.height - keyboardRect.origin.y; self.keyboardHeight.constant = -keyboardHeight; ! [UIView animateWithDuration:animationDuration animations:^{ [self.view layoutIfNeeded]; }]; } After
Key Value Observation
ϒοΫϚʔΫҰཡ BookmarkManager - (NSArray *)bookmarks TableViewController ࢹ ௨ ߋ৽
TableViewController [[IBKMBookmarkManager sharedManager] reloadBookmarksWithBlock:^(NSError *error) { if (error) { NSLog(@"Error:
%@", error); } [self.tableView reloadData]; }]; खͰஸೡʹUITableViewʹөͤ͞ΔͷΛΊ͍ͨ
TableViewController [[IBKMBookmarkManager sharedManager] reloadBookmarksWithBlock:^(NSError *error) { if (error) { NSLog(@"Error:
%@", error); } }];
Key Value Observation [[IBKMBookmarkManager sharedManager] addObserver:self forKeyPath:@"bookmarks" options:NSKeyValueObservingOptionNew context:nil];
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if
(object == [IBKMBookmarkManager sharedManager] && [keyPath isEqualToString:@"bookmarks"]) { NSIndexSet *indexSet = change[NSKeyValueChangeIndexesKey]; NSKeyValueChange changeKind = (NSKeyValueChange)[change[NSKeyValueChangeKindKey] integerValue]; ! NSMutableArray *indexPaths = [NSMutableArray array]; [indexSet enumerateIndexesUsingBlock:^(NSUInteger index, BOOL *stop) { [indexPaths addObject:[NSIndexPath indexPathForRow:index inSection:0]]; }]; ! [self.tableView beginUpdates]; if (changeKind == NSKeyValueChangeInsertion) { [self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic]; } else if (changeKind == NSKeyValueChangeRemoval) { [self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic]; } else if (changeKind == NSKeyValueChangeReplacement) { [self.tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic]; } [self.tableView endUpdates]; } }
IBKMBookmarkManager [[self mutableArrayValueForKey:@"bookmarks"] insertObjects:newBookmarks atIndexes:[NSIndexSet indexSetWithIndexesInRange: NSMakeRange(0, newBookmarks.count)]]; self.bookmarksΛૢ࡞ͤͣproxyΛܦ༝͢Δ
ϒοΫϚʔΫҰཡ BookmarkManager - (NSArray)bookmarks TableViewController ࢹ ௨ ߋ৽
ςετ
Test Frameworks OCUnit/XCTest Kiwi BDD. ςετΛॻ͖͘͢͢ΔͨΊʹ͍ͬͯΔ Nocilla ωοτϫʔΫStub UIAutomation ౷߹ςετʹΘΕ͍ͯΔ.
KIF͍͖͍ͬͯͨ
context(@"Fetching service data", ^{ it(@"should receive data within one second",
^{ __block NSData *fetchData = nil; NSURLRequest *request = [NSURLRequest requestWithURL: [NSURL URLWithString:@"http://www.hatena.ne.jp/"]]; ! [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { fetchData = data; } ]; [[expectFutureValue(fetchData) shouldEventually] beNonNil]; }); });
stubRequest(@"GET", @"http://www.hatena.ne.jp/"). andReturn(200);
ͯͳ εϚʔτϑΥϯॏࢹ εϚʔτϑΥϯͷτϥϑΟοΫ͕ແࢹͰ͖ͳ͍ େ͖ͳࡋྔ اը͔Βઃܭɺεϐʔυײ͋Δ։ൃ ։ൃख๏ʑมԽ ΤϯδχΞͷࣗओੑͰͲΜͲΜม͍͚͑ͯΔ
ੵۃ࠾༻த http://www.hatena.ne.jp/company/staff
None