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
5分で学ぶ差分更新とRxDataSources
Search
Yuji Hato
April 10, 2018
Technology
0
260
5分で学ぶ差分更新とRxDataSources
Learn in 5 minutes
Incremental updates and RxDataSources
Yuji Hato
April 10, 2018
Tweet
Share
More Decks by Yuji Hato
See All by Yuji Hato
ABEMAモバイルアプリ開発のDevOps戦略
dekatotoro
1
590
Multiplatform Engineering Roadmap for the Future
dekatotoro
1
130
Introduction to RIBs
dekatotoro
5
1.3k
継続的な開発スタイル 「AbemaTV iOSアプリを週一で リリースしている話」
dekatotoro
6
3.8k
iOS Adaptive UI - 解像度の異なるデバイスや画面の向きに対応する 最適なレイアウトへ -
dekatotoro
0
340
動画アプリをなめらかに動かす技術 - iOS -
dekatotoro
0
310
AbemaTV モバイルアプリの開発体制と 開発プロセスの話
dekatotoro
0
240
Apple TV - tvOS入門 -
dekatotoro
0
110
AbemaTV on Apple TV
dekatotoro
0
36
Other Decks in Technology
See All in Technology
コンテンツを支える 若手ゲームクリエイターの アートディレクションの事例紹介 / cagamefi-game
cyberagentdevelopers
PRO
1
130
pandasはPolarsに性能面で追いつき追い越せるのか
vaaaaanquish
4
4.5k
Amazon_CloudWatch_ログ異常検出_導入ガイド
tsujiba
4
1.6k
カメラを用いた店内計測におけるオプトインの仕組みの実現 / ai-optin-camera
cyberagentdevelopers
PRO
1
120
わたしとトラックポイント / TrackPoint tips
masahirokawahara
1
240
【若手エンジニア応援LT会】AWS Security Hubの活用に苦労した話
kazushi_ohata
0
160
小規模に始めるデータメッシュとデータガバナンスの実践
kimujun
3
590
オーティファイ会社紹介資料 / Autify Company Deck
autifyhq
9
120k
LeSSに潜む「隠れWF病」とその処方箋
lycorptech_jp
PRO
2
120
Autify Company Deck
autifyhq
1
39k
ネット広告に未来はあるか?「3rd Party Cookie廃止とPrivacy Sandboxの効果検証の裏側」 / third-party-cookie-privacy
cyberagentdevelopers
PRO
1
130
AWS CDKでデータリストアの運用、どのように設計する?~Aurora・EFSの実践事例を紹介~/aws-cdk-data-restore-aurora-efs
mhrtech
4
650
Featured
See All Featured
Fireside Chat
paigeccino
32
3k
Being A Developer After 40
akosma
86
590k
Product Roadmaps are Hard
iamctodd
PRO
48
10k
Making Projects Easy
brettharned
115
5.9k
10 Git Anti Patterns You Should be Aware of
lemiorhan
654
59k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
28
9.1k
YesSQL, Process and Tooling at Scale
rocio
167
14k
The Cult of Friendly URLs
andyhume
78
6k
Making the Leap to Tech Lead
cromwellryan
132
8.9k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
131
33k
Typedesign – Prime Four
hannesfritz
39
2.4k
How to Think Like a Performance Engineer
csswizardry
19
1.1k
Transcript
AbemaTV iOSࣾϥϯνษڧձ 2018/04/10 Yuji Hato 5ͰֶͿ ࠩߋ৽ͱRxDataSources
About me Yuji Hato CyberAgent, Inc. / AbemaTV, Inc. dekatotoro
@dekatotoro Contributed services
RxDataSources
RxDataSources RxDataSources ͬͯԿʁ
RxDataSources RxSwiftͷͨΊͷUITableViewͱ UICollectionViewͷDataSource
RxDataSources Կ͕خ͍͠ͷʁ
RxDataSources UITableView, UICollectionViewͷ delete, insert, move͕ ؆୯ʹ࣮Ͱ͖Δ !
RxDataSources delete, insert, moveͷͨΊͷߋ৽ͷࠩΛந ग़͢ΔΞϧΰϦζϜਖ਼֬ʹΖ͏ͱ͢Δͱ ͚ͬ͜͏͍͠…
RxDataSources ࠩநग़ΞϧΰϦζϜ
RxDataSources ɾWagner-Fischer ɾHeckel ɾMyers ɾWu …
RxDataSources ࠩநग़ΞϧΰϦζϜͷϥΠϒϥϦ
RxDataSources ɾosteslag/Changeset … Wagner-Fischer ɾjflinter/Dwifft … Myers ɾwokalski/Diff.swift … Myers
ɾonyarnold/Differ … Myers(Diff.swiftͷfork) ɾonmyway133/DeepDiff … HeckelΆ͍ ɾInstagram/IGListKit … Heckel ɾRxSwiftCommunity/RxDataSources … Heckelվ ɾkazuhiro4949/EditDistance … Wu
RxDataSources IGListKit … SectionΛදݱͨ͠ଟ࣍ݩ ྻͷࠩʹରԠ͍ͯ͠ͳ͍ RxDataSources … ϢχʔΫIDΛ࣋ͪɺ ྻʹॏෳ͕ͳ͍લఏͰSectionͷࠩߋ৽
RxDataSources ↓ ͜ΕΘ͔Γ͍͢ https://github.com/horita-yuya/ DifferenceAlgorithmComparison
RxDataSources ࣮
RxDataSources
RxDataSources SectionModelͷprotocol
public protocol SectionModelType { associatedtype Item public var items: [Self.Item]
{ get } public init(original: Self, items: [Self.Item]) } RxDataSources
public protocol IdentifiableType { associatedtype Identity : Hashable public var
identity: Self.Identity { get } } RxDataSources
public protocol AnimatableSectionModelType : SectionModelType, IdentifiableType where Self.Item : IdentifiableType,
Self.Item : Equatable { } RxDataSources
RxDataSources SectionModel
enum DownloadSeriesSectionModel: AnimatableSectionModelType { typealias Item = DownloadSeriesSectionItem case episodeList(season:
DownloadSeason?, items: [Item]) case other(items: [Item]) // Mark: - IdentifiableType var identity: String { … } // Mark: - SectionModelType var items: [DownloadSeriesSectionItem] { switch self { case .episodeList(_, let items): return items case .other(let items): return items } } init(original: DownloadSeriesSectionModel, items: [Item]) { switch original { case .episodeList(let season, _): self = .episodeList(season: season, items: items) case .other: self = .other(items: items) } } } RxDataSources
RxDataSources SectionItemModel
enum DownloadSeriesSectionItem: IdentifiableType, Equatable { case episode(downloadMedia: DownloadMedia) case seeOtherEpisode(series:
DownloadSeries) // Mark: - IdentifiableType var identity: String { … } // Mark: - Equatable static func == (lhs: DownloadSeriesSectionItem, rhs: DownloadSeriesSectionItem) -> Bool { … } } RxDataSources
RxDataSources AnimatableSectionModel
public struct AnimatableSectionModel<Section: IdentifiableType, ItemType: IdentifiableType & Equatable> { public
var model: Section public var items: [Item] public init(model: Section, items: [ItemType]) { self.model = model self.items = items } } extension AnimatableSectionModel : AnimatableSectionModelType { public typealias Item = ItemType public typealias Identity = Section.Identity public var identity: Section.Identity { return model.identity } public init(original: AnimatableSectionModel, items: [Item]) { self.model = original.model self.items = items } public var hashValue: Int { return self.model.identity.hashValue } } RxDataSources Α͘ݟͨΒ3Y%BUB4PVSDFT ʹ"OJNBUBCMF4FDUJPO.PEFM͕ ༻ҙ͞Ε͍ͯΔͷͰ͜ΕΛ͏ ͷ͕CFUUFS
RxDataSources RxTableViewSectionedAnimatedDataSource
open class RxTableViewSectionedAnimatedDataSource<S: AnimatableSectionModelType> : TableViewSectionedDataSource<S> , RxTableViewDataSourceType { …
public init( animationConfiguration: AnimationConfiguration = AnimationConfiguration(), decideViewTransition: @escaping DecideViewTransition = { _, _, _ in .animated }, configureCell: @escaping ConfigureCell, titleForHeaderInSection: @escaping TitleForHeaderInSection = { _, _ in nil }, titleForFooterInSection: @escaping TitleForFooterInSection = { _, _ in nil }, canEditRowAtIndexPath: @escaping CanEditRowAtIndexPath = { _, _ in false }, canMoveRowAtIndexPath: @escaping CanMoveRowAtIndexPath = { _, _ in false }, sectionIndexTitles: @escaping SectionIndexTitles = { _ in nil }, sectionForSectionIndexTitle: @escaping SectionForSectionIndexTitle = { _, _, index in index } ) { self.animationConfiguration = animationConfiguration self.decideViewTransition = decideViewTransition super.init( configureCell: configureCell, titleForHeaderInSection: titleForHeaderInSection, titleForFooterInSection: titleForFooterInSection, canEditRowAtIndexPath: canEditRowAtIndexPath, canMoveRowAtIndexPath: canMoveRowAtIndexPath, sectionIndexTitles: sectionIndexTitles, sectionForSectionIndexTitle: sectionForSectionIndexTitle ) } … } RxDataSources
final class DownloadSeriesDelegate: NSObject, UITableViewDelegate { … lazy var dataSource:
RxTableViewSectionedAnimatedDataSource<DownloadSeriesSectionModel> = .init( animationConfiguration: AnimationConfiguration(insertAnimation: .fade, reloadAnimation: .none, deleteAnimation: .fade), configureCell: { [weak self] dataSource, table, indexPath, item in guard let me = self else { return UITableViewCell() // Should never reach here. } switch item { case .episode(let downloadMedia): let cell = table.dequeueReusableCell(DownloadListMediaCell.self, forIndexPath: indexPath) cell.configure(downloadMedia: downloadMedia) … return cell case .seeOtherEpisode(let series): let cell = table.dequeueReusableCell(DownloadSeeOtherEpisodeCell.self, forIndexPath: indexPath) cell.rx.tapGesture .subscribe(onNext: { [weak self] in … }) .disposed(by: cell.reusableDisposeBag) … return cell } }) … RxDataSources
final class DownloadSeriesViewStream { … let sectionModels: Property<[DownloadSeriesSectionModel]> private let
_sectionModels = Variable<[DownloadSeriesSectionModel]>([]) … } RxDataSources
final class DownloadSeriesViewController: UIViewController { … viewStream.sectionModels.asObservable() // IMPORTANT: //
crashճආɺཁௐࠪ. .throttle(1.0, latest: true, scheduler: ConcurrentMainScheduler.instance) .bind(to: tableView.rx.items(dataSource: delegate.dataSource)) .disposed(by: rx.disposeBag) … RxDataSources
RxDataSources UITableViewDelegateʁ
// MARK: - UITableViewDelegate func tableView(_ tableView: UITableView, heightForRowAt indexPath:
IndexPath) -> CGFloat { … } func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { … } func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { … } func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { … } … RxDataSources
Conclusion
Conclusion • ࠩநग़ΞϧΰϦζϜͷϥΠϒϥϦݕ౼͠Α͏ • DiffΞϧΰϦζϜࣗલͰ࡞Ζ͏ͱ͢Δͱ͚ͬ͜͏େม • RxSwift͍ͬͯΔͳΒRxDataSourcesͰྑͦ͞͏
Thank you