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
19k
はてなにおけるモダン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.9k
GraphQL放談
cockscomb
4
2k
GraphQL Highway
cockscomb
28
8.6k
吉田を支える技術
cockscomb
0
2.4k
コーポレートサイトを静的化してAmplify Consoleにデプロイする
cockscomb
0
3.4k
ユーザインターフェイスと非同期処理
cockscomb
5
1.9k
GUIアプリケーションの構造と設計
cockscomb
10
10k
イカリング2におけるシングルページアプリケーション
cockscomb
2
7.6k
あなたの知らない UIKit の世界 — UITableView に UITextView を置きたい
cockscomb
1
7.5k
Other Decks in Programming
See All in Programming
そのpreloadは必要?見過ごされたpreloadが技術的負債として爆発した日
mugitti9
2
2.9k
Go言語の特性を活かした公式MCP SDKの設計
hond0413
1
150
monorepo の Go テストをはやくした〜い!~最小の依存解決への道のり~ / faster-testing-of-monorepos
convto
2
350
Catch Up: Go Style Guide Update
andpad
0
150
プログラマのための作曲入門
cheebow
0
530
iOSエンジニア向けの英語学習アプリを作る!
yukawashouhei
0
180
ソフトウェア設計の実践的な考え方
masuda220
PRO
3
440
GraphQL×Railsアプリのデータベース負荷分散 - 月間3,000万人利用サービスを無停止で
koxya
1
1k
いま中途半端なSwift 6対応をするより、Default ActorやApproachable Concurrencyを有効にしてからでいいんじゃない?
yimajo
2
330
Web フロントエンドエンジニアに開かれる AI Agent プロダクト開発 - Vercel AI SDK を観察して AI Agent と仲良くなろう! #FEC余熱NIGHT
izumin5210
3
370
プロダクト開発をAI 1stに変革する〜SaaS is dead時代で生き残るために〜 / AI 1st Product Development
kobakei
0
480
CI_CD「健康診断」のススメ。現場でのボトルネック特定から、健康診断を通じた組織的な改善手法
teamlab
PRO
0
170
Featured
See All Featured
Optimising Largest Contentful Paint
csswizardry
37
3.4k
KATA
mclloyd
32
15k
Bootstrapping a Software Product
garrettdimon
PRO
307
110k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.5k
A designer walks into a library…
pauljervisheath
209
24k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
114
20k
RailsConf 2023
tenderlove
30
1.2k
Site-Speed That Sticks
csswizardry
11
880
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
32
2.2k
Imperfection Machines: The Place of Print at Facebook
scottboms
269
13k
Docker and Python
trallard
46
3.6k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
22k
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