Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥
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
2k
GraphQL放談
cockscomb
4
2.1k
GraphQL Highway
cockscomb
28
8.6k
吉田を支える技術
cockscomb
0
2.4k
コーポレートサイトを静的化してAmplify Consoleにデプロイする
cockscomb
0
3.4k
ユーザインターフェイスと非同期処理
cockscomb
5
2k
GUIアプリケーションの構造と設計
cockscomb
10
10k
イカリング2におけるシングルページアプリケーション
cockscomb
2
7.6k
あなたの知らない UIKit の世界 — UITableView に UITextView を置きたい
cockscomb
1
7.5k
Other Decks in Programming
See All in Programming
AI時代もSEOを頑張っている話
shirahama_x
0
260
テストやOSS開発に役立つSetup PHP Action
matsuo_atsushi
0
140
これだけで丸わかり!LangChain v1.0 アップデートまとめ
os1ma
6
1.4k
認証・認可の基本を学ぼう前編
kouyuume
0
180
【Streamlit x Snowflake】データ基盤からアプリ開発・AI活用まで、すべてをSnowflake内で実現
ayumu_yamaguchi
1
110
【CA.ai #3】Google ADKを活用したAI Agent開発と運用知見
harappa80
0
290
ID管理機能開発の裏側 高速にSaaS連携を実現したチームのAI活用編
atzzcokek
0
200
dnx で実行できるコマンド、作ってみました
tomohisa
0
140
30分でDoctrineの仕組みと使い方を完全にマスターする / phpconkagawa 2025 Doctrine
ttskch
3
770
ViewファーストなRailsアプリ開発のたのしさ
sugiwe
0
410
Full-Cycle Reactivity in Angular: SignalStore mit Signal Forms und Resources
manfredsteyer
PRO
0
110
配送計画の均等化機能を提供する取り組みについて(⽩⾦鉱業 Meetup Vol.21@六本⽊(数理最適化編))
izu_nori
0
140
Featured
See All Featured
Designing Experiences People Love
moore
142
24k
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
380
Making Projects Easy
brettharned
120
6.5k
Learning to Love Humans: Emotional Interface Design
aarron
274
41k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
21
1.3k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
253
22k
Building Better People: How to give real-time feedback that sticks.
wjessup
370
20k
Site-Speed That Sticks
csswizardry
13
990
The Language of Interfaces
destraynor
162
25k
A Modern Web Designer's Workflow
chriscoyier
697
190k
GraphQLとの向き合い方2022年版
quramy
50
14k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
37
2.6k
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