SlideShare ist ein Scribd-Unternehmen logo
1 von 36
Downloaden Sie, um offline zu lesen
.(
) . ..)
!
Disk Defragment
Code Defragment
→ →
Advantages
EASY to UNDERSTAND
READ
FOLLOW
FIND
MAINTENANCE
Goal
→
NO FREE LUNCH
CASE STUDY
CASE #1. Data + Logic + UI
class ViewController: UIViewController {
@IBOutlet var number1: UILabel!
@IBOutlet var number2: UILabel!
@IBOutlet var result: UILabel!
struct CalcData {
let num1: Int
let num2: Int
}
private func textToInt(_ text: String?) -> Int {
guard let text = text else { return 0 }
return Int(text) ?? 0
}
@IBAction func calcResult(_ sender: Any) {
let n1 = textToInt(number1.text)
let n2 = textToInt(number2.text)
let data = CalcData(num1: n1, num2: n2)
let res = calcPlus(data)
result.text = intToText(res)
}
private func intToText(_ num: Int) -> String {
return "(num)"
}
private func calcPlus(_ data: CalcData) -> Int {
return data.num1 + data.num2
}
}
❓
CASE #1. Data + Logic + UI
class ViewController: UIViewController {
// MARK: - DATA
struct CalcData {
let num1: Int
let num2: Int
}
// MARK: - LOGIC
private func textToInt(_ text: String?) -> Int {
guard let text = text else { return 0 }
return Int(text) ?? 0
}
private func intToText(_ num: Int) -> String {
return "(num)"
}
private func calcPlus(_ data: CalcData) -> Int {
return data.num1 + data.num2
}
// MARK: - UI
@IBOutlet var number1: UILabel!
@IBOutlet var number2: UILabel!
@IBOutlet var result: UILabel!
@IBAction func calcResult(_ sender: Any) {
let n1 = textToInt(number1.text)
let n2 = textToInt(number2.text)
let data = CalcData(num1: n1, num2: n2)
let res = calcPlus(data)
result.text = intToText(res)
}
}
❗
CASE #2. Data Setter ❓
class ViewController: UIViewController {
@IBOutlet var textLabel: UILabel!
var count: Int = 0
@IBAction func addOne() {
count += 1
textLabel.text = "(count)"
}
@IBAction func subOne() {
count -= 1
textLabel.text = "(count)" // duplicated
}
}
CASE #2. Data Setter ❗
class ViewController: UIViewController {
@IBOutlet var textLabel: UILabel!
var count: Int = 0 {
didSet {
textLabel.text = "(count)"
}
}
@IBAction func addOne() {
count += 1
}
@IBAction func subOne() {
count -= 1
}
}
CASE #3. Overrides
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupNavigationBar()
}
func setupNavigationBar() {
self.navigationController?.title = "App Title"
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.setNavigationBarHidden(false, animated: animated)
//Other Codes
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.navigationController?.setNavigationBarHidden(true, animated: animated)
//Other Codes
}
}
❓
class BaseViewController: UIViewController {
var viewWillAppearActions: [(Bool) -> ()] = []
var viewWillDisappearActions: [(Bool) -> ()] = []
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
viewWillAppearActions.forEach({ $0(animated) })
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
viewWillDisappearActions.forEach({ $0(animated) })
}
}
class ViewController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupNavigationBar()
}
func setupNavigationBar() {
self.navigationController?.title = "App Title"
viewWillAppearActions.append({ [weak self] anim in
self?.navigationController?.setNavigationBarHidden(false, animated: anim)
})
viewWillDisappearActions.append({ [weak self] anim in
self?.navigationController?.setNavigationBarHidden(true, animated: anim)
})
}
}
❗CASE #3. Overrides
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupKeyboardEvent()
}
func setupKeyboardEvent() {
NotificationCenter.default.addObserver(self,
selector: #selector(onKeyboardWillShow),
name: .UIKeyboardWillShow,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(onKeyboardWillHide),
name: .UIKeyboardWillHide,
object: nil)
}
@objc func onKeyboardWillShow(notification: Notification) {
print("Keyboard will show")
}
@objc func onKeyboardWillHide(notification: Notification) {
print("Keyboard will hide")
}
}
CASE #4. Selector ❓
class KeyboardEventWrapper {
var onKeyboardWillShowCallBack: (Notification) -> () = { _ in }
init() {
NotificationCenter.default.addObserver(self,
selector: #selector(onKeyboardWillShow),
name: .UIKeyboardWillShow,
object: nil)
}
@objc func onKeyboardWillShow(notification: Notification) {
onKeyboardWillShowCallBack(notification)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
}
class ViewController: UIViewController {
var keyboardEventWrapper: KeyboardEventWrapper!
override func viewDidLoad() {
super.viewDidLoad()
setupKeyboardEvent()
}
func setupKeyboardEvent() {
keyboardEventWrapper = KeyboardEventWrapper()
keyboardEventWrapper.onKeyboardWillShowCallBack = { _ in
print("Keyboard will show")
}
}
}
❗CASE #4. Selector
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate
{
@IBAction func onLoadImage() {
let picker = UIImagePickerController()
picker.delegate = self
present(picker, animated: true, completion: nil)
}
// MARK: - UIImagePickerControllerDelegate
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [String: Any]) {
let originalInfo = info[UIImagePickerControllerOriginalImage]
guard let originalImage = originalInfo as? UIImage else { return }
// ...
picker.dismiss(animated: true, completion: nil)
}
}
CASE #5. Delegate ❓
class ImagePickerWrapper: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var onImagePicked: (UIImage?) -> () = { _ in }
func showImagePicker(on vc: UIViewController) {
let picker = UIImagePickerController()
picker.delegate = self
vc.present(picker, animated: true, completion: nil)
}
// MARK: - UIImagePickerControllerDelegate
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [String: Any]) {
let originalInfo = info[UIImagePickerControllerOriginalImage]
guard let originalImage = originalInfo as? UIImage else { return }
onImagePicked(originalImage)
picker.dismiss(animated: true, completion: nil)
}
}
class ViewController: UIViewController {
var imagePicker: ImagePickerWrapper!
@IBAction func onLoadImage() {
imagePicker = ImagePickerWrapper()
imagePicker.showImagePicker(on: self)
imagePicker.onImagePicked = { image in
guard let image = image else { return }
// ...
}
}
}
❗CASE #5. Delegate
ELEGANT WAY
feat. RxSwift
CASE #1. Data + Logic + UI
struct CalcData {
let num1: Int
let num2: Int
}
func textToInt(_ text: String?) -> Int {
guard let text = text else { return 0 }
return Int(text) ?? 0
}
func intToText(_ num: Int) -> String {
return "(num)"
}
func calcPlus(_ data: CalcData) -> Int {
return data.num1 + data.num2
}
class ViewController: UIViewController {
@IBOutlet var number1: UILabel!
@IBOutlet var number2: UILabel!
@IBOutlet var result: UILabel!
@IBAction func calcResult(_ sender: Any) {
let n1 = textToInt(number1.text)
let n2 = textToInt(number2.text)
let data = CalcData(num1: n1, num2: n2)
let res = calcPlus(data)
result.text = intToText(res)
}
}
Model.swift
Context.swift
ViewController.swift
❗❗
CASE #2. Data Setter
import RxSwift
import RxCocoa
// Common Functions
let intToText = { (i: Int) in "(i)" }
///
class ViewController: UIViewController {
@IBOutlet var textLabel: UILabel!
let disposeBag = DisposeBag()
let count = BehaviorRelay<Int>(value: 0)
override func viewDidLoad() {
super.viewDidLoad()
count.map(intToText)
.bind(to: textLabel.rx.text)
.disposed(by: disposeBag)
}
@IBAction func addOne() {
count.accept(count.value + 1)
}
@IBAction func subOne() {
count.accept(count.value - 1)
}
}
❗❗
CASE #2. Data Setter
import RxSwift
import RxCocoa
// Common Functions
let intToText = { (i: Int) in "(i)" }
///
class ViewController: UIViewController {
@IBOutlet var textLabel: UILabel!
@IBOutlet var textLabelx10: UILabel!
let disposeBag = DisposeBag()
let count = BehaviorRelay<Int>(value: 0)
override func viewDidLoad() {
super.viewDidLoad()
count.map(intToText)
.bind(to: textLabel.rx.text)
.disposed(by: disposeBag)
count.map({ $0 * 10 })
.map(intToText)
.bind(to: textLabelx10.rx.text)
.disposed(by: disposeBag)
}
@IBAction func addOne() {
count.accept(count.value + 1)
}
@IBAction func subOne() {
count.accept(count.value - 1)
}
}
❗❗
import RxSwift
import RxCocoa
import RxViewController // <==
class ViewController: UIViewController {
let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
setupNavigationBar()
}
func setupNavigationBar() {
self.navigationController?.title = "App Title"
self.rx.viewWillAppear.subscribe(onNext: { [weak self] anim in
self?.navigationController?.setNavigationBarHidden(false, animated: anim)
}).disposed(by: disposeBag)
self.rx.viewWillDisappear.subscribe(onNext: { [weak self] anim in
self?.navigationController?.setNavigationBarHidden(true, animated: anim)
}).disposed(by: disposeBag)
}
}
CASE #3. Overrides ❗❗
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
setupKeyboardEvent()
}
func setupKeyboardEvent() {
NotificationCenter.default.rx.notification(.UIKeyboardWillShow)
.subscribe(onNext: { notifiaction in
print("Keyboard will show")
})
.disposed(by: disposeBag)
NotificationCenter.default.rx.notification(.UIKeyboardWillHide)
.subscribe(onNext: { notifiaction in
print("Keyboard will hide")
})
.disposed(by: disposeBag)
}
}
CASE #4. Selector ❗❗
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
let disposeBag = DisposeBag()
@IBOutlet weak var imageView: UIImageView!
@IBAction func onLoadImage() {
let picker = UIImagePickerController()
present(picker, animated: true, completion: nil)
picker.rx.didFinishPickingMediaWithInfo
.map({ info -> UIImage? in
info[UIImagePickerControllerOriginalImage] as? UIImage
})
.bind(to: imageView.rx.image)
.disposed(by: disposeBag)
}
}
CASE #5. Delegate ❗❗
// MARK:- UIImagePickerController.rx
// picker.rx.didFinishPickingMediaWithInfo
// ~~~~~~ ~~
// Base Reactive
extension Reactive where Base: UIImagePickerController {
public var didFinishPickingMediaWithInfo: Observable<[String : Any]> {
return RxImagePickerProxy.proxy(for: base)
.didFinishPickingMediaWithInfoSubject
.asObservable()
.do(onCompleted: {
self.base.dismiss(animated: true, completion: nil)
})
}
public var didCancel: Observable<Void> {
return RxImagePickerProxy.proxy(for: base)
.didCancelSubject
.asObservable()
.do(onCompleted: {
self.base.dismiss(animated: true, completion: nil)
})
}
}
CASE #5. Delegate ❗❗
import UIKit
import RxSwift
import RxCocoa
public typealias ImagePickerDelegate = UIImagePickerControllerDelegate & UINavigationControllerDelegate
extension UIImagePickerController: HasDelegate {
public typealias Delegate = ImagePickerDelegate
}
class RxImagePickerProxy: DelegateProxy<UIImagePickerController, ImagePickerDelegate>,
DelegateProxyType, UIImagePickerControllerDelegate, UINavigationControllerDelegate
{
public init(imagePicker: UIImagePickerController) {
super.init(parentObject: imagePicker, delegateProxy: RxImagePickerProxy.self)
}
//MARK:- DelegateProxyType
public static func registerKnownImplementations() {
self.register { RxImagePickerProxy(imagePicker: $0) }
}
static func currentDelegate(for object: UIImagePickerController) -> ImagePickerDelegate? {
return object.delegate
}
static func setCurrentDelegate(_ delegate: ImagePickerDelegate?, to object: UIImagePickerController)
{
object.delegate = delegate
}
//MARK:- Proxy Subject
//MARK:- UIImagePickerControllerDelegate
//MARK:- Completed
}
CASE #5. Delegate ❗❗
class RxImagePickerProxy: DelegateProxy<UIImagePickerController, ImagePickerDelegate>,
DelegateProxyType, UIImagePickerControllerDelegate, UINavigationControllerDelegate
{
//MARK:- DelegateProxyType
//MARK:- Proxy Subject
internal lazy var didFinishPickingMediaWithInfoSubject = PublishSubject<[String : Any]>()
internal lazy var didCancelSubject = PublishSubject<Void>()
//MARK:- UIImagePickerControllerDelegate
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [String: Any]) {
didFinishPickingMediaWithInfoSubject.onNext(info)
didFinishPickingMediaWithInfoSubject.onCompleted()
didCancelSubject.onCompleted()
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
didCancelSubject.onNext(())
didCancelSubject.onCompleted()
didFinishPickingMediaWithInfoSubject.onCompleted()
}
//MARK:- Completed
deinit {
self.didFinishPickingMediaWithInfoSubject.onCompleted()
self.didCancelSubject.onCompleted()
}
}
CASE #5. Delegate ❗❗
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
let disposeBag = DisposeBag()
@IBOutlet weak var imageView: UIImageView!
@IBAction func onLoadImage() {
let picker = UIImagePickerController()
present(picker, animated: true, completion: nil)
picker.rx.didFinishPickingMediaWithInfo
.map({ info -> UIImage? in
info[UIImagePickerControllerOriginalImage] as? UIImage
})
.bind(to: imageView.rx.image)
.disposed(by: disposeBag)
}
}
CASE #5. Delegate ❗❗
ALL TOGETHER
SUMMARY
UI
Model.swift
struct CalcData {
let n1: Int?
let n2: Int?
let result: Int?
}
extension CalcData {
static func empty() -> CalcData {
return CalcData(n1: nil, n2: nil, result: nil)
}
}
Context.swift (Business Logic)
let i2s = { (i: Int?) in "(i ?? 0)" }
let s2i = { (s: String?) in Int(s ?? "0") }
class Context {
let model = BehaviorRelay<CalcData>(value: CalcData.empty())
func doCalc(data: CalcData) -> CalcData {
guard let n1 = data.n1 else { return data }
guard let n2 = data.n2 else { return data }
let result = n1 + n2
return CalcData(n1: n1, n2: n2, result: result)
}
}
ViewController.swift
class ViewController: UIViewController {
@IBOutlet weak var n1Field: UITextField! // Input
@IBOutlet weak var n2Field: UITextField! // Input
@IBOutlet weak var resultLabel: UILabel! // Output
@IBOutlet weak var calcButton: UIButton! // Event
let context = Context()
let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
bindUI()
bindEvent()
}
func bindUI() {
// ...
}
func bindEvent() {
// …
}
}
ViewController.swift
class ViewController: UIViewController {
func bindUI() {
//n1 input
n1Field.rx.text.map(s2i)
.withLatestFrom(context.model) { (n1, dat) in
CalcData(n1: n1, n2: dat.n2, result: dat.result)
}
.bind(to: context.model)
.disposed(by: disposeBag)
//n2 input
n2Field.rx.text.map(s2i)
.withLatestFrom(context.model) { (n2, dat) in
CalcData(n1: dat.n1, n2: n2, result: dat.result)
}
.bind(to: context.model)
.disposed(by: disposeBag)
//result output
viewModel.model.map({ $0.result })
.map(i2s)
.bind(to: resultLabel.rx.text)
.disposed(by: disposeBag)
}
func bindEvent() {
//event
calcButton.rx.tap
.withLatestFrom(context.model)
.map(context.doCalc)
.bind(to: context.model)
.disposed(by: disposeBag)
}
}
Summary
class ViewController: UIViewController {
@IBOutlet weak var n1Field: UITextField! // Input
@IBOutlet weak var n2Field: UITextField! // Input
@IBOutlet weak var resultLabel: UILabel! // Output
@IBOutlet weak var calcButton: UIButton! // Event
let context = Context()
let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
bindUI()
bindEvent()
}
func bindUI() {
//n1 input
n1Field.rx.text.map(s2i)
.withLatestFrom(context.model) { (n1, dat) in
CalcData(n1: n1, n2: dat.n2, result: dat.result)
}
.bind(to: context.model)
.disposed(by: disposeBag)
//n2 input
n2Field.rx.text.map(s2i)
.withLatestFrom(context.model) { (n2, dat) in
CalcData(n1: dat.n1, n2: n2, result: dat.result)
}
.bind(to: context.model)
.disposed(by: disposeBag)
//result output
viewModel.model.map({ $0.result })
.map(i2s)
.bind(to: resultLabel.rx.text)
.disposed(by: disposeBag)
}
func bindEvent() {
//event
calcButton.rx.tap
.withLatestFrom(context.model)
.map(context.doCalc)
.bind(to: context.model)
.disposed(by: disposeBag)
}
}
struct CalcData {
let n1: Int?
let n2: Int?
let result: Int?
}
extension CalcData {
static func empty() -> CalcData {
return CalcData(n1: nil, n2: nil, result: nil)
}
}
View
ViewController
Context
Model
let i2s = { (i: Int?) in "(i ?? 0)" }
let s2i = { (s: String?) in Int(s ?? "0") }
class Context {
let model = BehaviorRelay<CalcData>(value: CalcData.empty())
func doCalc(data: CalcData) -> CalcData {
guard let n1 = data.n1 else { return data }
guard let n2 = data.n2 else { return data }
let result = n1 + n2
return CalcData(n1: n1, n2: n2, result: result)
}
}
struct CalcData {
let n1: Int?
let n2: Int?
let result: Int?
}
extension CalcData {
static func empty() -> CalcData {
return CalcData(n1: nil, n2: nil, result: nil)
}
}
View
ViewController
Context
Model
ViewModel
Summary
class ViewController: UIViewController {
@IBOutlet weak var n1Field: UITextField! // Input
@IBOutlet weak var n2Field: UITextField! // Input
@IBOutlet weak var resultLabel: UILabel! // Output
@IBOutlet weak var calcButton: UIButton! // Event
let viewModel = ViewModel()
let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
bindUI()
bindEvent()
}
func bindUI() {
//n1 input
n1Field.rx.text.map(s2i)
.withLatestFrom(viewModel.model) { (n1, dat) in
CalcData(n1: n1, n2: dat.n2, result: dat.result)
}
.bind(to: viewModel.model)
.disposed(by: disposeBag)
//n2 input
n2Field.rx.text.map(s2i)
.withLatestFrom(viewModel.model) { (n2, dat) in
CalcData(n1: dat.n1, n2: n2, result: dat.result)
}
.bind(to: viewModel.model)
.disposed(by: disposeBag)
//result output
viewModel.model.map({ $0.result })
.map(i2s)
.bind(to: resultLabel.rx.text)
.disposed(by: disposeBag)
}
func bindEvent() {
//event
calcButton.rx.tap
.withLatestFrom(viewModel.model)
.map(viewModel.doCalc)
.bind(to: viewModel.model)
.disposed(by: disposeBag)
}
}
let i2s = { (i: Int?) in "(i ?? 0)" }
let s2i = { (s: String?) in Int(s ?? "0") }
class ViewModel {
let model = BehaviorRelay<CalcData>(value: CalcData.empty())
func doCalc(data: CalcData) -> CalcData {
guard let n1 = data.n1 else { return data }
guard let n2 = data.n2 else { return data }
let result = n1 + n2
return CalcData(n1: n1, n2: n2, result: result)
}
}
20180721 code defragment

Weitere ähnliche Inhalte

Was ist angesagt?

Effective Spring Transaction Management
Effective Spring Transaction ManagementEffective Spring Transaction Management
Effective Spring Transaction Management
UMA MAHESWARI
 
[CB21] The Lazarus Group's Attack Operations Targeting Japan by Shusei Tomona...
[CB21] The Lazarus Group's Attack Operations Targeting Japan by Shusei Tomona...[CB21] The Lazarus Group's Attack Operations Targeting Japan by Shusei Tomona...
[CB21] The Lazarus Group's Attack Operations Targeting Japan by Shusei Tomona...
CODE BLUE
 
Clean Architecture A Craftsman’s Guide to Software Structure and Design by Ro...
Clean Architecture A Craftsman’s Guide to Software Structure and Design by Ro...Clean Architecture A Craftsman’s Guide to Software Structure and Design by Ro...
Clean Architecture A Craftsman’s Guide to Software Structure and Design by Ro...
HbBazan
 

Was ist angesagt? (20)

Escaping the python sandbox
Escaping the python sandboxEscaping the python sandbox
Escaping the python sandbox
 
Effective Spring Transaction Management
Effective Spring Transaction ManagementEffective Spring Transaction Management
Effective Spring Transaction Management
 
Hunting for Credentials Dumping in Windows Environment
Hunting for Credentials Dumping in Windows EnvironmentHunting for Credentials Dumping in Windows Environment
Hunting for Credentials Dumping in Windows Environment
 
ReactorKit으로 단방향 반응형 앱 만들기
ReactorKit으로 단방향 반응형 앱 만들기ReactorKit으로 단방향 반응형 앱 만들기
ReactorKit으로 단방향 반응형 앱 만들기
 
Hacking tutorial
Hacking tutorialHacking tutorial
Hacking tutorial
 
RxSwift Testing 같이 시작하기 feat. RxBlocking, RxTest
RxSwift Testing 같이 시작하기 feat. RxBlocking, RxTestRxSwift Testing 같이 시작하기 feat. RxBlocking, RxTest
RxSwift Testing 같이 시작하기 feat. RxBlocking, RxTest
 
Windows attacks - AT is the new black
Windows attacks - AT is the new blackWindows attacks - AT is the new black
Windows attacks - AT is the new black
 
[CB21] The Lazarus Group's Attack Operations Targeting Japan by Shusei Tomona...
[CB21] The Lazarus Group's Attack Operations Targeting Japan by Shusei Tomona...[CB21] The Lazarus Group's Attack Operations Targeting Japan by Shusei Tomona...
[CB21] The Lazarus Group's Attack Operations Targeting Japan by Shusei Tomona...
 
Node.js 기본
Node.js 기본Node.js 기본
Node.js 기본
 
Functional Patterns with Java8 @Bucharest Java User Group
Functional Patterns with Java8 @Bucharest Java User GroupFunctional Patterns with Java8 @Bucharest Java User Group
Functional Patterns with Java8 @Bucharest Java User Group
 
Log Analysis
Log AnalysisLog Analysis
Log Analysis
 
Polyglot payloads in practice by avlidienbrunn at HackPra
Polyglot payloads in practice by avlidienbrunn at HackPraPolyglot payloads in practice by avlidienbrunn at HackPra
Polyglot payloads in practice by avlidienbrunn at HackPra
 
Clean Architecture A Craftsman’s Guide to Software Structure and Design by Ro...
Clean Architecture A Craftsman’s Guide to Software Structure and Design by Ro...Clean Architecture A Craftsman’s Guide to Software Structure and Design by Ro...
Clean Architecture A Craftsman’s Guide to Software Structure and Design by Ro...
 
Constructor and Destructor in c++
Constructor  and Destructor in c++Constructor  and Destructor in c++
Constructor and Destructor in c++
 
A Threat Hunter Himself
A Threat Hunter HimselfA Threat Hunter Himself
A Threat Hunter Himself
 
XXE - XML External Entity Attack
XXE - XML External Entity Attack	XXE - XML External Entity Attack
XXE - XML External Entity Attack
 
RACE - Minimal Rights and ACE for Active Directory Dominance
RACE - Minimal Rights and ACE for Active Directory DominanceRACE - Minimal Rights and ACE for Active Directory Dominance
RACE - Minimal Rights and ACE for Active Directory Dominance
 
iOS Application Pentesting
iOS Application PentestingiOS Application Pentesting
iOS Application Pentesting
 
Threat Hunting
Threat HuntingThreat Hunting
Threat Hunting
 
Attack and Mitigation for Insecure Deserialization
Attack and Mitigation for Insecure DeserializationAttack and Mitigation for Insecure Deserialization
Attack and Mitigation for Insecure Deserialization
 

Ähnlich wie 20180721 code defragment

ViewController.swift Calculatorimport Cocoaimport UIKit.pdf
 ViewController.swift Calculatorimport Cocoaimport UIKit.pdf ViewController.swift Calculatorimport Cocoaimport UIKit.pdf
ViewController.swift Calculatorimport Cocoaimport UIKit.pdf
arasanlethers
 

Ähnlich wie 20180721 code defragment (20)

That’s My App - Running in Your Background - Draining Your Battery
That’s My App - Running in Your Background - Draining Your BatteryThat’s My App - Running in Your Background - Draining Your Battery
That’s My App - Running in Your Background - Draining Your Battery
 
ViewController.swift Calculatorimport Cocoaimport UIKit.pdf
 ViewController.swift Calculatorimport Cocoaimport UIKit.pdf ViewController.swift Calculatorimport Cocoaimport UIKit.pdf
ViewController.swift Calculatorimport Cocoaimport UIKit.pdf
 
Adopting 3D Touch in your apps
Adopting 3D Touch in your appsAdopting 3D Touch in your apps
Adopting 3D Touch in your apps
 
What's new in iOS9
What's new in iOS9What's new in iOS9
What's new in iOS9
 
iOS
iOSiOS
iOS
 
How to become an Android dev starting from iOS (and vice versa)
How to become an Android dev starting from iOS (and vice versa)How to become an Android dev starting from iOS (and vice versa)
How to become an Android dev starting from iOS (and vice versa)
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modeling
 
Get the Most Out of iOS 11 with Visual Studio Tools for Xamarin
Get the Most Out of iOS 11 with Visual Studio Tools for XamarinGet the Most Out of iOS 11 with Visual Studio Tools for Xamarin
Get the Most Out of iOS 11 with Visual Studio Tools for Xamarin
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modeling
 
Advancing the UI — Part 1: Look, Motion, and Gestures
Advancing the UI — Part 1: Look, Motion, and GesturesAdvancing the UI — Part 1: Look, Motion, and Gestures
Advancing the UI — Part 1: Look, Motion, and Gestures
 
303 TANSTAAFL: Using Open Source iPhone UI Code
303 TANSTAAFL: Using Open Source iPhone UI Code303 TANSTAAFL: Using Open Source iPhone UI Code
303 TANSTAAFL: Using Open Source iPhone UI Code
 
Blending Culture in Twitter Client
Blending Culture in Twitter ClientBlending Culture in Twitter Client
Blending Culture in Twitter Client
 
Writing Maintainable JavaScript
Writing Maintainable JavaScriptWriting Maintainable JavaScript
Writing Maintainable JavaScript
 
Scala on Your Phone
Scala on Your PhoneScala on Your Phone
Scala on Your Phone
 
The zen of async: Best practices for best performance
The zen of async: Best practices for best performanceThe zen of async: Best practices for best performance
The zen of async: Best practices for best performance
 
Introduction to kotlin
Introduction to kotlinIntroduction to kotlin
Introduction to kotlin
 
Android workshop
Android workshopAndroid workshop
Android workshop
 
Object-Oriented JavaScript
Object-Oriented JavaScriptObject-Oriented JavaScript
Object-Oriented JavaScript
 
Object-Oriented Javascript
Object-Oriented JavascriptObject-Oriented Javascript
Object-Oriented Javascript
 
Swift ui userinput
Swift ui userinputSwift ui userinput
Swift ui userinput
 

Mehr von Chiwon Song

Mehr von Chiwon Song (20)

20240330_고급진 코드를 위한 exception 다루기
20240330_고급진 코드를 위한 exception 다루기20240330_고급진 코드를 위한 exception 다루기
20240330_고급진 코드를 위한 exception 다루기
 
요즘 유행하는 AI 나도 해보자 (feat. CoreML)
요즘 유행하는 AI 나도 해보자 (feat. CoreML)요즘 유행하는 AI 나도 해보자 (feat. CoreML)
요즘 유행하는 AI 나도 해보자 (feat. CoreML)
 
20210812 컴퓨터는 어떻게 동작하는가?
20210812 컴퓨터는 어떻게 동작하는가?20210812 컴퓨터는 어떻게 동작하는가?
20210812 컴퓨터는 어떻게 동작하는가?
 
20201121 코드 삼분지계
20201121 코드 삼분지계20201121 코드 삼분지계
20201121 코드 삼분지계
 
20200815 inversions
20200815 inversions20200815 inversions
20200815 inversions
 
20191116 custom operators in swift
20191116 custom operators in swift20191116 custom operators in swift
20191116 custom operators in swift
 
[20190601] 직업훈련교사_수업의실행_교안
[20190601] 직업훈련교사_수업의실행_교안[20190601] 직업훈련교사_수업의실행_교안
[20190601] 직업훈련교사_수업의실행_교안
 
[20190601] 직업훈련교사_수업의실행
[20190601] 직업훈련교사_수업의실행[20190601] 직업훈련교사_수업의실행
[20190601] 직업훈련교사_수업의실행
 
20190330 immutable data
20190330 immutable data20190330 immutable data
20190330 immutable data
 
20190306 만들면서 배우는 IoT / IoT의 이해
20190306 만들면서 배우는 IoT / IoT의 이해20190306 만들면서 배우는 IoT / IoT의 이해
20190306 만들면서 배우는 IoT / IoT의 이해
 
20181020 advanced higher-order function
20181020 advanced higher-order function20181020 advanced higher-order function
20181020 advanced higher-order function
 
20180310 functional programming
20180310 functional programming20180310 functional programming
20180310 functional programming
 
20171104 FRP 패러다임
20171104 FRP 패러다임20171104 FRP 패러다임
20171104 FRP 패러다임
 
스크래치로 시작하는 코딩
스크래치로 시작하는 코딩스크래치로 시작하는 코딩
스크래치로 시작하는 코딩
 
메이커운동과 아두이노
메이커운동과 아두이노메이커운동과 아두이노
메이커운동과 아두이노
 
아두이노 RC카 만들기
아두이노 RC카 만들기아두이노 RC카 만들기
아두이노 RC카 만들기
 
[5] 아두이노로 만드는 IoT
[5] 아두이노로 만드는 IoT[5] 아두이노로 만드는 IoT
[5] 아두이노로 만드는 IoT
 
[4] 아두이노와 인터넷
[4] 아두이노와 인터넷[4] 아두이노와 인터넷
[4] 아두이노와 인터넷
 
[2] 아두이노 활용 실습
[2] 아두이노 활용 실습[2] 아두이노 활용 실습
[2] 아두이노 활용 실습
 
[3] 프로세싱과 아두이노
[3] 프로세싱과 아두이노[3] 프로세싱과 아두이노
[3] 프로세싱과 아두이노
 

Kürzlich hochgeladen

Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
panagenda
 

Kürzlich hochgeladen (20)

2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 

20180721 code defragment

  • 2. !
  • 7. CASE #1. Data + Logic + UI class ViewController: UIViewController { @IBOutlet var number1: UILabel! @IBOutlet var number2: UILabel! @IBOutlet var result: UILabel! struct CalcData { let num1: Int let num2: Int } private func textToInt(_ text: String?) -> Int { guard let text = text else { return 0 } return Int(text) ?? 0 } @IBAction func calcResult(_ sender: Any) { let n1 = textToInt(number1.text) let n2 = textToInt(number2.text) let data = CalcData(num1: n1, num2: n2) let res = calcPlus(data) result.text = intToText(res) } private func intToText(_ num: Int) -> String { return "(num)" } private func calcPlus(_ data: CalcData) -> Int { return data.num1 + data.num2 } } ❓
  • 8. CASE #1. Data + Logic + UI class ViewController: UIViewController { // MARK: - DATA struct CalcData { let num1: Int let num2: Int } // MARK: - LOGIC private func textToInt(_ text: String?) -> Int { guard let text = text else { return 0 } return Int(text) ?? 0 } private func intToText(_ num: Int) -> String { return "(num)" } private func calcPlus(_ data: CalcData) -> Int { return data.num1 + data.num2 } // MARK: - UI @IBOutlet var number1: UILabel! @IBOutlet var number2: UILabel! @IBOutlet var result: UILabel! @IBAction func calcResult(_ sender: Any) { let n1 = textToInt(number1.text) let n2 = textToInt(number2.text) let data = CalcData(num1: n1, num2: n2) let res = calcPlus(data) result.text = intToText(res) } } ❗
  • 9. CASE #2. Data Setter ❓ class ViewController: UIViewController { @IBOutlet var textLabel: UILabel! var count: Int = 0 @IBAction func addOne() { count += 1 textLabel.text = "(count)" } @IBAction func subOne() { count -= 1 textLabel.text = "(count)" // duplicated } }
  • 10. CASE #2. Data Setter ❗ class ViewController: UIViewController { @IBOutlet var textLabel: UILabel! var count: Int = 0 { didSet { textLabel.text = "(count)" } } @IBAction func addOne() { count += 1 } @IBAction func subOne() { count -= 1 } }
  • 11. CASE #3. Overrides class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() setupNavigationBar() } func setupNavigationBar() { self.navigationController?.title = "App Title" } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) self.navigationController?.setNavigationBarHidden(false, animated: animated) //Other Codes } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) self.navigationController?.setNavigationBarHidden(true, animated: animated) //Other Codes } } ❓
  • 12. class BaseViewController: UIViewController { var viewWillAppearActions: [(Bool) -> ()] = [] var viewWillDisappearActions: [(Bool) -> ()] = [] override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) viewWillAppearActions.forEach({ $0(animated) }) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) viewWillDisappearActions.forEach({ $0(animated) }) } } class ViewController: BaseViewController { override func viewDidLoad() { super.viewDidLoad() setupNavigationBar() } func setupNavigationBar() { self.navigationController?.title = "App Title" viewWillAppearActions.append({ [weak self] anim in self?.navigationController?.setNavigationBarHidden(false, animated: anim) }) viewWillDisappearActions.append({ [weak self] anim in self?.navigationController?.setNavigationBarHidden(true, animated: anim) }) } } ❗CASE #3. Overrides
  • 13. class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() setupKeyboardEvent() } func setupKeyboardEvent() { NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardWillShow), name: .UIKeyboardWillShow, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardWillHide), name: .UIKeyboardWillHide, object: nil) } @objc func onKeyboardWillShow(notification: Notification) { print("Keyboard will show") } @objc func onKeyboardWillHide(notification: Notification) { print("Keyboard will hide") } } CASE #4. Selector ❓
  • 14. class KeyboardEventWrapper { var onKeyboardWillShowCallBack: (Notification) -> () = { _ in } init() { NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardWillShow), name: .UIKeyboardWillShow, object: nil) } @objc func onKeyboardWillShow(notification: Notification) { onKeyboardWillShowCallBack(notification) } deinit { NotificationCenter.default.removeObserver(self) } } class ViewController: UIViewController { var keyboardEventWrapper: KeyboardEventWrapper! override func viewDidLoad() { super.viewDidLoad() setupKeyboardEvent() } func setupKeyboardEvent() { keyboardEventWrapper = KeyboardEventWrapper() keyboardEventWrapper.onKeyboardWillShowCallBack = { _ in print("Keyboard will show") } } } ❗CASE #4. Selector
  • 15. class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate { @IBAction func onLoadImage() { let picker = UIImagePickerController() picker.delegate = self present(picker, animated: true, completion: nil) } // MARK: - UIImagePickerControllerDelegate func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String: Any]) { let originalInfo = info[UIImagePickerControllerOriginalImage] guard let originalImage = originalInfo as? UIImage else { return } // ... picker.dismiss(animated: true, completion: nil) } } CASE #5. Delegate ❓
  • 16. class ImagePickerWrapper: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate { var onImagePicked: (UIImage?) -> () = { _ in } func showImagePicker(on vc: UIViewController) { let picker = UIImagePickerController() picker.delegate = self vc.present(picker, animated: true, completion: nil) } // MARK: - UIImagePickerControllerDelegate func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String: Any]) { let originalInfo = info[UIImagePickerControllerOriginalImage] guard let originalImage = originalInfo as? UIImage else { return } onImagePicked(originalImage) picker.dismiss(animated: true, completion: nil) } } class ViewController: UIViewController { var imagePicker: ImagePickerWrapper! @IBAction func onLoadImage() { imagePicker = ImagePickerWrapper() imagePicker.showImagePicker(on: self) imagePicker.onImagePicked = { image in guard let image = image else { return } // ... } } } ❗CASE #5. Delegate
  • 18. CASE #1. Data + Logic + UI struct CalcData { let num1: Int let num2: Int } func textToInt(_ text: String?) -> Int { guard let text = text else { return 0 } return Int(text) ?? 0 } func intToText(_ num: Int) -> String { return "(num)" } func calcPlus(_ data: CalcData) -> Int { return data.num1 + data.num2 } class ViewController: UIViewController { @IBOutlet var number1: UILabel! @IBOutlet var number2: UILabel! @IBOutlet var result: UILabel! @IBAction func calcResult(_ sender: Any) { let n1 = textToInt(number1.text) let n2 = textToInt(number2.text) let data = CalcData(num1: n1, num2: n2) let res = calcPlus(data) result.text = intToText(res) } } Model.swift Context.swift ViewController.swift ❗❗
  • 19. CASE #2. Data Setter import RxSwift import RxCocoa // Common Functions let intToText = { (i: Int) in "(i)" } /// class ViewController: UIViewController { @IBOutlet var textLabel: UILabel! let disposeBag = DisposeBag() let count = BehaviorRelay<Int>(value: 0) override func viewDidLoad() { super.viewDidLoad() count.map(intToText) .bind(to: textLabel.rx.text) .disposed(by: disposeBag) } @IBAction func addOne() { count.accept(count.value + 1) } @IBAction func subOne() { count.accept(count.value - 1) } } ❗❗
  • 20. CASE #2. Data Setter import RxSwift import RxCocoa // Common Functions let intToText = { (i: Int) in "(i)" } /// class ViewController: UIViewController { @IBOutlet var textLabel: UILabel! @IBOutlet var textLabelx10: UILabel! let disposeBag = DisposeBag() let count = BehaviorRelay<Int>(value: 0) override func viewDidLoad() { super.viewDidLoad() count.map(intToText) .bind(to: textLabel.rx.text) .disposed(by: disposeBag) count.map({ $0 * 10 }) .map(intToText) .bind(to: textLabelx10.rx.text) .disposed(by: disposeBag) } @IBAction func addOne() { count.accept(count.value + 1) } @IBAction func subOne() { count.accept(count.value - 1) } } ❗❗
  • 21. import RxSwift import RxCocoa import RxViewController // <== class ViewController: UIViewController { let disposeBag = DisposeBag() override func viewDidLoad() { super.viewDidLoad() setupNavigationBar() } func setupNavigationBar() { self.navigationController?.title = "App Title" self.rx.viewWillAppear.subscribe(onNext: { [weak self] anim in self?.navigationController?.setNavigationBarHidden(false, animated: anim) }).disposed(by: disposeBag) self.rx.viewWillDisappear.subscribe(onNext: { [weak self] anim in self?.navigationController?.setNavigationBarHidden(true, animated: anim) }).disposed(by: disposeBag) } } CASE #3. Overrides ❗❗
  • 22. import UIKit import RxSwift import RxCocoa class ViewController: UIViewController { let disposeBag = DisposeBag() override func viewDidLoad() { super.viewDidLoad() setupKeyboardEvent() } func setupKeyboardEvent() { NotificationCenter.default.rx.notification(.UIKeyboardWillShow) .subscribe(onNext: { notifiaction in print("Keyboard will show") }) .disposed(by: disposeBag) NotificationCenter.default.rx.notification(.UIKeyboardWillHide) .subscribe(onNext: { notifiaction in print("Keyboard will hide") }) .disposed(by: disposeBag) } } CASE #4. Selector ❗❗
  • 23. import UIKit import RxSwift import RxCocoa class ViewController: UIViewController { let disposeBag = DisposeBag() @IBOutlet weak var imageView: UIImageView! @IBAction func onLoadImage() { let picker = UIImagePickerController() present(picker, animated: true, completion: nil) picker.rx.didFinishPickingMediaWithInfo .map({ info -> UIImage? in info[UIImagePickerControllerOriginalImage] as? UIImage }) .bind(to: imageView.rx.image) .disposed(by: disposeBag) } } CASE #5. Delegate ❗❗
  • 24. // MARK:- UIImagePickerController.rx // picker.rx.didFinishPickingMediaWithInfo // ~~~~~~ ~~ // Base Reactive extension Reactive where Base: UIImagePickerController { public var didFinishPickingMediaWithInfo: Observable<[String : Any]> { return RxImagePickerProxy.proxy(for: base) .didFinishPickingMediaWithInfoSubject .asObservable() .do(onCompleted: { self.base.dismiss(animated: true, completion: nil) }) } public var didCancel: Observable<Void> { return RxImagePickerProxy.proxy(for: base) .didCancelSubject .asObservable() .do(onCompleted: { self.base.dismiss(animated: true, completion: nil) }) } } CASE #5. Delegate ❗❗
  • 25. import UIKit import RxSwift import RxCocoa public typealias ImagePickerDelegate = UIImagePickerControllerDelegate & UINavigationControllerDelegate extension UIImagePickerController: HasDelegate { public typealias Delegate = ImagePickerDelegate } class RxImagePickerProxy: DelegateProxy<UIImagePickerController, ImagePickerDelegate>, DelegateProxyType, UIImagePickerControllerDelegate, UINavigationControllerDelegate { public init(imagePicker: UIImagePickerController) { super.init(parentObject: imagePicker, delegateProxy: RxImagePickerProxy.self) } //MARK:- DelegateProxyType public static func registerKnownImplementations() { self.register { RxImagePickerProxy(imagePicker: $0) } } static func currentDelegate(for object: UIImagePickerController) -> ImagePickerDelegate? { return object.delegate } static func setCurrentDelegate(_ delegate: ImagePickerDelegate?, to object: UIImagePickerController) { object.delegate = delegate } //MARK:- Proxy Subject //MARK:- UIImagePickerControllerDelegate //MARK:- Completed } CASE #5. Delegate ❗❗
  • 26. class RxImagePickerProxy: DelegateProxy<UIImagePickerController, ImagePickerDelegate>, DelegateProxyType, UIImagePickerControllerDelegate, UINavigationControllerDelegate { //MARK:- DelegateProxyType //MARK:- Proxy Subject internal lazy var didFinishPickingMediaWithInfoSubject = PublishSubject<[String : Any]>() internal lazy var didCancelSubject = PublishSubject<Void>() //MARK:- UIImagePickerControllerDelegate func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String: Any]) { didFinishPickingMediaWithInfoSubject.onNext(info) didFinishPickingMediaWithInfoSubject.onCompleted() didCancelSubject.onCompleted() } func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { didCancelSubject.onNext(()) didCancelSubject.onCompleted() didFinishPickingMediaWithInfoSubject.onCompleted() } //MARK:- Completed deinit { self.didFinishPickingMediaWithInfoSubject.onCompleted() self.didCancelSubject.onCompleted() } } CASE #5. Delegate ❗❗
  • 27. import UIKit import RxSwift import RxCocoa class ViewController: UIViewController { let disposeBag = DisposeBag() @IBOutlet weak var imageView: UIImageView! @IBAction func onLoadImage() { let picker = UIImagePickerController() present(picker, animated: true, completion: nil) picker.rx.didFinishPickingMediaWithInfo .map({ info -> UIImage? in info[UIImagePickerControllerOriginalImage] as? UIImage }) .bind(to: imageView.rx.image) .disposed(by: disposeBag) } } CASE #5. Delegate ❗❗
  • 29. UI
  • 30. Model.swift struct CalcData { let n1: Int? let n2: Int? let result: Int? } extension CalcData { static func empty() -> CalcData { return CalcData(n1: nil, n2: nil, result: nil) } }
  • 31. Context.swift (Business Logic) let i2s = { (i: Int?) in "(i ?? 0)" } let s2i = { (s: String?) in Int(s ?? "0") } class Context { let model = BehaviorRelay<CalcData>(value: CalcData.empty()) func doCalc(data: CalcData) -> CalcData { guard let n1 = data.n1 else { return data } guard let n2 = data.n2 else { return data } let result = n1 + n2 return CalcData(n1: n1, n2: n2, result: result) } }
  • 32. ViewController.swift class ViewController: UIViewController { @IBOutlet weak var n1Field: UITextField! // Input @IBOutlet weak var n2Field: UITextField! // Input @IBOutlet weak var resultLabel: UILabel! // Output @IBOutlet weak var calcButton: UIButton! // Event let context = Context() let disposeBag = DisposeBag() override func viewDidLoad() { super.viewDidLoad() bindUI() bindEvent() } func bindUI() { // ... } func bindEvent() { // … } }
  • 33. ViewController.swift class ViewController: UIViewController { func bindUI() { //n1 input n1Field.rx.text.map(s2i) .withLatestFrom(context.model) { (n1, dat) in CalcData(n1: n1, n2: dat.n2, result: dat.result) } .bind(to: context.model) .disposed(by: disposeBag) //n2 input n2Field.rx.text.map(s2i) .withLatestFrom(context.model) { (n2, dat) in CalcData(n1: dat.n1, n2: n2, result: dat.result) } .bind(to: context.model) .disposed(by: disposeBag) //result output viewModel.model.map({ $0.result }) .map(i2s) .bind(to: resultLabel.rx.text) .disposed(by: disposeBag) } func bindEvent() { //event calcButton.rx.tap .withLatestFrom(context.model) .map(context.doCalc) .bind(to: context.model) .disposed(by: disposeBag) } }
  • 34. Summary class ViewController: UIViewController { @IBOutlet weak var n1Field: UITextField! // Input @IBOutlet weak var n2Field: UITextField! // Input @IBOutlet weak var resultLabel: UILabel! // Output @IBOutlet weak var calcButton: UIButton! // Event let context = Context() let disposeBag = DisposeBag() override func viewDidLoad() { super.viewDidLoad() bindUI() bindEvent() } func bindUI() { //n1 input n1Field.rx.text.map(s2i) .withLatestFrom(context.model) { (n1, dat) in CalcData(n1: n1, n2: dat.n2, result: dat.result) } .bind(to: context.model) .disposed(by: disposeBag) //n2 input n2Field.rx.text.map(s2i) .withLatestFrom(context.model) { (n2, dat) in CalcData(n1: dat.n1, n2: n2, result: dat.result) } .bind(to: context.model) .disposed(by: disposeBag) //result output viewModel.model.map({ $0.result }) .map(i2s) .bind(to: resultLabel.rx.text) .disposed(by: disposeBag) } func bindEvent() { //event calcButton.rx.tap .withLatestFrom(context.model) .map(context.doCalc) .bind(to: context.model) .disposed(by: disposeBag) } } struct CalcData { let n1: Int? let n2: Int? let result: Int? } extension CalcData { static func empty() -> CalcData { return CalcData(n1: nil, n2: nil, result: nil) } } View ViewController Context Model let i2s = { (i: Int?) in "(i ?? 0)" } let s2i = { (s: String?) in Int(s ?? "0") } class Context { let model = BehaviorRelay<CalcData>(value: CalcData.empty()) func doCalc(data: CalcData) -> CalcData { guard let n1 = data.n1 else { return data } guard let n2 = data.n2 else { return data } let result = n1 + n2 return CalcData(n1: n1, n2: n2, result: result) } }
  • 35. struct CalcData { let n1: Int? let n2: Int? let result: Int? } extension CalcData { static func empty() -> CalcData { return CalcData(n1: nil, n2: nil, result: nil) } } View ViewController Context Model ViewModel Summary class ViewController: UIViewController { @IBOutlet weak var n1Field: UITextField! // Input @IBOutlet weak var n2Field: UITextField! // Input @IBOutlet weak var resultLabel: UILabel! // Output @IBOutlet weak var calcButton: UIButton! // Event let viewModel = ViewModel() let disposeBag = DisposeBag() override func viewDidLoad() { super.viewDidLoad() bindUI() bindEvent() } func bindUI() { //n1 input n1Field.rx.text.map(s2i) .withLatestFrom(viewModel.model) { (n1, dat) in CalcData(n1: n1, n2: dat.n2, result: dat.result) } .bind(to: viewModel.model) .disposed(by: disposeBag) //n2 input n2Field.rx.text.map(s2i) .withLatestFrom(viewModel.model) { (n2, dat) in CalcData(n1: dat.n1, n2: n2, result: dat.result) } .bind(to: viewModel.model) .disposed(by: disposeBag) //result output viewModel.model.map({ $0.result }) .map(i2s) .bind(to: resultLabel.rx.text) .disposed(by: disposeBag) } func bindEvent() { //event calcButton.rx.tap .withLatestFrom(viewModel.model) .map(viewModel.doCalc) .bind(to: viewModel.model) .disposed(by: disposeBag) } } let i2s = { (i: Int?) in "(i ?? 0)" } let s2i = { (s: String?) in Int(s ?? "0") } class ViewModel { let model = BehaviorRelay<CalcData>(value: CalcData.empty()) func doCalc(data: CalcData) -> CalcData { guard let n1 = data.n1 else { return data } guard let n2 = data.n2 else { return data } let result = n1 + n2 return CalcData(n1: n1, n2: n2, result: result) } }