Slide 1

Slide 1 text

Advanced TableView / CollectionView Design nori Jun 2017 @1amageek Hello. #WWDC2017 Thank you Yahoo Japan

Slide 2

Slide 2 text

About 1amageek System Device Technology LSI design engineer iOS engineer iOS engineer 2017.5 ~ 2015.10 ~ 2009.4 ~ Bio

Slide 3

Slide 3 text

Bleu Salada OSS Library Bluetooth Library Firebase Library https://github.com/1amageek AssemblyLine Multitask Library

Slide 4

Slide 4 text

TableView is the basis of Mobile design. Facebook Twitter

Slide 5

Slide 5 text

Things to think about Mock UI Network Model API Sort ActionCount Scheme Pull to reload REST Background Kingfisher SDWebImage APIKit Session Cache

Slide 6

Slide 6 text

Design flow UI Network Model Load and Reload Bad network REST API Scheme Data Populate Version Migration Cache Non Blocking Frame rate Easy & Simple Latency

Slide 7

Slide 7 text

Design flow UI Network Model Load and Reload Bad network REST API Scheme Data Populate Version Migration Cache Non Blocking Frame rate Easy & Simple Latency

Slide 8

Slide 8 text

Solution AutoSync Database

Slide 9

Slide 9 text

Advanced TableView Design ≒ TableView Design with AutoSync Database

Slide 10

Slide 10 text

Reactive Cell Layout Without REST API Realtime reload TableView Design with AutoSync Database

Slide 11

Slide 11 text

Realtime reload 1. Write load function in viewDidLoad 2. Pull to refresh

Slide 12

Slide 12 text

Realtime reload 1. Write load function in viewDidLoad 2. Pull to refresh

Slide 13

Slide 13 text

Without REST API 1. Use mock until API is created 2. Parsing JSON / Model Mapping 3. AFNetworking / Alamofire / APIKit 4. Server engineer

Slide 14

Slide 14 text

Without REST API 1. Use mock until API is created 2. Parsing JSON / Model Mapping 3. AFNetworking / Alamofire / APIKit 4. Server engineer

Slide 15

Slide 15 text

Reactive Cell Layout 1. Create an API for user action 2. Parsing JSON / Model Mapping 3. Latency 4. Consistency ※ Firebase Realtime Databaseͱ͸ͳΜͳͷ͔ʁ

Slide 16

Slide 16 text

Reactive Cell Layout 1. Create an API for user action 2. Parsing JSON / Model Mapping 3. Latency 4. Consistency ※ Firebase Realtime Databaseͱ͸ͳΜͳͷ͔ʁ

Slide 17

Slide 17 text

DEMO

Slide 18

Slide 18 text

Feed Feed Feed Feed Sample App

Slide 19

Slide 19 text

class User: Object { dynamic var name: String? dynamic var profileImage: File? dynamic var bio: String? dynamic var feedIDs: Set = [] dynamic var photoIDs: Set = [] }

Slide 20

Slide 20 text

class Photo: Object { dynamic var data: File? dynamic var text: String? }

Slide 21

Slide 21 text

class Feed: Object { @objc enum ContentType: Int { case unknown case photo case movie } dynamic var userID: String? dynamic var contentType: ContentType = .unknown dynamic var contentID: String? dynamic var likeCount: Int = 0 override func encode(_ key: String, value: Any?) -> Any? { if key == "contentType" { return self.contentType.rawValue as Int } return nil } override func decode(_ key: String, value: Any?) -> Any? { if key == "contentType" { if let type: Int = value as? Int { self.contentType = ContentType(rawValue: type)! return self.contentType } } return nil } }

Slide 22

Slide 22 text

// Make photo sample (0..<6).forEach { (index) in let name: String = "\(index)" let image: UIImage = UIImage(named: name)! let data: Data = UIImageJPEGRepresentation(image, 0.7)! let file: File = File(data: data) let photo: Photo = Photo() photo.text = "This picture \(index) is very beautiful " photo.data = file photo.save({ (ref, error) in if let error = error { debugPrint(error) return } // relationship to user user.photoIDs.insert(ref!.key) // Make Feed sample let feed: Feed = Feed() feed.userID = user.key feed.contentType = .photo feed.contentID = ref!.key feed.save({ (ref, error) in if let error = error { debugPrint(error) return } // relationship to user user.feedIDs.insert(ref!.key) }) }) }

Slide 23

Slide 23 text

let options: SaladaOptions = SaladaOptions() options.limit = 10 options.ascending = false self.datasource = DataSource(parentKey: userID, referenceKey: "feedIDs", options: options, block: { [weak self](changes) in guard let tableView: UITableView = self?.tableView else { return } switch changes { case .initial: tableView.reloadData() case .update(let deletions, let insertions, let modifications): tableView.beginUpdates() tableView.insertRows(at: insertions.map { IndexPath(item: 0, section: $0) }, with: .automatic) tableView.deleteRows(at: deletions.map { IndexPath(item: 0, section: $0) }, with: .automatic) tableView.reloadRows(at: modifications.map { IndexPath(item: 0, section: $0) }, with: .automatic tableView.insertSections(IndexSet(insertions), with: .automatic) tableView.deleteSections(IndexSet(deletions), with: .automatic) tableView.reloadSections(IndexSet(modifications), with: .automatic) tableView.endUpdates() case .error(let error): print(error) } })

Slide 24

Slide 24 text

func configure(cell: TableViewCell, at indexPath: IndexPath) { self.datasource?.observeObject(at: indexPath.section, block: { (feed) in guard let feed: Feed = feed else { return } // Get user data User.observeSingle(feed.userID!, eventType: .value, block: { (user) in guard let user: User = user else { return } cell.titleView.titleLabel.text = user.name cell.titleView.dateLabel.text = self.dateFormatter.string(from: feed.updatedAt) if let ref: StorageReference = user.profileImage?.ref { cell.titleView.imageView.sd_setImage(with: ref, placeholderImage: nil) } }) // Switch content type switch feed.contentType { // Photo case .photo: // Get photo data Photo.observeSingle(feed.contentID!, eventType: .value, block: { (photo) in guard let photo: Photo = photo else { return } cell.detailView.detailLabel.text = photo.text cell.setNeedsLayout() if let ref: StorageReference = photo.data?.ref { cell.photoView.imageView.sd_setImage(with: ref, placeholderImage: nil) } }) // TODO: hide content default: break } }) }

Slide 25

Slide 25 text

var likeCount: Int = feed.likeCount cell.actionView.likeCountLabel.text = String(likeCount) cell.actionView.actionBlock = { likeCount += 1 cell.actionView.likeCountLabel.text = String(likeCount) feed.likeCount = likeCount }

Slide 26

Slide 26 text

Ads PXL Your photos will be born again as a wonderful art. This photo collage is what makes you feel more happy and pleased. Let's share the pixel art to all over the world. $0.99

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

Thank you '