안드로이드 개발자를 위한 스위프트

Post on 06-Jan-2017

3.643 Views

Category:

Software

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

let swift(16)

안드로이드�개발자를�위한�스위프트Swift & VIPER

osxdev.org / todait유병한

저는…

유병한�

현재�투데잇에서�iOS�개발을�담당(하고�있지만�사실은�Android�개발자�🙈🙉)�

이제는�iOS�개발자가�되고픔

아니�Android�개발자가�왜�iOS�개발을...?

회사에�iOS�개발자가�없어서...😭

Agenda

Swift를�사용하면서�Java에�비해�좋았던�부분(중요한�부분만�빠르게�알아봐요!)�

VIPER�아키텍처�적용�사례

let swift(16)

Android�개발을�하면서�아쉬웠던�부분

Java ☕

Null�Pointer�Exception�

Getter�/�Setter�

Anonymous�Class�

복잡한�계산로직을�자유자재로,�가독성이�좋게�짜기�힘듦

Activity (== ViewController)

너무나�많은�역할을�하는�Activity�

View,�Life�Cycle,�Navigation,�Networking,�DB,�Business�Logic,�…�

어떤�코드가�어디에�있는지�찾기�힘듦(==�뭣이�중헌지�모름)�

이러한�구조로는�테스트도�불가능

빚이되어�돌아오리…💸

Dirty�&�Fast�

모든�것이�빚으로�돌아옴�

버그라던지.�

버그라던지..�

버그라던지...

인간의욕심은끝이없고

같은실수를반복한다

같은�실수를�반복하지�말자!�🤔

let swift(16)

Swift

Swift

Optional Type

Property

Closure & Functional

Protocol & Extension

Java,�넘나�위험한�것!�⚠

Optional Type

Optional�Type이란?

타입�선언�시�변수에�nil이�저장될�수�있는지�여부를�명시

var nonOptional: Int = 0 nonOptional = nil // Compile Error!

var optional: Int? = 0 optional = nil // OK!

Optional Chaining

let viewController = UIViewController() print(viewController.navigationItem.backBarButtonItem?.title?.characters.count)

print(viewController.navigationItem.backBarButtonItem?.title ?? "Title")

Optional Binding - if let

if let viewController = viewController as? UITableViewController { viewController.tableView.reloadData() }

Optional Binding - if let

if let viewController = viewController as? UITableViewController, refreshControl = viewController.refreshControl { refreshControl.beginRefreshing() }

Optional Binding - if let

if let viewController = viewController as? UITableViewController, refreshControl = viewController.refreshControl where refreshControl.refreshing { refreshControl.beginRefreshing() }

Optional Binding - guard let

func signUp1(email: String?) { guard let email = email else { return } print(email.characters.count) }

Optional Binding - guard let

func signUp(email: String?, password: String?) { guard let email = email, password = password else { return } print("\(email) / \(password)") }

Optional Binding - guard let

func signUp(email: String?, password: String?) { guard let email = email, password = password where 8 <= password.characters.count else { return } print("\(email) / \(password)") }

Optional Binding - switch

let passwordText: String? = ""

switch(passwordText) { case .Some(let password) where 8 <= password.characters.count: print(password) case .Some: print("8자리�이상�입력해주세요") case .None: print("password is nil") }

이제는�안녕�Getter,�Setter�🙋

Property

Stored Property

struct Box { let width: Double let height: Double let depth: Double }

Stored Propertystruct Box { var width: Double { willSet { print("newValue: \(newValue)") } didSet { print("oldValue: \(oldValue)") volume = width * height * depth } } var height: Double { ... } var depth: Double { ... } var volume: Double }

Computed Property

struct Box { var width: Double var height: Double var depth: Double var volume: Double { get { return width * height * depth } set { print("newValue: \(newValue)") } } }

Computed Property

struct Box { var width: Double var height: Double var depth: Double var volume: Double { return width * height * depth } }

for,�if의�늪에서�나를�구해줘요!�😱

Closure & Functional

객체로서의�함수

함수의�인자로�함수를�넘길�수�있음�

함수의�결과로�함수를�반환할�수�있음

Closure�사용과�타입�추론

Closure는�이름이�없는�함수

var sum = [1, 23, 4, 32].reduce(0, combine: { (sum: Int, element: Int) -> Int in return sum + element })

Closure�사용과�타입�추론

타입이�명확한�경우�생략�가능

extension SequenceType { /// Returns the result of repeatedly calling `combine` with an /// accumulated value initialized to `initial` and each element of /// `self`, in turn, i.e. return /// `combine(combine(...combine(combine(initial, self[0]), /// self[1]),...self[count-2]), self[count-1])`. @warn_unused_result public func reduce<T>(initial: T, @noescape combine: (T, Self.Generator.Element) throws -> T) rethrows -> T }

var sum = [1, 23, 4, 32].reduce(0, combine: { (sum: Int, element: Int) -> Int in return sum + element })

Closure�사용과�타입�추론

sum = [1, 23, 4, 32].reduce(0, combine: { sum, element in return sum + element })

sum = [1, 23, 4, 32].reduce(0, combine: { return $0 + $1 })

sum = [1, 23, 4, 32].reduce(0, combine: { $0 + $1 })

sum = [1, 23, 4, 32].reduce(0) { $0 + $1 }

sum = [1, 23, 4, 32].reduce(0, combine: +)

투데잇에서의�Functional

통계�계산�로직에서�적극적으로�사용�

대용량�데이터를�다루는�것이�아닌�유저�한사람의�데이터�그�중에서도�특정�날짜의�데이터를�주로�다룸�

스레드�처리만�잘�해주면�사용자�체감�상�크게�문제될�상황은�없음�

퍼포먼스도�물론�중요하지만�오류�없고,�가독성이�높고,�수정이�용이한�코드가�필요�

map,�flatMap,�filter,�reduce,�contains�...

Protocol & Extension

Property&Method Requirements

Property�&�Method�에�대한�명세

protocol Flyable { var distance: Int { get set } func fly() }

struct SwiftBird: Flyable { var distance: Int func fly() { print("flying!") } }

Protocol with an Extension

Protocol은�Property를�가질�수�없지만�Method는�가질�수�있음

protocol ViewControllerProtocol: class { var loadingView: LoadingView { get set } }

extension ViewControllerProtocol where Self: UIViewController { func showLoadingView() { loadingView.showLoadingView(self) } func dismissLoadingView() { loadingView.dismissView() } }

let swift(16)

VIPER

좋은�Architecture는?

Distribution�

Testability�

Ease�of�Use

VIPER�구성요소

View Presenter

Router

Interactor Entity

DataService

Todait의�VIPER�구성요소

View Presenter

Router

Interactor

Entity

ViewModel

DataService

DataServiceView Presenter

Router

Interactor

Entity

ViewModel

DataService

View

UIViewController에�해당�

View�Life�Cycleex)�viewDidLoad�함수가�호출되었음을�Presenter에�알림�

View�Eventex)�signUpButton이�클릭되었음을�Presenter에�알림�

View�Controlex)�titleLabel의�텍스트를�바꾸는�방법을�Presenter에�제공

DataServiceView Presenter

Router

Interactor

Entity

ViewModel

DataService

Presenter

View와�Interactor의�중간�다리�역할�

View에�대한�비즈니스�로직�

Life�Cycle에�대한�처리�

View�Event에�대한�처리�

View�업데이트�

UIKit�Independent

DataServiceView Presenter

Router

Interactor

Entity

ViewModel

DataService

Interactor

Data(Entity)에�대한�비즈니스�로직

DataServiceView Presenter

Router

Interactor

Entity

ViewModel

DataService

Entity

네트워크,�DB�등의�데이터�모델�

Realm�Object,�NSUserDefuatls,�Json�Data�등�

Interactor에서�사용

DataServiceView Presenter

Router

Interactor

Entity

ViewModel

DataService

Router

View�간의�전환�

VIPER�컴포넌트들의�DI(Dependency�Injection)를�담당

DataServiceView Presenter

Router

Interactor

Entity

ViewModel

DataService

DataService

Network�요청,�DB�접근,�UserDefaults,�이미지�처리�등�반복되는�코드를�모듈화�

Interactor가�호출함

DataServiceView Presenter

Router

Interactor

Entity

ViewModel

DataService

ViewModel

View에�나타나는�데이터와�1:1�매칭�

Entity가�어떻게�View에�바인딩될지�정의�

Interactor에서�생성되어�Presenter로�전달

VIPER Flow

가입하기�버튼을�눌려�회원가입을�완료하는�과정

DataService

presenter.onClickSignUpButton()

View Presenter

Router

Interactor

Entity

ViewModel

DataService

DataService

viewController.showLoadingAlert()

View Presenter

Router

Interactor

Entity

ViewModel

DataService

DataService

interactor.signUp(signUpViewModel)

View Presenter

Router

Interactor

Entity

ViewModel

DataService

DataService

signUpViewModel.checkValidation()

View Presenter

Router

Interactor

Entity

ViewModel

DataService

DataServic

serverService.signUp(email, password)

View Presenter

Router

Interactor

Entity

ViewModel

DataService

realmService.saveUserData()

DataServiceView Presenter

Router

Interactor

Entity

ViewModel

DataService

presenter.onSignUpSucceed() / presenter.onSignUpFailed()

DataServiceView Presenter

Router

Interactor

Entity

ViewModel

DataService

viewController.dismissLoadingAlert()

DataServiceView Presenter

Router

Interactor

Entity

ViewModel

DataService

router.dismissViewController()

DataServiceView Presenter

Router

Interactor

Entity

ViewModel

DataService

VIPER with Swift - Protocol

protocol ViewControllerProtocol: class { var loadingAlert: LoadingAlert { get set } }

extension ViewControllerProtocol where Self: UIViewController { func showLoadingAlert() { loadingView.showLoadingAlert(self) } func dismissLoadingAlert() { loadingView.dismissAlert() } }

VIPER with Swift - Computed Property

protocol SignUpViewControllerProtocolForPresenter: class { var email: String? { get set } var password: String? { get set } }

extension SignUpViewController: SignUpViewControllerProtocolForPresenter { var email: String? { get { return emailTextField.text } set { emailTextField.text = newValue } } var password: String? { get { return passwordTextField.text } set { passwordTextField.text = newValue } } }

장점

하나의�화면에서�기능�단위로�코드를�명확하게�분리�

(물론�모든�컴포넌트에�대해�테스트를�하고�있지�않지만)�모든�컴포넌트에�대해�테스트�가능해지는�구조가됨�

(물론�혼자�개발하고�있지만)�분업이�훨씬�수월해짐

단점

간단한�화면,�간단한�기능에�대해서도�작성해야할�코드가�늘어남

Next Step

Code�Generator�

RxSwift,�KVO�

Android에도�적용

Swift로�iOS�앱�개발을�하면서�느낀�점

Swift�정말�최고!�

UI가�있는�어플리케이션�만든다는�관점에서�큰�동작�원리는�Android나�iOS나�비슷한�것�같음�

iOS에도�문제가�많다고�하지만�안드로이드에�비할바는�아닌�것�같음�

훨씬�평화로운�iOS!�피쓰~�🕊

투데잇의 성장을 함께할 당신을 기다리고 있습니다.

i O S 개 발 을 박 ♥ 살 내 주 실 당 신 !

let swift(16)

top related