Successfully reported this slideshow.
Your SlideShare is downloading. ×

미려한 UI/UX를 위한 여정

Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad

Check these out next

1 of 96 Ad

More Related Content

Slideshows for you (20)

Similar to 미려한 UI/UX를 위한 여정 (20)

Advertisement

Recently uploaded (20)

미려한 UI/UX를 위한 여정

  1. 1. Animation in iOS Looper Code : https://github.com/dotNetTree/letswift2019
  2. 2. Animation in iOS
  3. 3. (0, 0) (40, 0)
  4. 4. (0, 0) (40, 0)
  5. 5. • 1 center (0, 0) -> center (40, 0) (0, 0) (40, 0)
  6. 6. • 1 center (0, 0) -> center (40, 0) (0, 0) (40, 0) vCircle.center = CGPoint.init(x: 0, y: 0) UIView.animate(withDuration: 1) { vCircle.center = CGPoint.init(x: 40, y: 0) }
  7. 7. • 1 center (0, 0) -> center(40, 0) (0, 0) (40, 0) vCircleCenterX.constant = 40 UIView.animate(withDuration: 1) { vCircle.superview?.layoutIfNeeded() }
  8. 8. (100, 100)
  9. 9. (100, 50) (100, 100)
  10. 10. (100, 100) let circlePath = UIBezierPath( arcCenter: CGPoint(x: 100, y: 100), radius: 50, startAngle: 0, endAngle: .pi * 2, clockwise: true ) let animation = CAKeyframeAnimation( keyPath: #keyPath(CALayer.position) ) animation.duration = 1 animation.path = circlePath.cgPath animation.fillMode = .forwards animation.isRemovedOnCompletion = false vCircle.layer.add(animation, forKey: nil) (100, 50)
  11. 11. • 3 center (0, 0) -> center (40, 0) • 1.5 alpha 0.9 -> alpha 0.3 (0, 0) (40, 0)
  12. 12. vCircle.center = CGPoint(x: 0, y: 0) vCircle.alpha = 1 UIView.animate(withDuration: 1.5, animations: { vCircle.center = CGPoint(x: 20, y: 0) vCircle.alpha = 0.3 }, completion: { _ in UIView.animate(withDuration: 1.5) { vCircle.center = CGPoint(x: 40, y: 0) } })
  13. 13. vCircle.center = CGPoint(x: 0, y: 0) vCircle.alpha = 1 UIView.animate(withDuration: 1.5, animations: { vCircle.center = CGPoint(x: 20, y: 0) vCircle.alpha = 0.3 }, completion: { _ in UIView.animate(withDuration: 1.5) { vCircle.center = CGPoint(x: 40, y: 0) } })
  14. 14. vCircle.center = CGPoint(x: 0, y: 0) vCircle.alpha = 1 UIView.animate(withDuration: 3) { vCircle.center = CGPoint(x: 40, y: 0) } UIView.animate(withDuration: 1.5) { vCircle.alpha = 0 }
  15. 15. • (Refresh Rate) • 1 • Hz (60Hz = 1 60 )
  16. 16. • FPS (Frame Per Second) • - • Hz FPS • (Device)
  17. 17. • CADisplayLink
  18. 18. • CADisplayLink • A timer object that allows your application to synchronize its drawing to the refresh rate of the display
  19. 19. • CADisplayLink • A timer object that allows your application to synchronize its drawing to the refresh rate of the display •
  20. 20. vCircle.center = CGPoint(x: 0, y: 0) vCircle.alpha = 1 UIView.animate(withDuration: 3) { vCircle.center = CGPoint(x: 40, y: 0) } UIView.animate(withDuration: 1.5) { vCircle.alpha = 0 }
  21. 21. func aniStart() { displayLink = CADisplayLink(target: self, selector: #selector(update)) displayLink?.add(to: .main, forMode: .common) start1 = now() ; start2 = now() term1 = 3 ; term2 = 1.5 isEnd1 = false; isEnd2 = false } @objc func update() { ani1(); ani2() } func ani1() { guard !isEnd1 else { return } let rate = min(1.0, (now() - start1) / term1) if rate == 1.0 { isEnd1 = true } vCircle.center = CGPoint(x: 40.0 * rate, y: 0) } func ani2() { guard !isEnd2 else { return } let rate = min(1.0, (now() - start2) / term2) if rate == 1.0 { isEnd2 = true } vCircle.alpha = CGFloat(1.0 - rate) }
  22. 22. Looper
  23. 23. func aniStart() { displayLink = CADisplayLink(target: self, selector: #selector(update)) displayLink?.add(to: .main, forMode: .common) start1 = now() ; start2 = now() term1 = 3 ; term2 = 1.5 isEnd1 = false; isEnd2 = false } @objc func update() { ani1(); ani2() } func ani1() { guard !isEnd1 else { return } let rate = min(1.0, (now() - start1) / term1) if rate == 1.0 { isEnd1 = true } vCircle.center = CGPoint(x: 40.0 * rate, y: 0) } func ani2() { guard !isEnd2 else { return } let rate = min(1.0, (now() - start2) / term2) if rate == 1.0 { isEnd2 = true } vCircle.alpha = CGFloat(1.0 - rate) }
  24. 24. func aniStart() { displayLink = CADisplayLink(target: self, selector: #selector(update)) displayLink?.add(to: .main, forMode: .common) start1 = now() ; start2 = now() term1 = 3 ; term2 = 1.5 isEnd1 = false; isEnd2 = false } @objc func update() { ani1(); ani2() } func ani1() { guard !isEnd1 else { return } let rate = min(1.0, (now() - start1) / term1) if rate == 1.0 { isEnd1 = true } vCircle.center = CGPoint(x: 40.0 * rate, y: 0) } func ani2() { guard !isEnd2 else { return } let rate = min(1.0, (now() - start2) / term2) if rate == 1.0 { isEnd2 = true } vCircle.alpha = CGFloat(1.0 - rate) } class Item { typealias Block = (Item) -> Void static let emptyBlock: Block = { _ in } var start = 0.0 var term = 0.0 var rate = 0.0 var current = 0.0 var block: Block = Item.emptyBlock var ended: Block = Item.emptyBlock var next: Item? = nil var isStop = false fileprivate var marked = false … }
  25. 25. func aniStart() { … } @objc func update() { ani1(); ani2() } func ani1() { guard !isEnd1 else { return } let rate = min(1.0, (now() - start1) / term1) if rate == 1.0 { isEnd1 = true } vCircle.center = CGPoint(x: 40.0 * rate, y: 0) } func ani2() { guard !isEnd2 else { return } let rate = min(1.0, (now() - start2) / term2) if rate == 1.0 { isEnd2 = true } vCircle.alpha = CGFloat(1.0 - rate) }
  26. 26. func aniStart() { … } @objc func update() { ani1(); ani2() } func ani1() { guard !isEnd1 else { return } let rate = min(1.0, (now() - start1) / term1) if rate == 1.0 { isEnd1 = true } vCircle.center = CGPoint(x: 40.0 * rate, y: 0) } func ani2() { guard !isEnd2 else { return } let rate = min(1.0, (now() - start2) / term2) if rate == 1.0 { isEnd2 = true } vCircle.alpha = CGFloat(1.0 - rate) } class Looper { private var items = Collection<Item>() private var pool = Collection<Item>() … fileprivate func loop() { let c = now() let _items = items.elements var cnt = _items.count var hasRemoveItems = false while 0 < cnt { cnt -= 1 let item = _items[cnt] … item.rate = { … }() item.block(item) … } if hasRemoveItems { … } } }
  27. 27. looper.invoke { (dsl) in dsl.time = 0.3 dsl.block = { item in vCircle.alpha = CGFloat(item.rate) } }
  28. 28. Looper looper.invoke { (dsl) in dsl.time = 0.3 dsl.block = { item in vCircle.alpha = CGFloat(item.rate) } } @discardableResult func invoke( _ block: (ItemDSL) -> Void ) -> Sequence { let dsl = ItemDSL() block(dsl) let item = getItem(dsl) item.start += now() item.end = item.start + item.term items.append(item) sequence.current = item return sequence }
  29. 29. Updater private var displayLink: CADisplayLink? func aniStart() { displayLink = CADisplayLink(target: self, selector: #selector(update)) displayLink?.add(to: .main, forMode: .common) … } @objc func update() { ... }
  30. 30. Updater class Updater { private var displayLink: CADisplayLink? fileprivate var loopers = [Looper]() func start() { displayLink = CADisplayLink( target: self, selector: #selector(update) ) displayLink?.add(to: .main, forMode: .common) } … @objc func update() { loopers.forEach { $0.loop() } } }
  31. 31. Looper looper.invoke { dsl in dsl.time = 3 dsl.block = { item in self.vCircle.center = CGPoint(x: 40.0 * item.rate, y: 0) } } looper.invoke { dsl in dsl.time = 1.5 dsl.block = { item in self.vCircle.alpha = CGFloat(1.0 - item.rate) } } 10
  32. 32. Demo
  33. 33. Demo Code : https://github.com/dotNetTree/letswift2019
  34. 34. Demo Code : https://github.com/dotNetTree/letswift2019
  35. 35. Looper Invokeitem loop Items Pool item Updater update
  36. 36. Section 1 Section 2 Section 3
  37. 37. Section 1 Section 2 Section 3
  38. 38. Section 1 Section 2 Section 3
  39. 39. Section 1 Section 2 Section 3 API 1 API 2 API 3 fetch 1 fetch 2 fetch 3 0.2sec 0.8sec 0.3sec
  40. 40. Section 1 Section 2Section 3
  41. 41. func fetch1(completion: @escaping (Response) -> Void) { Alamofire.request(“api/fetch1").response { completion($0.response!) } } … fetch1 { response1 in fetch2 { response2 in fetch3 { response3 in section3.render(with: response3) } section2.render(with: response2) } section1.render(with: response1) }
  42. 42. var res1: Response!; var res2: Response!; var res3: Response! func fetchAll() { fetch1 { r in res1 = r; render(); } fetch2 { r in res2 = r; render(); } fetch3 { r in res3 = r; render(); } } func render() { guard let res1 = res1, let res2 = res2, let res3 = res3 else { return } section1.render(with: res1) section2.render(with: res2) section3.render(with: res3) }
  43. 43. var res1: Response!; var res2: Response!; var res3: Response! func fetchAll() { fetch1 { r in res1 = r; render(); } fetch2 { r in res2 = r; render(); } fetch3 { r in res3 = r; render(); } } func render() { guard let res1 = res1, let res2 = res2, let res3 = res3 else { return } section1.render(with: res1) section2.render(with: res2) section3.render(with: res3) }
  44. 44. var res1: Response! looper.invoke { dsl in fetch1 { r in res1 = r } dsl.isInfinity = true dsl.block = { item in if res1 != nil { section1.render(with: res1); item.isStop = true } } }
  45. 45. var res1: Response!; var res2: Response! looper.invoke { dsl in fetch1 { r in res1 = r } dsl.isInfinity = true dsl.block = { item in if res1 != nil { section1.render(with: res1); item.isStop = true } } }.next { dsl in fetch2 { r in res2 = r } dsl.isInfinity = true dsl.block = { item in if res2 != nil { section2.render(with: res2); item.isStop = true } } }
  46. 46. Flow - async Flow() .async { sync in /* start */ } .async { sync in /* start */ } .start()
  47. 47. Flow - async Flow() .async { sync in /* start */ } .async { sync in /* start */ } .start()
  48. 48. Flow - async Flow() .async { sync in … sync { /* 1*/ } … } .async { sync in … sync { /* 2 */ } … } .start()
  49. 49. var res1: Response!; var res2: Response! looper.invoke { dsl in fetch1 { r in res1 = r } dsl.isInfinity = true dsl.block = { item in if res1 != nil { section1.render(with: res1); item.isStop = true } } }.next { dsl in fetch2 { r in res2 = r } dsl.isInfinity = true dsl.block = { item in if res2 != nil { section2.render(with: res2); item.isStop = true } } } Flow() .async { sync in fetch1 { r in sync { section1.render(with: r) } } } .async { sync in fetch2 { r in sync { section2.render(with: r) } } } .start()
  50. 50. class Flow { private class Block { static let TypeAsync = “async" var type: String let body: Any init(type: String, body: Any) { self.type = type self.body = body } } typealias VoidClosure = () -> Void typealias Sync = (@escaping VoidClosure) -> Void typealias Async = (@escaping Sync) -> Void private var blocks = [Block]() private var seq: Looper.Sequence? … }
  51. 51. class Flow { private class Block { … } typealias VoidClosure = () -> Void typealias Sync = (@escaping VoidClosure) -> Void typealias Async = (@escaping Sync) -> Void private var blocks = [Block]() privatevar seq: Looper.Sequence? @discardableResult func async(body: @escaping Async) -> Flow { blocks.append(Block(type: Block.TypeAsync, body: body)) return self } func start() { … _start() } … } private func _start() { while blocks.count > 0 { let block = blocks.removeFirst() switch block.type { case Block.TypeAsync: let body = block.body as! Async let dslBlock = getDSLBlock(body) seq = seq?.next(dslBlock) ?? looper.invoke(dslBlock) default: break } } }
  52. 52. class Flow { … typealias VoidClosure = () -> Void typealias Sync = (@escaping VoidClosure) -> Void typealias Async = (@escaping Sync) -> Void … private func getDSLBlock( _ async: @escaping Async ) -> (Looper.Looper.ItemDSL) -> Void { { dsl in var completion: VoidClosure? async({ c in completion = c }) dsl.isInfinity = true dsl.block = { item in if completion != nil { completion?(); item.isStop = true } } } } Flow() .async { sync in fetch1 { r in sync { section1.render(with: r) } } } .async { sync in fetch2 { r in sync { section2.render(with: r) } } } .start()
  53. 53. Flow - async Flow() .async { sync in fetch1 { r in sync { section1.render(with: r) } } } .async { sync in fetch2 { r in sync { section2.render(with: r) } } } .start()
  54. 54. Flow - async Flow() .async { sync in sync { indicator.show() } } .async { sync in fetch1 { r in sync { section1.render(with: r) } } } .async { sync in fetch2 { r in sync { section2.render(with: r) } } } .async { sync in fetch3 { r in sync { section3.render(with: r) } } } .async { sync in sync { indicator.hide() } } .start()
  55. 55. Flow - sync Flow() . .async { sync in fetch1 { r in sync { section1.render(with: r) } } } .async { sync in fetch2 { r in sync { section2.render(with: r) } } } .async { sync in fetch3 { r in sync { section3.render(with: r) } } } . .start() .async { sync in sync { indicator.show() } } .async { sync in sync { indicator.hide() } }
  56. 56. Flow - sync class Flow { private class Block { static let TypeSync = "sync" … } …. @discardableResult func sync(body: @escaping Sync) -> Flow { blocks.append(Block(type: Block.TypeSync, body: body)) return self } … }
  57. 57. private func _start() { while blocks.count > 0 { let block = blocks.removeFirst() switch block.type { case Block.TypeAsync: let body = block.body as! Async let dslBlock = getDSLBlock(body) seq = seq?.next(dslBlock) ?? looper.invoke(dslBlock) case Block.Sync: let body = block.body as! VoidClosure let nBody: Async = { $0(body) } blocks.insert( Flow.Block(type: Block.TypeAsync, body: nBody), at: 0 ) default: break } } }
  58. 58. Flow() .sync { indicator.show() } .async { sync in fetch1 { r in sync { section1.render(with: r) } } } .async { sync in fetch2 { r in sync { section2.render(with: r) } } } .async { sync in fetch3 { r in sync { section3.render(with: r) } } } .sync { indicator.hide() } .start() 200ms + 15ms800ms + 15ms800ms + 15ms + 15ms800ms + 15ms + 15ms + 15ms Flow - sync 15ms=
  59. 59. Flow - pause Flow() .sync { indicator.show(); after(delay: 2) { indicator.hide() } } .async { sync in fetch1 { r in sync { section1.render(with: r) } } } .async { sync in fetch2 { r in sync { section2.render(with: r) } } } .async { sync in fetch3 { r in sync { section3.render(with: r) } } } .start()
  60. 60. Flow - pause Flow() .sync { indicator.show() } .async { sync in fetch1 { r in sync { section1.render(with: r) } } } .async { sync in fetch2 { r in sync { section2.render(with: r) } } } .async { sync in fetch3 { r in sync { section3.render(with: r) } } } .sync { indicator.hide() } .start()
  61. 61. Flow - pause var started: TimeInterval! Flow() .sync { indicator.show(); started = now() } .async { sync in fetch1 { r in sync { section1.render(with: r) } } } .async { sync in fetch2 { r in sync { section2.render(with: r) } } } .async { sync in fetch3 { r in sync { section3.render(with: r) } } } .pause(duration: { 2 - min(2, now() - started) }) { indicator.hide() } .start()
  62. 62. Flow - pause private class Block { … static let TypePause = "pause" var delay: () -> TimeInterval init( type: String, body: Any, delay: @escaping () -> TimeInterval = { 0 } ) { … self.delay = delay } }
  63. 63. Flow - pause class Flow { … @discardableResult func pause( duration delay: @escaping () -> TimeInterval, body: @escaping VoidClosure = Block.EmptyBody ) -> Flow { blocks.append(Flow.Block(type: Block.TypePause, body: body, delay: delay)) return self } … }
  64. 64. private func getDSLBlock( delay: @escaping () -> TimeInterval = { 0 }, _ body: @escaping Async ) -> (Looper.Looper.ItemDSL) -> Void { { dsl in var waiting: Double! var started: Double! var completion: VoidClosure? body({ c in completion = c }) dsl.isInfinity = true dsl.block = { item in if started == nil { started = item.current; waiting = delay() } if completion != nil && item.current - started >= waiting { completion?(); item.isStop = true } } } } private func getDSLBlock( delay: @escaping () -> TimeInterval = { 0 }, _ body: @escaping Async ) -> (Looper.Looper.ItemDSL) -> Void { { dsl in var waiting: Double! var started: Double! var completion: VoidClosure? body({ c in completion = c }) dsl.isInfinity = true dsl.block = { item in if started == nil { started = item.current; waiting = delay() } if completion != nil { completion?(); item.isStop = true } } } } private func getDSLBlock( delay: @escaping () -> TimeInterval = { 0 }, _ body: @escaping Async ) -> (Looper.Looper.ItemDSL) -> Void { { dsl in var waiting: Double! var started: Double! var completion: VoidClosure? body({ c in completion = c }) dsl.isInfinity = true dsl.block = { item in if completion != nil { completion?(); item.isStop = true } } } } private func getDSLBlock( delay: @escaping () -> TimeInterval = { 0 }, _ body: @escaping Async ) -> (Looper.Looper.ItemDSL) -> Void { { dsl in var completion: VoidClosure? body({ c in completion = c }) dsl.isInfinity = true dsl.block = { item in if completion != nil { completion?(); item.isStop = true } } } } private func getDSLBlock( _ body: @escaping Async ) -> (Looper.Looper.ItemDSL) -> Void { { dsl in var completion: VoidClosure? body({ c in completion = c }) dsl.isInfinity = true dsl.block = { item in if completion != nil { completion?(); item.isStop = true } } } }
  65. 65. private func _start() { while blocks.count > 0 { let block = blocks.removeFirst() switch block.type { … case Block.Sync: let body = block.body as! VoidClosure let nBody: Async = { $0(body) } blocks.insert(Flow.Block(type: Block.TypeAsync, body: nBody), at: 0) case Block.Pause: let body = block.body as! VoidClosure let nBody: Async = { $0(body) } blocks.insert( Flow.Block(type: Block.TypeAsync, body: nBody, delay: block.delay), at: 0 ) default: break } } }
  66. 66. private func _start() { while blocks.count > 0 { let block = blocks.removeFirst() switch block.type { … case Block.Sync, Block.Pause: let body = block.body as! VoidClosure let nBody: Async = { $0(body) } blocks.insert( Flow.Block(type: Block.TypeAsync, body: nBody, delay: block.delay), at: 0 ) default: break } } }
  67. 67. private func _start() { while blocks.count > 0 { let block = blocks.removeFirst() switch block.type { case Block.TypeAsync: let delay = block.delay let body = block.body as! Async let dslBlock = getDSLBlock(delay: delay, body) seq = seq?.next(dslBlock) ?? looper.invoke(dslBlock) case Block.Sync, Block.Pause: let body = block.body as! VoidClosure let nBody: Async = { $0(body) } blocks.insert( Flow.Block(type: Block.TypeAsync, body: nBody, delay: block.delay), at: 0 ) default: break } } }
  68. 68. Flow - bundle var started: TimeInterval! Flow() .sync { indicator.show(); started = now() } .async { sync in fetch1 { r in sync { section1.render(with: r) } } } .async { sync in fetch2 { r in sync { section2.render(with: r) } } } .async { sync in fetch3 { r in sync { section3.render(with: r) } } } .pause(duration: { 2 - min(2, now() - started) }) { indicator.hide() } .start()
  69. 69. Flow - bundle var started: TimeInterval! var k1: String!; var k2: String!; Flow() .sync { indicator.show(); started = now() } .async { sync in fetchKey1 { r in sync { key1 = r } } } .async { sync in fetchKey2 { r in sync { key2 = r) } } } .async { sync in fetch1(k1, k2) { r in sync { section1.render(with: r) } } } .async { sync in fetch2 { r in sync { section2.render(with: r) } } } .async { sync in fetch3 { r in sync { section3.render(with: r) } } } .pause(duration: { 2 - min(2, now() - started) }) { indicator.hide() } .start()
  70. 70. Flow - bundle Flow() .sync { indicator.show(); started = now() } .async { sync in fetchKey1 { r in sync { key1 = r } } } .async { sync in fetchKey2 { r in sync { key2 = r) } } } .sync { Flow() .async { sync in fetch1(k1, k2) { r in sync { section1.render(with: r) } } } … .start() } .start()
  71. 71. Flow - bundle Flow() .sync { indicator.show(); started = now() } .bundle { Flow().async { … }.async { … } } .async { sync in fetch1(k1, k2) { r in sync { section1.render(with: r) } } } .async { sync in fetch2 { r in sync { section2.render(with: r) } } } .async { sync in fetch3 { r in sync { section3.render(with: r) } } } .pause(duration: { 2 - min(2, now() - started) }) { indicator.hide() } .start()
  72. 72. Flow - bundle class Flow { private class Block { static let TypeBundle = “bundle" … } typealias Bundle = () -> Flow … @discardableResult func bundle(body: @escaping Bundle) -> Flow { blocks.append(Block(type: Block.TypeBundle, body: body)) return self } }
  73. 73. private func _start() { var sub: Flow? knitting: while blocks.count > 0 { let block = blocks.removeFirst() switch block.type { … case Block.TypeBundle: let body = block.body as! Bundle sub = body() break knitting default: break } } … }
  74. 74. private func _start() { var sub: Flow? … if let sub = sub { if blocks.count > 0 { sub.blocks.append( Flow.Block( type: Block.TypeBundle, body: { () -> Flow in self.seq = nil; return self } ) ) } if seq?.current != nil { seq?.current?.ended = { _ in sub._start() } } else { sub._start() } } }
  75. 75. Flow() .sync { indicator.show(); started = now() } .bundle { Flow() .async { sync in fetchKey1 { r in sync { k1 = r } } } .async { sync in fetchKey2 { r in sync { k2 = r } } } } .async { sync in fetch1(k1, k2) { r in sync { section1.render(with: r) } } } .async { sync in fetch2 { r in sync { section2.render(with: r) } } } .async { sync in fetch3 { r in sync { section3.render(with: r) } } } .pause(duration: { 2 - min(2, now() - started) }) { indicator.hide() } .start()
  76. 76. Flow() .sync { indicator.show(); started = now() } .bundle { Flow() .async { sync in fetchKey1 { r in sync { k1 = r } } } .async { sync in fetchKey2 { r in sync { k2 = r } } } } .async { sync in fetch1(k1, k2) { r in sync { section1.render(with: r) } } } .async { sync in fetch2 { r in sync { section2.render(with: r) } } } .async { sync in fetch3 { r in sync { section3.render(with: r) } } } .pause(duration: { 2 - min(2, now() - started) }) { indicator.hide() } .start() var flow1: Flow Flow() .sync { indicator.show(); started = now() } .bundle { Flow() .async { sync in fetchKey1 { r in sync { k1 = r } } } .async { sync in fetchKey2 { r in sync { k2 = r } } } } .async { sync in fetch1(k1, k2) { r in sync { section1.render(with: r) } } } .async { sync in fetch2 { r in sync { section2.render(with: r) } } } .async { sync in fetch3 { r in sync { section3.render(with: r) } } } .pause(duration: { 2 - min(2, now() - started) }) { indicator.hide() }
  77. 77. var flow1: Flow flow1 = Flow() flow1.sync { indicator.show(); started = now() } .bundle { Flow() .async { sync in fetchKey1 { r in sync { k1 = r } } } .async { sync in fetchKey2 { r in sync { k2 = r } } } } .async { sync in fetch1(k1, k2) { r in sync { section1.render(with: r) } } } .async { sync in fetch2 { r in sync { section2.render(with: r) } } } .async { sync in fetch3 { r in sync { section3.render(with: r) } } } .pause(duration: { 2 - min(2, now() - started) }) { indicator.hide() }
  78. 78. var flow1: Flow flow1 = Flow() flow1.sync { indicator.show(); started = now() } .bundle { Flow() .async { sync in fetchKey1 { r in sync { k1 = r } } } .async { sync in fetchKey2 { r in sync { k2 = r } } } .bundle { flow1 } } .async { sync in fetch1(k1, k2) { r in sync { section1.render(with: r) } } } .async { sync in fetch2 { r in sync { section2.render(with: r) } } } .async { sync in fetch3 { r in sync { section3.render(with: r) } } } .pause(duration: { 2 - min(2, now() - started) }) { indicator.hide() }
  79. 79. var flow1: Flow flow1 = Flow() flow1.sync { indicator.show(); started = now() } .bundle { Flow() .async { sync in fetchKey1 { r in sync { k1 = r } } } .async { sync in fetchKey2 { r in sync { k2 = r } } } .bundle { flow1 .async { sync in fetch1(k1, k2) { r in sync { section1.render(with: r) } } } .async { sync in fetch2 { r in sync { section2.render(with: r) } } } .async { sync in fetch3 { r in sync { section3.render(with: r) } } } .pause(duration: { 2 - min(2, now() - started) }) { indicator.hide() } } }
  80. 80. var flow1: Flow flow1 = Flow() flow1.sync { indicator.show(); started = now() } Flow() .async { sync in fetchKey1 { r in sync { k1 = r } } } .async { sync in fetchKey2 { r in sync { k2 = r } } } .bundle { flow1 .async { sync in fetch1(k1, k2) { r in sync { section1.render(with: r) } } } .async { sync in fetch2 { r in sync { section2.render(with: r) } } } .async { sync in fetch3 { r in sync { section3.render(with: r) } } } .pause(duration: { 2 - min(2, now() - started) }) { indicator.hide() } }
  81. 81. var flow1: Flow flow1 = Flow() flow1.sync { indicator.show(); started = now() Flow() .async { sync in fetchKey1 { r in sync { k1 = r } } } .async { sync in fetchKey2 { r in sync { k2 = r } } } .bundle { flow1 .async { sync in fetch1(k1, k2) { r in sync { section1.render(with: r) } } } .async { sync in fetch2 { r in sync { section2.render(with: r) } } } .async { sync in fetch3 { r in sync { section3.render(with: r) } } } .pause(duration: { 2 - min(2, now() - started) }) { indicator.hide() } } .start() }
  82. 82. var flow1: Flow flow1 = Flow() flow1.sync { indicator.show(); started = now() Flow() .async { sync in fetchKey1 { r in sync { k1 = r } } } .async { sync in fetchKey2 { r in sync { k2 = r } } } .bundle { flow1 .async { sync in fetch1(k1, k2) { r in sync { section1.render(with: r) } } } .async { sync in fetch2 { r in sync { section2.render(with: r) } } } .async { sync in fetch3 { r in sync { section3.render(with: r) } } } .pause(duration: { 2 - min(2, now() - started) }) { indicator.hide() } } .start() }
  83. 83. var flow1: Flow flow1 = Flow() flow1.sync { indicator.show(); started = now() Flow() .async { sync in fetchKey1 { r in sync { k1 = r } } } .async { sync in fetchKey2 { r in sync { k2 = r } } } .bundle { flow1 .async { sync in fetch1(k1, k2) { r in sync { section1.render(with: r) } } } .async { sync in fetch2 { r in sync { section2.render(with: r) } } } .async { sync in fetch3 { r in sync { section3.render(with: r) } } } .pause(duration: { 2 - min(2, now() - started) }) { indicator.hide() } } .start() }
  84. 84. var flow1: Flow flow1 = Flow() Flow() .async { sync in fetchKey1 { r in sync { k1 = r } } } .async { sync in fetchKey2 { r in sync { k2 = r } } } .bundle { flow1 .async { sync in fetch1(k1, k2) { r in sync { section1.render(with: r) } } } .async { sync in fetch2 { r in sync { section2.render(with: r) } } } .async { sync in fetch3 { r in sync { section3.render(with: r) } } } .pause(duration: { 2 - min(2, now() - started) }) { indicator.hide() } }
  85. 85. var flow1: Flow flow1 = Flow() Flow() .async { sync in fetchKey1 { r in sync { k1 = r } } } .async { sync in fetchKey2 { r in sync { k2 = r } } } .bundle { flow1 .async { sync in fetch1(k1, k2) { r in sync { section1.render(with: r) } } } .async { sync in fetch2 { r in sync { section2.render(with: r) } } } .async { sync in fetch3 { r in sync { section3.render(with: r) } } } .pause(duration: { 2 - min(2, now() - started) }) { indicator.hide() } }
  86. 86. var flow1: Flow flow1 = Flow() Flow() .async { sync in fetchKey1 { r in sync { k1 = r } } } .async { sync in fetchKey2 { r in sync { k2 = r } } } flow1 .async { sync in fetch1(k1, k2) { r in sync { section1.render(with: r) } } } .async { sync in fetch2 { r in sync { section2.render(with: r) } } } .async { sync in fetch3 { r in sync { section3.render(with: r) } } } .pause(duration: { 2 - min(2, now() - started) }) { indicator.hide() }
  87. 87. Flow() .async { sync in fetchKey1 { r in sync { k1 = r } } } .async { sync in fetchKey2 { r in sync { k2 = r flow1 .async { sync in fetch1(k1, k2) { r in sync { section1.render(with: r) } } } .async { sync in fetch2 { r in sync { section2.render(with: r) } } } .async { sync in fetch3 { r in sync { section3.render(with: r) } } } .pause(duration: { 2 - min(2, now() - started) }) { indicator.hide() } .start() } } }
  88. 88. private func _start() { var sub: Flow? … if let sub = sub { if blocks.count > 0 { sub.blocks.append( Flow.Block( type: Block.TypeBundle, body: { () -> Flow in self.seq = nil; return self } ) ) } if seq?.current != nil { seq?.current?.ended = { _ in sub._start() } } else { sub._start() } } }
  89. 89. Flow() .sync { indicator.show(); started = now() } .bundle { Flow() .async { sync in fetchKey1 { r in sync { k1 = r } } } .async { sync in fetchKey2 { r in sync { k2 = r } } } } .async { sync in fetch1(k1, k2) { r in sync { section1.render(with: r) } } } .async { sync in fetch2 { r in sync { section2.render(with: r) } } } .async { sync in fetch3 { r in sync { section3.render(with: r) } } } .pause(duration: { 2 - min(2, now() - started) }) { indicator.hide() } .start()
  90. 90. Q&A

×