uikonf app & data driven design @swift.berlin
TRANSCRIPT
![Page 1: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/1.jpg)
UIKonf App Architecture&Data Oriented Design
![Page 2: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/2.jpg)
![Page 3: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/3.jpg)
+------------+ +----------------+| | | || Objects | | Data |+------------+ +----------------+| Talk | | Title || Speaker | | Description || Organizer | | StartTime || Volunteer | | EndTime || Venue | | Name || Break | | TwitterHandle || Workshop | | PhotoURL || ... | | ... || | | |+------------+ +----------------+
![Page 4: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/4.jpg)
![Page 5: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/5.jpg)
Time slot
[ { "t_id": "startDay1", "startTime": "18-09-00", "endTime": "18-10-00", "description": "Check in first day", "locations": [ "Heimathafen Neukölln" ] }, ...
![Page 6: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/6.jpg)
Organizer
... { "name": "Maxim Zaks", "twitter": "@iceX33", "bio": "Software developer with a history in IDE development, Web development and even Enterprise Java development (He was young and under bad influence). Nowadays working as a game developer (preferably iOS). Regular visitor and occasional speaker at conferences.", "photo": "http://www.uikonf.com/static/images/maxim-zaks.png", "organizer": true }, ...
![Page 7: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/7.jpg)
Speaker
... { "name": "Graham Lee", "twitter": "@iwasleeg", "bio": "Graham Lee works at Facebook, where he helps people make better tests so they can help people make better software. In the past he worked with some other people, and has written books and blogs so he can work with people he hasn't met too. His blog is at sicpers.info.", "photo": "http://www.uikonf.com/static/images/Graham-Lee.png" }, ...
![Page 8: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/8.jpg)
Talk
... { "title": "World Modeling", "speaker_name": "Mike Lee", "t_id": "session1Day1", "t_index": 1 }, ...
![Page 9: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/9.jpg)
Location
... { "name": "Heimathafen Neukölln", "address": "Karl-Marx-Str. 141, 12043 Berlin", "description": "Conference venue" }, ...
![Page 10: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/10.jpg)
Import Data from JSON Array
for item in jsonArray { let entity = context.createEntity()
for pair in (item as! NSDictionary) { let (key,value) = (pair.key as! String, pair.value as! JsonValue)
let component = converters[key]!(value) entity.set(component) } }
![Page 11: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/11.jpg)
What is a context?It's a managing data structure
![Page 12: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/12.jpg)
public class Context { public func createEntity() -> Entity public func destroyEntity(entity : Entity) public func entityGroup(matcher : Matcher) -> Group }
![Page 13: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/13.jpg)
What's an entity?Bag of components
![Page 14: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/14.jpg)
Entity
public class Entity { public func set(c:Component, overwrite:Bool = false) public func get<C:Component>(ct:C.Type) -> C? public func has<C:Component>(ct:C.Type) -> Bool public func remove<C:Component>(ct:C.Type)}
![Page 15: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/15.jpg)
What's a componentIt's just data (value object)
![Page 16: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/16.jpg)
Components
struct NameComponent : Component, DebugPrintable { let name : String var debugDescription: String{ return "[\(name)]" }}
![Page 17: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/17.jpg)
What's a componentIt also can be just a flag
![Page 18: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/18.jpg)
struct OrganizerComponent : Component {}
![Page 19: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/19.jpg)
![Page 20: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/20.jpg)
Import Data from JSON Array
for item in jsonArray { let entity = context.createEntity()
for pair in (item as! NSDictionary) { let (key,value) = (pair.key as! String, pair.value as! JsonValue)
let component = converters[key]!(value) entity.set(component) } }
![Page 21: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/21.jpg)
Converters dictionary
typealias Converter = (JsonValue) -> Component
let converters : [String : Converter] = [ "t_id" : { TimeSlotIdComponent(id: $0 as! String) }, "t_index" : { TimeSlotIndexComponent(index: $0 as! Int) }, ...
![Page 22: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/22.jpg)
How does it work with UIKit
![Page 23: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/23.jpg)
![Page 24: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/24.jpg)
override func viewDidLoad() { super.viewDidLoad()
groupOfEvents = context.entityGroup( Matcher.Any(StartTimeComponent, EndTimeComponent))
setNavigationTitleFont()
groupOfEvents.addObserver(self)
context.entityGroup( Matcher.All(RatingComponent)).addObserver(self)
readDataIntoContext(context)
syncData(context)
}
![Page 25: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/25.jpg)
What's a group?Subset of Entites
![Page 26: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/26.jpg)
Entity
public class Group : SequenceType { public var count : Int public var sortedEntities: [Entity] public func addObserver(observer : GroupObserver) public func removeObserver(observer : GroupObserver)}
![Page 27: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/27.jpg)
![Page 28: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/28.jpg)
override func viewDidLoad() { super.viewDidLoad()
groupOfEvents = context.entityGroup( Matcher.Any(StartTimeComponent, EndTimeComponent))
setNavigationTitleFont()
groupOfEvents.addObserver(self)
context.entityGroup( Matcher.All(RatingComponent)).addObserver(self)
readDataIntoContext(context)
syncData(context)
}
![Page 29: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/29.jpg)
![Page 30: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/30.jpg)
extension TimeLineViewController : GroupObserver {
func entityAdded(entity : Entity) { if entity.has(RatingComponent){ updateSendButton() } else { reload() } }
func entityRemoved(entity : Entity, withRemovedComponent removedComponent : Component) { if removedComponent is RatingComponent { return } reload() }}
![Page 31: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/31.jpg)
private lazy var reload : dispatch_block_t = dispatch_debounce_block(0.1) { ...}
![Page 32: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/32.jpg)
![Page 33: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/33.jpg)
![Page 34: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/34.jpg)
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let sectionName = sectionNameTable[indexPath.section]()! let cellIdentifier = cellIdTable[sectionName]!
let cell = tableView.dequeueReusableCellWithIdentifier( cellIdentifier, forIndexPath: indexPath) as! EntityCell
let cellEntity = cellEntityTable[sectionName]!(indexPath.row)
cell.updateWithEntity(cellEntity, context: context)
return cell as! UITableViewCell}
![Page 35: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/35.jpg)
protocol EntityCell { func updateWithEntity(entity : Entity, context : Context)}
class LocationCell: UITableViewCell, EntityCell {
@IBOutlet weak var nameLabel: UILabel! @IBOutlet weak var descriptionLabel: UITextView!
func updateWithEntity(entity : Entity, context : Context){
nameLabel.text = entity.get(NameComponent)!.name let descriptionText = entity.get(DescriptionComponent)?.description let address = entity.get(AddressComponent)!.address
descriptionLabel.text = descriptionText != nil ? descriptionText! + "\n" + address : address }}
![Page 36: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/36.jpg)
![Page 37: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/37.jpg)
struct PhotoComponent : Component, DebugPrintable { let url : NSURL let image : UIImage let loaded : Bool var debugDescription: String{ return "[\(url), loaded: \(loaded)]" }}
![Page 38: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/38.jpg)
Data:{ ... "photo": "http://www.uikonf.com/static/images/maxim-zaks.png", ...}
Converter:"photo" : { PhotoComponent(url: NSURL(string:$0 as! String)!, image : UIImage(named:"person-icon")!, loaded: false)},
![Page 39: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/39.jpg)
func setPhoto() { let photoComponent = entity!.get(PhotoComponent)! imageView.image = photoComponent.image if !photoComponent.loaded { ... }}
![Page 40: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/40.jpg)
var detachedPerson = entity!.detachcancelLoadingPhoto = dispatch_after_cancellable( 0.5, dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0)) { if let data = NSData(contentsOfURL: photoComponent.url), let image = UIImage(data: data) {
let photoComponent = detachedPerson.get(PhotoComponent)! detachedPerson.set( PhotoComponent(url: photoComponent.url, image:image, loaded:true), overwrite: true ) detachedPerson.sync() }}
![Page 41: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/41.jpg)
What's a detached Entity?It's an Entity implemented as a struct
with a sync method
![Page 42: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/42.jpg)
var detachedPerson = entity!.detachcancelLoadingPhoto = dispatch_after_cancellable( 0.5, dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0)) { if let data = NSData(contentsOfURL: photoComponent.url), let image = UIImage(data: data) {
let photoComponent = detachedPerson.get(PhotoComponent)! detachedPerson.set( PhotoComponent(url: photoComponent.url, image:image, loaded:true), overwrite: true ) detachedPerson.sync() }}
![Page 43: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/43.jpg)
Recap
—Context is a managing Data Structure—Entity is a bag of components—Components are just value types—Groups are subsets on the components—You can observe groups -> KVO like behavior—Use detached entity if you want to go on another
queue
![Page 44: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/44.jpg)
Tanks youMaxim - @iceX33
![Page 45: UIKonf App & Data Driven Design @swift.berlin](https://reader031.vdocuments.net/reader031/viewer/2022020123/55bab25fbb61eb91158b45b4/html5/thumbnails/45.jpg)
Links
—UIKonf App on Github—Blog: Think different about Data Model—Blog: What is an entity framework—Book: Data oriented Design (C++ heavy)—Talk: Data-Oriented Design and C++ (hardcore)