SlideShare una empresa de Scribd logo
1 de 174
Descargar para leer sin conexión
let swift(17)
Swift, Kotlin과 모던 언어의 특징
세미콜론 없는 세상
github.com/inkfyox유용하
let swift(17)
목적
Swift vs. Kotlin Swift & Kotlin
문법의 유사성 소개
모던 언어에서의 이슈들을 두 언어가 어떻게 해결하고 있는지 비교
차이점이 생길 수 밖에 없는 기반 시스템 비교
Swift & Kotlin
Swift
•Apple에서 개발
•Objective-C의 다음 세대 언어
•Open source (https://github.com/apple/swift)
•주로 사용되는 곳: iOS, macOS, watchOS, tvOS
•기타: Linux
Kotlin
•JetBrains에서 개발
•Java의 다음 세대 언어 (중의 하나)
•Open source (https://github.com/JetBrains/kotlin)
•주로 사용되는 곳: Android, server, 자바가 쓰이는 곳 어디든
•기타: JVM이 아닌 JavaScript 타겟도 지원함
History
1.0.0M1~M14, 1.0 Beta 1~4
안드로이드 공식 지원
프로젝트 공개
오픈소스화
1.1.0
1.0
1.1 1.2
2.0 3.0 3.1
프로젝트 공개 오픈소스화
let swift(17)
타입 시스템
변수 선언
let number: Int = 1
var any: Any = number
val number: Int = 1
var any: Any = number
타입 체크
if any is Int {
    // ...
}
if (any is Int) {
// ...
}
Downcast let num2: Int = any as! Int val num2: Int = any as Int
타입 변환 let long: Int64 = Int64(number) val long: Long = number.toLong()
타입 추론 let number = 1 val number = 1
정적 타입
변수 선언
let number: Int = 1
var any: Any = number
val number: Int = 1
var any: Any = number
타입 체크
if any is Int {
    // ...
}
if (any is Int) {
// ...
}
Downcast let num2: Int = any as! Int val num2: Int = any as Int
타입 변환 let long: Int64 = Int64(number) val long: Long = number.toLong()
타입 추론 let number = 1 val number = 1
정적 타입
변수 선언
let number: Int = 1
var any: Any = number
val number: Int = 1
var any: Any = number
타입 체크
if any is Int {
    // ...
}
if (any is Int) {
// ...
}
Downcast let num2: Int = any as! Int val num2: Int = any as Int
타입 변환 let long: Int64 = Int64(number) val long: Long = number.toLong()
타입 추론 let number = 1 val number = 1
정적 타입
변수 선언
let number: Int = 1
var any: Any = number
val number: Int = 1
var any: Any = number
타입 체크
if any is Int {
    // ...
}
if (any is Int) {
// ...
}
Downcast let num2: Int = any as! Int val num2: Int = any as Int
타입 변환 let long: Int64 = Int64(number) val long: Long = number.toLong()
타입 추론 let number = 1 val number = 1
정적 타입
var conference = "LetSwift"
conference = "VarSwift"
var conference = "ValKotlin"
conference = "VarKotlin"
let conference: String
if isSwift {
conference = "LetSwift"
} else {
conference = "ValKotlin"
}
val conference: String
if (isSwift) {
conference = "LetSwift"
} else {
conference = "ValKotlin"
}
let conference = "LetSwift"
conference = "VarSwift"
val conference = "ValKotlin"
conference = “VarKotlin"
읽기 전용 변수
읽기 전용 변수 -> 재할당 불가
var conference = "LetSwift"
conference = "VarSwift"
var conference = "ValKotlin"
conference = "VarKotlin"
let conference: String
if isSwift {
conference = "LetSwift"
} else {
conference = "ValKotlin"
}
val conference: String
if (isSwift) {
conference = "LetSwift"
} else {
conference = "ValKotlin"
}
let conference = "LetSwift"
conference = "VarSwift"
val conference = "ValKotlin"
conference = “VarKotlin"
읽기 전용 변수
읽기 전용 변수 -> 재할당 불가
var conference = "LetSwift"
conference = "VarSwift"
var conference = "ValKotlin"
conference = "VarKotlin"
let conference: String
if isSwift {
conference = "LetSwift"
} else {
conference = "ValKotlin"
}
val conference: String
if (isSwift) {
conference = "LetSwift"
} else {
conference = "ValKotlin"
}
let conference = "LetSwift"
conference = "VarSwift"
val conference = "ValKotlin"
conference = “VarKotlin"
읽기 전용 변수
컴파일 시점에 값이 정해지는 것은 아님
처음 사용되기 전에 값이 한번 할당된다는 것을 컴파일 시점에 체크
타입 추론
SomeClassWithVeryLongName* bar = [[SomeClassWithVeryLongName alloc] init];
SomeClassWithVeryLongName* other = bar
SomeClassWithVeryLongName bar = new SomeClassWithVeryLongName();
SomeClassWithVeryLongName other = bar;
ObjC
Java
타입 추론
SomeClassWithVeryLongName* bar = [[SomeClassWithVeryLongName alloc] init];
SomeClassWithVeryLongName* other = bar
SomeClassWithVeryLongName bar = new SomeClassWithVeryLongName();
SomeClassWithVeryLongName other = bar;
ObjC
Java
중복된 정보
타입 추론
SomeClassWithVeryLongName* bar = [[SomeClassWithVeryLongName alloc] init];
SomeClassWithVeryLongName* other = bar
SomeClassWithVeryLongName bar = new SomeClassWithVeryLongName();
SomeClassWithVeryLongName other = bar;
ObjC
Java
let bar = SomeClassWithVeryLongName()
var other = bar
val bar = SomeClassWithVeryLongName()
var other = bar
타입 추론
SomeClassWithVeryLongName* bar = [[SomeClassWithVeryLongName alloc] init];
SomeClassWithVeryLongName* other = bar
SomeClassWithVeryLongName bar = new SomeClassWithVeryLongName();
SomeClassWithVeryLongName other = bar;
ObjC
Java
let bar = SomeClassWithVeryLongName()
var other = bar
val bar = SomeClassWithVeryLongName()
var other = bar
other = SomeOtherClass()
other = SomeOtherClass() 그래도 정적 타입이니까
Optional & Nullable
nil/null 값을 가진 변수를 주소값으로 사용했을때
•런타임 에러 발생
•프로그램의 안정성을 해침 (가장 빈번한 에러)
•Objc의 경우 sendmsg방식으로 크래시는 안나도 의도치 않은 동작 가능
•100% 안전하려면 항상 변수가 nil/null 인지 확인해야함
•nil/null인 경우가 없는 경우도 체크하게 됨 -> 비효율
•강제가 아니기 때문에 빠뜨릴 수 있음 -> 구멍
Optional & Nullable
타입에 nil/null을 가질 수 있는지의 의미도 부여한다면
•nil/null 가질 수 있는 Optional/Nullable 타입: 무조건 체크해야함
•런타임 에러 -> 컴파일타임 에러: 안정성 향상
•not-null 타입: 체크 안하고 안정적으로 사용
•의외로 not-null인 변수를 다루는 경우가 더 많음: 코드가 간결해짐
Optional & Nullable
타입
let str = "1234"
let num: Int? = Int(str)
val str = "1234"
val num: Int? = str.toIntOrNull()
기본값 let num2: Int = num ?? -1 val num2: Int = num ?: -1
체이닝 server?.connect().name.capitalized server?.connect()?.name?.capitalize()
Downcast
let any: Any
let number = any as? Int
val any: Any
val number = any as? Int
강제
Downcast
let number = any as! Int val number = any as Int
강제
Unwrap
server!.connect().name.capitalized server!!.connect().name.capitalize()
Optional & Nullable
타입
let str = "1234"
let num: Int? = Int(str)
val str = "1234"
val num: Int? = str.toIntOrNull()
기본값 let num2: Int = num ?? -1 val num2: Int = num ?: -1
체이닝 server?.connect().name.capitalized server?.connect()?.name?.capitalize()
Downcast
let any: Any
let number = any as? Int
val any: Any
val number = any as? Int
강제
Downcast
let number = any as! Int val number = any as Int
강제
Unwrap
server!.connect().name.capitalized server!!.connect().name.capitalize()
Optional & Nullable
타입
let str = "1234"
let num: Int? = Int(str)
val str = "1234"
val num: Int? = str.toIntOrNull()
기본값 let num2: Int = num ?? -1 val num2: Int = num ?: -1
체이닝 server?.connect().name.capitalized server?.connect()?.name?.capitalize()
Downcast
let any: Any
let number = any as? Int
val any: Any
val number = any as? Int
강제
Downcast
let number = any as! Int val number = any as Int
강제
Unwrap
server!.connect().name.capitalized server!!.connect().name.capitalize()
Optional & Nullable
타입
let str = "1234"
let num: Int? = Int(str)
val str = "1234"
val num: Int? = str.toIntOrNull()
기본값 let num2: Int = num ?? -1 val num2: Int = num ?: -1
체이닝 server?.connect().name.capitalized server?.connect()?.name?.capitalize()
Downcast
let any: Any
let number = any as? Int
val any: Any
val number = any as? Int
강제
Downcast
let number = any as! Int val number = any as Int
강제
Unwrap
server!.connect().name.capitalized server!!.connect().name.capitalize()
((server?.connect())?.name)?.capitalized
Optional & Nullable
타입
let str = "1234"
let num: Int? = Int(str)
val str = "1234"
val num: Int? = str.toIntOrNull()
기본값 let num2: Int = num ?? -1 val num2: Int = num ?: -1
체이닝 server?.connect().name.capitalized server?.connect()?.name?.capitalize()
Downcast
let any: Any
let number = any as? Int
val any: Any
val number = any as? Int
강제
Downcast
let number = any as! Int val number = any as Int
강제
Unwrap
server!.connect().name.capitalized server!!.connect().name.capitalize()
Optional & Nullable
타입
let str = "1234"
let num: Int? = Int(str)
val str = "1234"
val num: Int? = str.toIntOrNull()
기본값 let num2: Int = num ?? -1 val num2: Int = num ?: -1
체이닝 server?.connect().name.capitalized server?.connect()?.name?.capitalize()
Downcast
let any: Any
let number = any as? Int
val any: Any
val number = any as? Int
강제
Downcast
let number = any as! Int val number = any as Int
강제
Unwrap
server!.connect().name.capitalized server!!.connect().name.capitalize()
웬만하면 쓰지말라고 느낌표 2개
Optional & Nullable
타입
let str = "1234"
let num: Int? = Int(str)
val str = "1234"
val num: Int? = str.toIntOrNull()
기본값 let num2: Int = num ?? -1 val num2: Int = num ?: -1
체이닝 server?.connect().name.capitalized server?.connect()?.name?.capitalize()
Downcast
let any: Any
let number = any as? Int
val any: Any
val number = any as? Int
강제
Downcast
let number = any as! Int val number = any as Int
강제
Unwrap
server!.connect().name.capitalized server!!.connect().name.capitalize()
Optional & Nullable
func foo(value: String?) {
if let value = value {
print(value.capitalized)
}
}


fun foo(value: String?) {

if (value != null) {

println(value.capitalize())

}

}

func foo(value: String?) {
guard let value = value else { return }
print(value.capitalized)
}


fun foo(value: String?) {
if (value == null) return
println(value.capitalize())
}
func foo(value: Any) {
if let value = value as? String {
print(value.capitalized)
}
}


fun foo(value: Any) {
if (value is String) {
println(value.capitalize())
}
}
Smart CastOptional Unwrap
Optional & Nullable
func foo(value: String?) {
if let value = value {
print(value.capitalized)
}
}


fun foo(value: String?) {

if (value != null) {

println(value.capitalize())

}

}

func foo(value: String?) {
guard let value = value else { return }
print(value.capitalized)
}


fun foo(value: String?) {
if (value == null) return
println(value.capitalize())
}
func foo(value: Any) {
if let value = value as? String {
print(value.capitalized)
}
}


fun foo(value: Any) {
if (value is String) {
println(value.capitalize())
}
}
Smart CastOptional Unwrap
Optional & Nullable
func foo(value: String?) {
if let value = value {
print(value.capitalized)
}
}


fun foo(value: String?) {

if (value != null) {

println(value.capitalize())

}

}

func foo(value: String?) {
guard let value = value else { return }
print(value.capitalized)
}


fun foo(value: String?) {
if (value == null) return
println(value.capitalize())
}
func foo(value: Any) {
if let value = value as? String {
print(value.capitalized)
}
}


fun foo(value: Any) {
if (value is String) {
println(value.capitalize())
}
}
Smart CastOptional Unwrap
let swift(17)
자료 구조와 Mutability
view2
class View
location
(0.0, 0.0)
class Point
x: 0.0
y: 0.0
Mutability: 공유 상태의 문제
view1
class View
location
(0.0, 0.0)
view2
class View
location
(10.0, 0.0)
view2.location.x += 10.0
class Point
x: 10.0
y: 0.0
view1
class View
location
(10.0, 0.0)
Mutability: 공유 상태의 문제
view2
class View
location
(10.0, 0.0)
class Point
x: 10.0
y: 0.0
view1
class View
location
(10.0, 0.0)
???
view2.location.x += 10.0
Mutability: 공유 상태의 문제
view2
class View
location
(0.0, 0.0)
class Point
readonly x: 0.0
readonly y: 0.0
공유 상태 문제 해결
view1
class View
location
(0.0, 0.0)
ObjC
view2
class View
location
(0.0, 0.0)
view1
class View
location
(0.0, 0.0)
view2.location.x += 10.0
재할당 불가능한 변수이기 때문
ObjC
class Point
readonly x: 0.0
readonly y: 0.0
공유 상태 문제 해결
view2
class View
location
(10.0, 0.0)
view1
class View
location
(0.0, 0.0)
view2.location = Point(view.location.x + 10.0, view.location)
기존 객체의 값을 이용해 새로운 객체를 할당
class Point
readonly x: 0.0
readonly y: 0.0
class Point
readonly x: 10.0
readonly y: 0.0
ObjC
*) 실제 View, UIView의 location의 예시는 아님
공유 상태 문제 해결
Immutable type
공유되는 변수의 내부 값이 변경 가능할때 생기는 문제 원천 차단
복잡도 감소
•변수의 상태 변화에 대한 트래킹 이슈 없음
성능 향상
•multi-thread에서 lock없이 공유 가능
view1
class View
location:
(0.0, 0.0)
Value 타입을 이용하면
애초에 공유될 수가 없음
struct Point
x: 0.0
y: 0.0
view2
class View
location:
(0.0, 0.0)
struct Point
x: 0.0
y: 0.0
Value 타입을 이용하면 초간단
공유 상태 문제 해결
view1
class View
location:
(0.0, 0.0)
struct Point
x: 0.0
y: 0.0
view2
class View
location:
(10.0, 0.0)
struct Point
x: 10.0
y: 0.0
Value 타입을 이용하면 초간단
view2.location.x += 10.0
공유 상태 문제 해결
숫자, 문자, Boolean
Value
(Int, Int64, Double, Bool, …)
Value (*) / Reference
(Int, Long, Double, Boolean, …)
String Value Reference
Collections
Value
(Array, Set, Dictionary)
Reference
(List, Set, Map)
Enum Value Reference
Struct Value 없음
Tuple Value 없음
Class Reference Reference
Function,
Closure / Lambda
Reference Reference
Reference / Value 타입
(*) Kotlin에는 Value 타입의 개념이 없고 JVM에서 원시타입이 Value 타입
String Literals
생성 let str = "lettSwiftn" val str = "valtKotlinn"
여러줄 생성
val json = """
{
"name": “Swift",
"version": (version)
}
"""
val json = """
{
"name": "Kotlin",
"version": $version
}
"""
연결
let lang = "Swift"
let title = "Hello, " + lang
val lang = "Kotlin"
val title = "Hello, " + lang
템플릿
let year = 2017
let current = "LetSwift(year)"
let previous = "LetSwift(year - 1)”
val year = 2017
val current = "ValKotlin$year"
val previous = "ValKotlin${year - 1}"
(Swift4.0)
str1
struct String
_storage
"Let"
String: Mutability
…
refCount: 1
"Let"
let str1 = "Let"
public struct String { … }
str1
struct String
_storage
"Let"
String: Mutability
…
refCount: 1
"Let"
let str1 = "Let"
String은 struct로 value 타입이지만,
내부에 실제 문자열 데이터를 저장할 저장소는 reference 타입일 수 밖에 없다.
public struct String { … }
str1
struct String
_storage
"Let"
let str1 = "Let"
var str2 = str1
…
refCount: 2
"Let"
str2
struct String
_storage
"Let"
public struct String { … }
String: Mutability
재할당할 때마다 저장소를 복사하는 것은 비효율, 일단은 공유한다.
str1
struct String
_storage
"Let"
…
refCount: 1
"Let"
str2
struct String
_storage
"LetSwift"
let str1 = "Let"
var str2 = str1
str2.append("Swift")
…
refCount: 1
“LetSwift"
public struct String { … }
String: Mutability
str1
struct String
_storage
"Let"
…
refCount: 1
"Let"
str2
struct String
_storage
"LetSwift"
let str1 = "Let"
var str2 = str1
str2.append("Swift")
…
refCount: 1
“LetSwift"
Copy-On-Write: (처음) 변경될 때 복사한다.
public struct String { … }
String: Mutability
str1
struct String
_storage
"Let"
…
refCount: 1
"Let"
str2
struct String
_storage
"LetSwift"
let str1 = "Let"
var str2 = str1
str2.append("Swift")
…
refCount: 1
“LetSwift"
public mutating func append(_ other: String)
public struct String { … }
String: Mutability
Copy-On-Write: (처음) 변경될 때 복사한다.
let str1 = "Let"
let str2 = str1
str2.append("Swift")
str1
struct String
_storage
"Let"
…
refCount: 1
"Let"
str2
struct String
_storage
"LetSwift"
…
refCount: 1
“LetSwift"
public mutating func append(_ other: String)
value 타입은 let / var에 의해 immutable / mutable이 결정
public struct String { … }
String: Mutability
str1
struct String
_storage
"Let"
…
refCount: 1
"Let"
str2
struct String
_storage
“LetSwift17"
let str1 = "Let"
var str2 = str1
str2.append("Swift")
str2.append("17")
…
refCount: 1
"LetSwift17"
public struct String { … }
refCount가 1이기 때문
String: Mutability
1. mutable 동작의 API가 없음
2. open class가 아니어서 상속을 할 수 없음
-> String 타입으로 다룰 수 있는 Mutable String을 만드는 것이 불가능
public class String … { … }
String: Mutability
1. mutable 동작의 API가 없음
2. open class가 아니어서 상속을 할 수 없음
-> String 타입으로 다룰 수 있는 Mutable String을 만드는 것이 불가능
String은 Map의 key등 상수형으로 많이 쓰임
이런 String의 상태가 변경되는 것은 큰 혼란을 일으킬 수 있음
public class String … { … }
String: Mutability
val str1 = "Let"
var str2 = str1 + "Swift"
str2 = str2.replace("Swift", “Kotlin")
1. mutable 동작의 API가 없음
2. open class가 아니어서 상속을 할 수 없음
-> String 타입으로 다룰 수 있는 Mutable String을 만드는 것이 불가능
변경하려면: 변경된 문자열을 가진 새로운 객체를 생성해야 함
public class String … { … }
String: Mutability
Collection
중복 가능
순서 있음
struct Array<E>
interface List<out E>
interface MutableList<E> : List<E>
(class: ArrayList, …)
(*)
중복 불가 struct Set<E>
interface Set<out E>
interface MutableSet<E> : Set<E>
(class: LinkedHashSet, SortedSet, …)
Key의 중복 불가
Key, Value의 쌍
struct Dictionary<K, V>
interface Map<out K, out V>
interface MutableMap<K, V> : Map<K, V>
(class: LinkedHashMap, HashMap, …)
(*) Array도 존재하지만 JVM array에 대응하는 자료 구조로
Collection과는 성격이 약간 다름
Collection
중복 가능
순서 있음
struct Array<E>
interface List<out E>
interface MutableList<E> : List<E>
(class: ArrayList, …)
(*)
중복 불가 struct Set<E>
interface Set<out E>
interface MutableSet<E> : Set<E>
(class: LinkedHashSet, SortedSet, …)
Key의 중복 불가
Key, Value의 쌍
struct Dictionary<K, V>
interface Map<out K, out V>
interface MutableMap<K, V> : Map<K, V>
(class: LinkedHashMap, HashMap, …)
Value 타입
Collection
중복 가능
순서 있음
struct Array<E>
interface List<out E>
interface MutableList<E> : List<E>
(class: ArrayList, …)
(*)
중복 불가 struct Set<E>
interface Set<out E>
interface MutableSet<E> : Set<E>
(class: LinkedHashSet, SortedSet, …)
Key의 중복 불가
Key, Value의 쌍
struct Dictionary<K, V>
interface Map<out K, out V>
interface MutableMap<K, V> : Map<K, V>
(class: LinkedHashMap, HashMap, …)
Immutable/Mutable 인터페이스 제공
성격에 따라 다양한 실제 구현 클래스 사용가능 (Java)
Immutable Collections
Array /
List
let array: [String] = ["Swift", "Kotlin"]





print(array[0])



val list: List<String> =

listOf("Swift", "Kotlin")



println(list[1])





Set
let set: Set<String> = ["Swift", "Kotlin"]





if set.contains("Objc") { }


val set: Set<String> =

setOf("Swift", "Kotlin")



if ("Java" in set) { }



Dictionary /
Map
let dic: [String : Double] =

[“Swift" : 3.1, "Kotlin" : 1.1]

print(dic["Swift"])



val map: Map<String, Double> = 

mapOf("Swift" to 3.1, “Kotlin" to 1.1)

println(map["Kotlin"])

Immutable Collections
Array /
List
let array: [String] = ["Swift", "Kotlin"]





print(array[0])



val list: List<String> =

listOf("Swift", "Kotlin")



println(list[1])





Set
let set: Set<String> = ["Swift", "Kotlin"]





if set.contains("Objc") { }


val set: Set<String> =

setOf("Swift", "Kotlin")



if ("Java" in set) { }



Dictionary /
Map
let dic: [String : Double] =

[“Swift" : 3.1, "Kotlin" : 1.1]

print(dic["Swift"])



val map: Map<String, Double> = 

mapOf("Swift" to 3.1, “Kotlin" to 1.1)

println(map["Kotlin"])

Immutable Collections
Array /
List
let array: [String] = ["Swift", "Kotlin"]





print(array[0])



val list: List<String> =

listOf("Swift", "Kotlin")



println(list[1])





Set
let set: Set<String> = ["Swift", "Kotlin"]





if set.contains("Objc") { }


val set: Set<String> =

setOf("Swift", "Kotlin")



if ("Java" in set) { }



Dictionary /
Map
let dic: [String : Double] =

[“Swift" : 3.1, "Kotlin" : 1.1]

print(dic["Swift"])



val map: Map<String, Double> = 

mapOf("Swift" to 3.1, “Kotlin" to 1.1)

println(map["Kotlin"])

Immutable Collections
Array /
List
let array: [String] = ["Swift", "Kotlin"]





print(array[0])



val list: List<String> =

listOf("Swift", "Kotlin")



println(list[1])





Set
let set: Set<String> = ["Swift", "Kotlin"]





if set.contains("Objc") { }


val set: Set<String> =

setOf("Swift", "Kotlin")



if ("Java" in set) { }



Dictionary /
Map
let dic: [String : Double] =

[“Swift" : 3.1, "Kotlin" : 1.1]

print(dic["Swift"])



val map: Map<String, Double> = 

mapOf("Swift" to 3.1, “Kotlin" to 1.1)

println(map["Kotlin"])

Immutable Collections
Array /
List
let array: [String] = ["Swift", "Kotlin"]





print(array[0])



val list: List<String> =

listOf("Swift", "Kotlin")



println(list[1])





Set
let set: Set<String> = ["Swift", "Kotlin"]





if set.contains("Objc") { }


val set: Set<String> =

setOf("Swift", "Kotlin")



if ("Java" in set) { }



Dictionary /
Map
let dic: [String : Double] =

[“Swift" : 3.1, "Kotlin" : 1.1]

print(dic["Swift"])



val map: Map<String, Double> = 

mapOf("Swift" to 3.1, “Kotlin" to 1.1)

println(map["Kotlin"])

Mutable Collections
Array /
List
var array: [String] = ["Swift", "Kotlin"]





print(array[0])



array[0] = "Objc"
val list: MutableList<String> =

mutableListOf("Swift", "Kotlin")



println(list[1])



list[1] = "Java"

Set
var set: Set<String> = ["Swift", "Kotlin"]





if set.contains("Objc") { }


set.insert("Objc")
val set: MutableSet<String> =

mutableSetOf("Swift", "Kotlin")



if ("Java" in set) { }



set.add("Java")
Dictionary /
Map
var dic: [String : Double] =

[“Swift" : 3.1, "Kotlin" : 1.1]

print(dic["Swift"])



dic["Swift"] = 4.0
val map: MutableMap<String, Double> = 

mutableMapOf("Swift" to 3.1, “Kotlin" to 1.1)

println(map["Kotlin"])



map["Kotlin"] = 1.2
Mutable Collections
Array /
List
var array: [String] = ["Swift", "Kotlin"]





print(array[0])



array[0] = "Objc"
val list: MutableList<String> =

mutableListOf("Swift", "Kotlin")



println(list[1])



list[1] = "Java"

Set
var set: Set<String> = ["Swift", "Kotlin"]





if set.contains("Objc") { }


set.insert("Objc")
val set: MutableSet<String> =

mutableSetOf("Swift", "Kotlin")



if ("Java" in set) { }



set.add("Java")
Dictionary /
Map
var dic: [String : Double] =

[“Swift" : 3.1, "Kotlin" : 1.1]

print(dic["Swift"])



dic["Swift"] = 4.0
val map: MutableMap<String, Double> = 

mutableMapOf("Swift" to 3.1, “Kotlin" to 1.1)

println(map["Kotlin"])



map["Kotlin"] = 1.2
Mutable Collections
Array /
List
var array: [String] = ["Swift", "Kotlin"]





print(array[0])



array[0] = "Objc"
val list: MutableList<String> =

mutableListOf("Swift", "Kotlin")



println(list[1])



list[1] = "Java"

Set
var set: Set<String> = ["Swift", "Kotlin"]





if set.contains("Objc") { }


set.insert("Objc")
val set: MutableSet<String> =

mutableSetOf("Swift", "Kotlin")



if ("Java" in set) { }



set.add("Java")
Dictionary /
Map
var dic: [String : Double] =

[“Swift" : 3.1, "Kotlin" : 1.1]

print(dic["Swift"])



dic["Swift"] = 4.0
val map: MutableMap<String, Double> = 

mutableMapOf("Swift" to 3.1, “Kotlin" to 1.1)

println(map["Kotlin"])



map["Kotlin"] = 1.2
Mutable Collections
Array /
List
var array: [String] = ["Swift", "Kotlin"]





print(array[0])



array[0] = "Objc"
val list: MutableList<String> =

mutableListOf("Swift", "Kotlin")



println(list[1])



list[1] = "Java"

Set
var set: Set<String> = ["Swift", "Kotlin"]





if set.contains("Objc") { }


set.insert("Objc")
val set: MutableSet<String> =

mutableSetOf("Swift", "Kotlin")



if ("Java" in set) { }



set.add("Java")
Dictionary /
Map
var dic: [String : Double] =

[“Swift" : 3.1, "Kotlin" : 1.1]

print(dic["Swift"])



dic["Swift"] = 4.0
val map: MutableMap<String, Double> = 

mutableMapOf("Swift" to 3.1, “Kotlin" to 1.1)

println(map["Kotlin"])



map["Kotlin"] = 1.2
Mutable Collections
Array /
List
var array: [String] = ["Swift", "Kotlin"]





print(array[0])



array[0] = "Objc"
val list: MutableList<String> =

mutableListOf("Swift", "Kotlin")



println(list[1])



list[1] = "Java"

Set
var set: Set<String> = ["Swift", "Kotlin"]





if set.contains("Objc") { }


set.insert("Objc")
val set: MutableSet<String> =

mutableSetOf("Swift", "Kotlin")



if ("Java" in set) { }



set.add("Java")
Dictionary /
Map
var dic: [String : Double] =

[“Swift" : 3.1, "Kotlin" : 1.1]

print(dic["Swift"])



dic["Swift"] = 4.0
val map: MutableMap<String, Double> = 

mutableMapOf("Swift" to 3.1, “Kotlin" to 1.1)

println(map["Kotlin"])



map["Kotlin"] = 1.2
Mutable Collections
Array /
List
var array: [String] = ["Swift", "Kotlin"]





print(array[0])



array[0] = "Objc"
val list: MutableList<String> =

mutableListOf("Swift", "Kotlin")



println(list[1])



list[1] = "Java"

Set
var set: Set<String> = ["Swift", "Kotlin"]





if set.contains("Objc") { }


set.insert("Objc")
val set: MutableSet<String> =

mutableSetOf("Swift", "Kotlin")



if ("Java" in set) { }



set.add("Java")
Dictionary /
Map
var dic: [String : Double] =

[“Swift" : 3.1, "Kotlin" : 1.1]

print(dic["Swift"])



dic["Swift"] = 4.0
val map: MutableMap<String, Double> = 

mutableMapOf("Swift" to 3.1, “Kotlin" to 1.1)

println(map["Kotlin"])



map["Kotlin"] = 1.2
Value 타입이므로 let -> var 로
Copy-On-Write로 동작
Mutable Collections
Array /
List
var array: [String] = ["Swift", "Kotlin"]





print(array[0])



array[0] = "Objc"
val list: MutableList<String> =

mutableListOf("Swift", "Kotlin")



println(list[1])



list[1] = "Java"

Set
var set: Set<String> = ["Swift", "Kotlin"]





if set.contains("Objc") { }


set.insert("Objc")
val set: MutableSet<String> =

mutableSetOf("Swift", "Kotlin")



if ("Java" in set) { }



set.add("Java")
Dictionary /
Map
var dic: [String : Double] =

[“Swift" : 3.1, "Kotlin" : 1.1]

print(dic["Swift"])



dic["Swift"] = 4.0
val map: MutableMap<String, Double> = 

mutableMapOf("Swift" to 3.1, “Kotlin" to 1.1)

println(map["Kotlin"])



map["Kotlin"] = 1.2
Mutable 전용 인터페이스 이용
var는 단순히 변수를 재할당 가능하다는 의미
Swift의 Mutability
Value 타입으로 구현
변수의 타입만으로 Immutable / mutable 동작 구분 (let, var)
데이터 저장공간은 Reference type의 멤버 변수로 가짐
Mutable 타입의 경우 내용이 처음 변경될 때 새로운 객체 생성
(이때 저장공간 복사 -> Copy-On-Write)
Swift의 Mutability
Value 타입으로 구현
변수의 타입만으로 Immutable / mutable 동작 구분 (let, var)
데이터 저장공간은 Reference type의 멤버 변수로 가짐
Mutable 타입의 경우 내용이 처음 변경될 때 새로운 객체 생성
(이때 저장공간 복사 -> Copy-On-Write)


var original: [Int] = [1, 2]
var mutable = array
mutable.append(3)
original
struct Array<Int>
_storage
1, 2
…
refCount: 2
[1, 2]
mutable
struct Array<Int>
_storage
1, 2
Swift의 Mutability
Value 타입으로 구현
변수의 타입만으로 Immutable / mutable 동작 구분 (let, var)
데이터 저장공간은 Reference type의 멤버 변수로 가짐
Mutable 타입의 경우 내용이 처음 변경될 때 새로운 객체 생성
(이때 저장공간 복사 -> Copy-On-Write)


var original: [Int] = [1, 2]
var mutable = array
mutable.append(3)
original
struct Array<Int>
_storage
1, 2
…
refCount: 1
[1, 2]
mutable
struct Array<Int>
_storage
1, 2, 3
…
refCount: 1
[1, 2, 3]
Swift의 Mutability
하지만, 함수로는 var 타입 변수를 넘길 수 없다. (Swift3)


func append(var array: [Int]) {
array.append(3)
}
Swift의 Mutability


func append(var array: [Int]) {
array.append(3)
}
var mutable: [Int] = [1, 2]
append(array: mutable)
어짜피 Value 타입이기 때문에,
본래의 변수가 변하지 않는다
하지만, 함수로는 var 타입 변수를 넘길 수 없다. (Swift3)
Swift의 Mutability


func append(var array: [Int]) {
array.append(3)
}
var mutable: [Int] = [1, 2]
append(array: mutable)
하지만, 값을 변경해야하는 경우마다 데이터를 복사해야하는 것도 비효율적
하지만, 함수로는 var 타입 변수를 넘길 수 없다. (Swift3)
Swift의 Mutability
Pass by Reference


func append(array: inout [Int]) {
array.append(3)
}
var mutable: [Int] = [1, 2]
append(array: &mutable)
Swift의 Mutability


func append(array: inout [Int]) {
array.append(3)
}
var mutable: [Int] = [1, 2]
append(array: &mutable)
mutable
struct Array<Int>
_storage
1, 2
…
refCount: 1
[1, 2]
In-Out 파라미터
Swift의 Mutability


func append(array: inout [Int]) {
array.append(3)
}
var mutable: [Int] = [1, 2]
append(array: &mutable)
array (func append)
struct Array<Int>
_storage
1, 2
…
refCount: 1
[1, 2]
In-Out 파라미터
Swift의 Mutability
In-Out 파라미터


func append(array: inout [Int]) {
array.append(3)
}
var mutable: [Int] = [1, 2]
append(array: &mutable)
array (func append)
struct Array<Int>
_storage
1, 2, 3
…
refCount: 1
[1, 2, 3]
Swift의 Mutability


func append(array: inout [Int]) {
array.append(3)
}
var mutable: [Int] = [1, 2]
append(array: &mutable)
mutable
struct Array<Int>
_storage
1, 2, 3
…
refCount: 1
[1, 2, 3]
Copy없이 데이터를 변경할 수 있음
In-Out 파라미터
In-Out과 Reference


func increase(_ i: inout Int) {
i += 1
}
var number = 10
increase(&number)
print(number)
In-Out 파라미터
원래 변수의 주소가 넘어감
원래 변수의 value를 변경하게 됨
In-Out과 Reference


func increase(_ i: inout Int) {
i += 1
}
var number = 10
increase(&number)
print(number)


class Wrapper(var i: Int)
fun increase(wrapper: Wrapper) {
wrapper.i += 1
}
val number = Wrapper(10)
increase(number)
println(number.i)
원래 변수의 주소가 넘어감
원래 변수의 value를 변경하게 됨
Wrapper를 이용할 수 밖에 없음
In-Out 파라미터
In-Out과 Reference


func increase(_ i: inout Int) {
i += 1
}
var number = 10
increase(&number)
print(number)


class Wrapper(var i: Int)
fun increase(wrapper: Wrapper) {
wrapper.i += 1
}
val number = Wrapper(10)
increase(number)
println(number.i)
원래 변수의 주소가 넘어감
원래 변수의 value를 변경하게 됨
Wrapper를 이용할 수 밖에 없음
In-Out 파라미터
이것이 두 언어의 Mutability 구현의 차이
let swift(17)
Extension
Extension
extension Int {
var length: Int {
return String(self).characters.count
}
func concat(_ to: Int) -> String {
return String(self) + String(to)
}
}
print(1234.length) // 4
print(123.concat(456)) // "123456"
val Int.length: Int get() = toString().length
fun Int.concat(to: Int): String =
toString() + to.toString()


println(123.length) // 3


println(123.concat(456)) // "123456"

extension 정의 block 사용
Extension
extension Int {
var length: Int {
return String(self).characters.count
}
func concat(_ to: Int) -> String {
return String(self) + String(to)
}
}
print(1234.length) // 4
print(123.concat(456)) // "123456"
val Int.length: Int get() = toString().length
fun Int.concat(to: Int): String =
toString() + to.toString()


println(123.length) // 3


println(123.concat(456)) // "123456"

extension 정의 block 사용 extension할 각 함수, 프로퍼티 별로 정의
Extension
extension Int {
var length: Int {
return String(self).characters.count
}
func concat(_ to: Int) -> String {
return String(self) + String(to)
}
}
print(1234.length) // 4
print(123.concat(456)) // "123456"
val Int.length: Int get() = toString().length
fun Int.concat(to: Int): String =
toString() + to.toString()


println(123.length) // 3


println(123.concat(456)) // "123456"

extension 정의 block 사용 extension할 각 함수, 프로퍼티 별로 정의
fun length(receiver: Int) = receiver.toString().length
fun concat(receiver: Int, to: Int): String = receiver.toString() + to.toString()
실제로는 아래와 같은 함수로 컴파일 됨
Trait
class MyClass { }
protocol MyProtocol { }
extension MyClass: MyProtocol { }
let bar: MyProtocol = MyClass()
extension MyProtocol {
func foo() { }
}
Trait
class MyClass { }
protocol MyProtocol { }
extension MyClass: MyProtocol { }
let bar: MyProtocol = MyClass()
extension MyProtocol {
func foo() { }
}
bar.foo()
let bar2: MyClass = MyClass()
bar2.foo()
Trait
class MyClass { }
protocol MyProtocol { }
extension MyClass: MyProtocol { }
let bar: MyProtocol = MyClass()
extension MyProtocol {
func foo() { }
}
bar.foo()
let bar2: MyClass = MyClass()
bar2.foo()
AKA: Protocol Oriented Programming
class MyClass { }
protocol MyProtocol { }
extension MyClass: MyProtocol { }
let bar: MyProtocol = MyClass()
extension MyProtocol {
func foo() { }
}
bar.foo()
let bar2: MyClass = MyClass()
bar2.foo()
interface MyProtocol {
fun foo() { }
}
class MyClass : MyProtocol
val bar: MyProtocol = MyClass()
bar.foo()
AKA: Protocol Oriented Programming
Trait
class MyClass { }
protocol MyProtocol { }
extension MyClass: MyProtocol { }
let bar: MyProtocol = MyClass()
extension MyProtocol {
func foo() { }
}
bar.foo()
let bar2: MyClass = MyClass()
bar2.foo()
interface MyProtocol {
fun foo() { }
}
class MyClass : MyProtocol
val bar: MyProtocol = MyClass()
bar.foo()
fun MyProtocol.foo2() { }
bar.foo2()
val bar2: MyClass = MyClass()
bar2.foo2()
AKA: Protocol Oriented Programming
Trait
class MyClass { }
protocol MyProtocol { }
extension MyClass: MyProtocol { }
let bar: MyProtocol = MyClass()
extension MyProtocol {
func foo() { }
}
bar.foo()
let bar2: MyClass = MyClass()
bar2.foo()
interface MyProtocol {
fun foo() { }
}
class MyClass : MyProtocol
val bar: MyProtocol = MyClass()
bar.foo()
fun MyProtocol.foo2() { }
bar.foo2()
val bar2: MyClass = MyClass()
bar2.foo2()
AKA: Protocol Oriented Programming 미리 인터페이스가 클래스에 적용이 되어야함
Trait
Trait
extension String: MyProtocol {
}
"Swift".foo()
정의되어 있는 class/struct에도 trait 가능
class MyClass { }
protocol MyProtocol { }
extension MyClass: MyProtocol { }
let bar: MyProtocol = MyClass()
extension MyProtocol {
func foo() { }
}
bar.foo()
let bar2: MyClass = MyClass()
bar2.foo()
interface MyProtocol {
fun foo() { }
}
class MyClass : MyProtocol
val bar: MyProtocol = MyClass()
bar.foo()
fun MyProtocol.foo2() { }
bar.foo2()
val bar2: MyClass = MyClass()
bar2.foo2()
AKA: Protocol Oriented Programming 미리 인터페이스가 클래스에 적용이 되어야함
Trait
extension String: MyProtocol {
}
"Swift".foo()
// ...
// ...
// ...
정의되어 있는 class/struct에도 trait 가능 안됨
class MyClass { }
protocol MyProtocol { }
extension MyClass: MyProtocol { }
let bar: MyProtocol = MyClass()
extension MyProtocol {
func foo() { }
}
bar.foo()
let bar2: MyClass = MyClass()
bar2.foo()
interface MyProtocol {
fun foo() { }
}
class MyClass : MyProtocol
val bar: MyProtocol = MyClass()
bar.foo()
fun MyProtocol.foo2() { }
bar.foo2()
val bar2: MyClass = MyClass()
bar2.foo2()
AKA: Protocol Oriented Programming 미리 인터페이스가 클래스에 적용이 되어야함
유틸리티를 위한 extension


fun <T> T.apply(block: T.() -> Unit): T { block(); return this }
val sum = 1.apply { println("get 1") } + 2 // 3


fun <T, R> T.let(block: (T) -> R): R = block(this)
val file = "filename".let { File(it) }


fun CharSequence?.isNullOrBlank(): Boolean = this == null || this.isBlank()
val str: String? = null
if (str.isNullOrBlank()) { }
Nullable에 대한 extension
모든 타입에 대한 넘나 편리한 유틸리티
선언형 표현에 크게 도움이 됨
let swift(17)
메모리 관리: ARC vs. GC
Heap


func foo() {
let subview: UIView = UIView(rect: CGRect.zero)
self.view.addSubview(subview)
subview.removeFromSuperview()
}
ARC
class UIView
refCount: 1
…
Stack
subview:
class UIViewController
refCount: 1
subview:
…
Heap


func foo() {
let subview: UIView = UIView(rect: CGRect.zero)
self.view.addSubview(subview)
subview.removeFromSuperview()
}
ARC
class UIView
refCount: 2
…
Stack
subview:
class UIViewController
refCount: 1
subview:
…
Heap


func foo() {
let subview: UIView = UIView(rect: CGRect.zero)
self.view.addSubview(subview)
subview.removeFromSuperview()
}
ARC
class UIView
refCount: 1
…
Stack
subview:
class UIViewController
refCount: 1
subview:
…
Heap


func foo() {
let subview: UIView = UIView(rect: CGRect.zero)
self.view.addSubview(subview)
subview.removeFromSuperview()
}
ARC
class UIView
refCount: 0
…
Stack
subview:
class UIViewController
refCount: 1
subview:
…
Heap


func foo() {
let subview: UIView = UIView(rect: CGRect.zero)
self.view.addSubview(subview)
subview.removeFromSuperview()
}
ARC
Stack
class UIViewController
refCount: 1
subview:
…
Heap


fun foo() {

val subview = View(context)



this.viewGroup.addView(subview)



this.viewGroup.removeView(subview)

}
GC
class View
…
Stack
subview:
class ViewGroup
child:
… GC task
thread
Heap


fun foo() {

val subview = View(context)



this.viewGroup.addView(subview)



this.viewGroup.removeView(subview)

}
GC
class View
…
Stack
subview:
class ViewGroup
child:
… GC task
thread
Heap


fun foo() {

val subview = View(context)



this.viewGroup.addView(subview)



this.viewGroup.removeView(subview)

}
GC
class View
…
Stack
subview:
class ViewGroup
child:
… GC task
thread
Heap


fun foo() {

val subview = View(context)



this.viewGroup.addView(subview)



this.viewGroup.removeView(subview)

}
GC
class View
…
Stack
subview:
class ViewGroup
child:
… GC task
thread
Heap


fun foo() {

val subview = View(context)



this.viewGroup.addView(subview)



this.viewGroup.removeView(subview)

}
GC
class View
…
Stack
class ViewGroup
child:
… GC task
thread
바로 해제되지 않는다.
Heap


fun foo() {

val subview = View(context)



this.viewGroup.addView(subview)



this.viewGroup.removeView(subview)

}
GC
class View
…
Stack
class ViewGroup
child:
…
No ref?
GC task
thread
Heap


fun foo() {

val subview = View(context)



this.viewGroup.addView(subview)



this.viewGroup.removeView(subview)

}
GC
class View
…
Stack
class ViewGroup
child:
…
No ref?
GC task
thread
Heap


fun foo() {

val subview = View(context)



this.viewGroup.addView(subview)



this.viewGroup.removeView(subview)

}
GC
Stack
class ViewGroup
child:
… GC task
thread
ARC vs GC: ReactiveX
var disposeBag = DisposeBag()
func startCount() {
Observable<Int>.interval(1.0, scheduler: s)
.subscribe(onNext: { print("next: ($0)") })
.addDisposableTo(disposeBag)
}
func stopCount() {
disposeBag = DisposeBag()
}

private val disposables = CompositeDisposable()



fun startCount() {

Observable.interval(0, 1, TimeUnit.SECONDS)

.subscribe { Log.d(TAG, "next: $it") }

.let { disposables.add(it) }

}



fun stopCount() {

disposables.clear()

}
1. disposeBag 변수에 다른 값을 할당
Subscription을 명시적으로 끝내야할 때
ARC vs GC: ReactiveX
var disposeBag = DisposeBag()
func startCount() {
Observable<Int>.interval(1.0, scheduler: s)
.subscribe(onNext: { print("next: ($0)") })
.addDisposableTo(disposeBag)
}
func stopCount() {
disposeBag = DisposeBag()
}

private val disposables = CompositeDisposable()



fun startCount() {

Observable.interval(0, 1, TimeUnit.SECONDS)

.subscribe { Log.d(TAG, "next: $it") }

.let { disposables.add(it) }

}



fun stopCount() {

disposables.clear()

}
1. disposeBag 변수에 다른 값을 할당
2. 기존 DisposeBag 객체는 refcount == 0 이 됨
Subscription을 명시적으로 끝내야할 때
ARC vs GC: ReactiveX
var disposeBag = DisposeBag()
func startCount() {
Observable<Int>.interval(1.0, scheduler: s)
.subscribe(onNext: { print("next: ($0)") })
.addDisposableTo(disposeBag)
}
func stopCount() {
disposeBag = DisposeBag()
}

private val disposables = CompositeDisposable()



fun startCount() {

Observable.interval(0, 1, TimeUnit.SECONDS)

.subscribe { Log.d(TAG, "next: $it") }

.let { disposables.add(it) }

}



fun stopCount() {

disposables.clear()

}
1. disposeBag 변수에 다른 값을 할당
2. 기존 DisposeBag 객체는 refcount == 0 이 됨
3. 즉시 메모리 해제가 되며 deinit이 불림
Subscription을 명시적으로 끝내야할 때
ARC vs GC: ReactiveX
var disposeBag = DisposeBag()
func startCount() {
Observable<Int>.interval(1.0, scheduler: s)
.subscribe(onNext: { print("next: ($0)") })
.addDisposableTo(disposeBag)
}
func stopCount() {
disposeBag = DisposeBag()
}

private val disposables = CompositeDisposable()



fun startCount() {

Observable.interval(0, 1, TimeUnit.SECONDS)

.subscribe { Log.d(TAG, "next: $it") }

.let { disposables.add(it) }

}



fun stopCount() {

disposables.clear()

}
1. disposeBag 변수에 다른 값을 할당
2. 기존 DisposeBag 객체는 refcount == 0 이 됨
3. 즉시 메모리 해제가 되며 deinit이 불림
4. 가지고 있던 구독을 dispose 함
Subscription을 명시적으로 끝내야할 때


public final class DisposeBag: DisposeBase {
…
deinit {
dispose()
}
}
ARC vs GC: ReactiveX
var disposeBag = DisposeBag()
func startCount() {
Observable<Int>.interval(1.0, scheduler: s)
.subscribe(onNext: { print("next: ($0)") })
.addDisposableTo(disposeBag)
}
func stopCount() {
disposeBag = DisposeBag()
}

private val disposables = CompositeDisposable()



fun startCount() {

Observable.interval(0, 1, TimeUnit.SECONDS)

.subscribe { Log.d(TAG, "next: $it") }

.let { disposables.add(it) }

}



fun stopCount() {

disposables.clear()

}
1. disposeBag 변수에 다른 값을 할당
2. 기존 DisposeBag 객체는 refcount == 0 이 됨
3. 즉시 메모리 해제가 되며 deinit이 불림
4. 가지고 있던 구독을 dispose 함
GC에서는 언제 해제될지 예측할 수 없다.
Subscription을 명시적으로 끝내야할 때
ARC vs GC: ReactiveX
var disposeBag = DisposeBag()
func startCount() {
Observable<Int>.interval(1.0, scheduler: s)
.subscribe(onNext: { print("next: ($0)") })
.addDisposableTo(disposeBag)
}
func stopCount() {
disposeBag = DisposeBag()
}

private val disposables = CompositeDisposable()



fun startCount() {

Observable.interval(0, 1, TimeUnit.SECONDS)

.subscribe { Log.d(TAG, "next: $it") }

.let { disposables.add(it) }

}



fun stopCount() {

disposables.clear()

}
1. disposeBag 변수에 다른 값을 할당
2. 기존 DisposeBag 객체는 refcount == 0 이 됨
3. 즉시 메모리 해제가 되며 deinit이 불림
4. 가지고 있던 구독을 dispose 함
GC에서는 언제 해제될지 예측할 수 없다.
-> 명시적으로 CompositeDisposable 이용
Subscription을 명시적으로 끝내야할 때
ARC vs GC: ReactiveX
var disposeBag = DisposeBag()
func startCount() {
Observable<Int>.interval(1.0, scheduler: s)
.subscribe(onNext: { print("next: ($0)") })
.addDisposableTo(disposeBag)
}
func stopCount() {
disposeBag = DisposeBag()
}

private val disposables = CompositeDisposable()



fun startCount() {

Observable.interval(0, 1, TimeUnit.SECONDS)

.subscribe { Log.d(TAG, "next: $it") }

.let { disposables.add(it) }

}



fun stopCount() {

disposables.clear()

}
1. disposeBag 변수에 다른 값을 할당
2. 기존 DisposeBag 객체는 refcount == 0 이 됨
3. 즉시 메모리 해제가 되며 deinit이 불림
4. 가지고 있던 구독을 dispose 함
GC에서는 언제 해제될지 예측할 수 없다.
-> 명시적으로 CompositeDisposable 이용
Subscription을 명시적으로 끝내야할 때
*) RxSwift3에도 CompositeDisposable은 있으나 clear가 없이 dispose만 있다. 재활용이 불가능
ARC vs GC: 순환 참조


class MyClass {
var closure: (() -> Void)?
init() {
closure = { self.foo() }
}
func foo() { }
}
var c: MyClass? = MyClass()
c = nil
class MyClass {
var lambda: ((Unit) -> Unit)?
init {
lambda = { this.foo() }
}
fun foo() { }
}
var c: MyClass? = MyClass()
c = null
ARC vs GC: 순환 참조


class MyClass {
var closure: (() -> Void)?
init() {
closure = { self.foo() }
}
func foo() { }
}
var c: MyClass? = MyClass()
c = nil
class MyClass {
var lambda: ((Unit) -> Unit)?
init {
lambda = { this.foo() }
}
fun foo() { }
}
var c: MyClass? = MyClass()
c = null
ARC vs GC: 순환 참조


class MyClass {
var closure: (() -> Void)?
init() {
closure = { self.foo() }
}
func foo() { }
}
var c: MyClass? = MyClass()
c = nil
class MyClass {
var lambda: ((Unit) -> Unit)?
init {
lambda = { this.foo() }
}
fun foo() { }
}
var c: MyClass? = MyClass()
c = null
순환 참조 발생 -> 런타임 메모리 누수 발생
ARC vs GC: 순환 참조


class MyClass {
var closure: (() -> Void)?
init() {
closure = { self.foo() }
}
func foo() { }
}
var c: MyClass? = MyClass()
c = nil
class MyClass {
var lambda: ((Unit) -> Unit)?
init {
lambda = { this.foo() }
}
fun foo() { }
}
var c: MyClass? = MyClass()
c = null
순환 참조 발생 -> 런타임 메모리 누수 발생
왜일까?
ARC vs GC: 순환 참조


class MyClass {
var closure: (() -> Void)?
init() {
closure = { self.foo() }
}
func foo() { }
}
var c: MyClass? = MyClass()
c = nil
c:
ARC vs GC: 순환 참조


class MyClass {
var closure: (() -> Void)?
init() {
closure = { self.foo() }
}
func foo() { }
}
var c: MyClass? = MyClass()
c = nil
class MyClass
refCount: 1
closure:
…
Closure
refCount: 1
“self”:
…
c:
ARC vs GC: 순환 참조


class MyClass {
var closure: (() -> Void)?
init() {
closure = { self.foo() }
}
func foo() { }
}
var c: MyClass? = MyClass()
c = nil
class MyClass
refCount: 1
closure:
…
Closure
refCount: 1
“self”:
…
c:
ARC vs GC: 순환 참조


class MyClass {
var closure: (() -> Void)?
init() {
closure = { self.foo() }
}
func foo() { }
}
var c: MyClass? = MyClass()
c = nil
class MyClass
refCount: 2
closure:
…
Closure
refCount: 1
“self”:
…
c:
ARC vs GC: 순환 참조


class MyClass {
var closure: (() -> Void)?
init() {
closure = { self.foo() }
}
func foo() { }
}
var c: MyClass? = MyClass()
c = nil
class MyClass
refCount: 2
closure:
…
Closure
refCount: 1
“self”:
…
순환 참조 발생
c:
ARC vs GC: 순환 참조


class MyClass {
var closure: (() -> Void)?
init() {
closure = { self.foo() }
}
func foo() { }
}
var c: MyClass? = MyClass()
c = nil
class MyClass
refCount: 2
closure:
…
Closure
refCount: 1
“self”:
…
c:
ARC vs GC: 순환 참조


class MyClass {
var closure: (() -> Void)?
init() {
closure = { self.foo() }
}
func foo() { }
}
var c: MyClass? = MyClass()
c = nil
class MyClass
refCount: 1
closure:
…
Closure
refCount: 1
“self”:
…
c:
ARC vs GC: 순환 참조


class MyClass {
var closure: (() -> Void)?
init() {
closure = { self.foo() }
}
func foo() { }
}
var c: MyClass? = MyClass()
c = nil
class MyClass
refCount: 1
closure:
…
Closure
refCount: 1
“self”:
…
이건 이제 어느 누구도 해제할 수 없다.
-> 메모리 누수!!
c:
ARC vs GC: 순환 참조


class MyClass {
var closure: (() -> Void)?
init() {
closure = {[weak self] in self?.foo()}
}
func foo() { }
}
var c: MyClass? = MyClass()
c = nil
class MyClass
refCount: 1
closure:
…
Closure
refCount: 1
“self”:
…
c:
ARC vs GC: 순환 참조


class MyClass {
var closure: (() -> Void)?
init() {
closure = {[weak self] in self?.foo()}
}
func foo() { }
}
var c: MyClass? = MyClass()
c = nil
class MyClass
refCount: 1
closure:
…
Closure
refCount: 1
“self”:
…
c:
ARC vs GC: 순환 참조


class MyClass {
var closure: (() -> Void)?
init() {
closure = {[weak self] in self?.foo()}
}
func foo() { }
}
var c: MyClass? = MyClass()
c = nil
class MyClass
refCount: 1
closure:
…
Closure
refCount: 1
“self”:
…
weak 참조, refCount 증가시키지 않음
(unowned도 비슷)
c:
ARC vs GC: 순환 참조


class MyClass {
var closure: (() -> Void)?
init() {
closure = {[weak self] in self?.foo()}
}
func foo() { }
}
var c: MyClass? = MyClass()
c = nil
class MyClass
refCount: 1
closure:
…
Closure
refCount: 1
“self”:
…
c:
ARC vs GC: 순환 참조


class MyClass {
var closure: (() -> Void)?
init() {
closure = {[weak self] in self?.foo()}
}
func foo() { }
}
var c: MyClass? = MyClass()
c = nil
class MyClass
refCount: 0
closure:
…
Closure
refCount: 1
“self”:
…
c:
ARC vs GC: 순환 참조


class MyClass {
var closure: (() -> Void)?
init() {
closure = {[weak self] in self?.foo()}
}
func foo() { }
}
var c: MyClass? = MyClass()
c = nil
Closure
refCount: 0
“self”: nil
…
c:
ARC vs GC: 순환 참조


class MyClass {
var closure: (() -> Void)?
init() {
closure = {[weak self] in self?.foo()}
}
func foo() { }
}
var c: MyClass? = MyClass()
c = nil
ARC vs GC: 순환 참조


class MyClass {
var closure: (() -> Void)?
init() {
closure = {[weak self] in self?.foo()}
}
func foo() { }
}
var c: MyClass? = MyClass()
c = nil
ARC vs GC: 순환 참조
class MyClass {
var lambda: ((Unit) -> Unit)?
init {
lambda = { this.foo() }
}
fun foo() { }
}
var c: MyClass? = MyClass()
c = null
c: class MyClass
lambda
…
Lambda
“self”:
…
ARC vs GC: 순환 참조
class MyClass {
var lambda: ((Unit) -> Unit)?
init {
lambda = { this.foo() }
}
fun foo() { }
}
var c: MyClass? = MyClass()
c = null
c: class MyClass
lambda
…
Lambda
“self”:
…
ARC vs GC: 순환 참조
class MyClass {
var lambda: ((Unit) -> Unit)?
init {
lambda = { this.foo() }
}
fun foo() { }
}
var c: MyClass? = MyClass()
c = null
c: class MyClass
lambda
…
Lambda
“self”:
…
ARC vs GC: 순환 참조
class MyClass {
var lambda: ((Unit) -> Unit)?
init {
lambda = { this.foo() }
}
fun foo() { }
}
var c: MyClass? = MyClass()
c = null
c: class MyClass
lambda
…
Lambda
“self”:
…
No ref?
GC task
thread
ARC vs GC: 순환 참조
class MyClass {
var lambda: ((Unit) -> Unit)?
init {
lambda = { this.foo() }
}
fun foo() { }
}
var c: MyClass? = MyClass()
c = null
c: class MyClass
lambda
…
Lambda
“self”:
…
GC task
thread
ARC vs GC: 순환 참조
class MyClass {
var lambda: ((Unit) -> Unit)?
init {
lambda = { this.foo() }
}
fun foo() { }
}
var c: MyClass? = MyClass()
c = null
c:
GC task
thread
ARC vs GC: 순환 참조
class MyClass {
var lambda: ((Unit) -> Unit)?
init {
lambda = { this.foo() }
}
fun foo() { }
}
var c: MyClass? = MyClass()
c = null
ARC vs GC: 순환 참조


class MyClass {
var closure: (() -> Void)?
init() {
closure = {[weak self] in self?.foo()}
}
func foo() { }
}
var c: MyClass? = MyClass()
c = nil
class MyClass {
var lambda: ((Unit) -> Unit)?
init {
lambda = { this.foo() }
}
fun foo() { }
}
var c: MyClass? = MyClass()
c = null
­ 부록
“너무 길어서 통편집된 주제들”
let swift(17)
제어 구문
switch / when
let index = 100

let validRange = 0...1000
let special: Set<Int> = [100, 101]
switch index {
case 0...10, 20, 30: print("0~10, 20, 30")
case 11, 22, 33: print("11, 22, 33")
case _ where special.contains(index): print("special")
case validRange: print("valid")
default: print("invalid")
}
val index = 11

val validRange = 0..1000
val special = setOf(100, 101)
when (index) {
!in validRange -> println("invalid")
in 0..10, 20, 30 -> println("0~10, 20, 30")
11, 22, 33 -> println("11, 22, 33")
in special -> println("special")
else -> println("valid")
}
공통점: break 필요없음.
주의점:
Swift의 switch에 익숙해지면
다른 언어 (Java, C, C++) switch에서 break 빼먹기 쉬움
-> 컴파일 에러 안남, 버그
switch / when
let index = 100

let validRange = 0...1000
let special: Set<Int> = [100, 101]
switch index {
case 0...10, 20, 30: print("0~10, 20, 30")
case 11, 22, 33: print("11, 22, 33")
case _ where special.contains(index): print("special")
case validRange: print("valid")
default: print("invalid")
}
val index = 11

val validRange = 0..1000
val special = setOf(100, 101)
when (index) {
!in validRange -> println("invalid")
in 0..10, 20, 30 -> println("0~10, 20, 30")
11, 22, 33 -> println("11, 22, 33")
in special -> println("special")
else -> println("valid")
}
- enum의 associated value 가능
- tuple 가능
switch / when
let index = 100

let validRange = 0...1000
let special: Set<Int> = [100, 101]
switch index {
case 0...10, 20, 30: print("0~10, 20, 30")
case 11, 22, 33: print("11, 22, 33")
case _ where special.contains(index): print("special")
case validRange: print("valid")
default: print("invalid")
}
val index = 11

val validRange = 0..1000
val special = setOf(100, 101)
when (index) {
!in validRange -> println("invalid")
in 0..10, 20, 30 -> println("0~10, 20, 30")
11, 22, 33 -> println("11, 22, 33")
in special -> println("special")
else -> println("valid")
}
- enum의 associated value 가능
- tuple 가능


when {
str.isEmpty() -> println("str empty")
str.length > 100 -> println("str too long")
File(str).exists() -> println("file exists")
else -> println("file not found")
}
if .. else if .. else if … else 의 가독성 개선
제어 구문과 Expression
Expression: 값을 가진 구문
index + 3 "Kotlin $version” str.length + 10 str.isEmpty()
제어 구문과 Expression
Expression: 값을 가진 구문
index + 3 "Kotlin $version” str.length + 10 str.isEmpty()
if (count == 0) { "Empty" } else { "Count: $count" } if…else 도 Expression!
제어 구문과 Expression
Expression: 값을 가진 구문
index + 3 "Kotlin $version” str.length + 10 str.isEmpty()
if (count == 0) { "Empty" } else { "Count: $count" }


val str = if (count == 0) "Empty" else "Count: $count"



let str = count == 0 ? "Empty" : "Count: (count)"

if…else 도 Expression!
제어 구문과 Expression
Expression: 값을 가진 구문
index + 3 "Kotlin $version” str.length + 10 str.isEmpty()
if (count == 0) { "Empty" } else { "Count: $count" }


val str = if (count == 0) "Empty" else "Count: $count"



let str = count == 0 ? "Empty" : "Count: (count)"

if…else 도 Expression!
제어 구문과 Expression


val str =
if (count == 0) {
notifyEmpty()
"Empty"
} else {
total++
"Count: $count"
}
맨 마지막 expression이 Block의 값
제어 구문과 Expression


val str =
if (count == 0) {
notifyEmpty()
"Empty"
} else {
total++
"Count: $count"
}
다른 작업을 할 수 있음
제어 구문과 Expression


val str =
if (count == 0) {
notifyEmpty()
"Empty"
} else {
total++
"Count: $count"
}


val message = when {
str.isEmpty() -> "empty"
str.length > 100 -> "too long"
File(str).exists() -> "file exists"
else -> "file not found"
}
when 도 expression
중간의 임시 변수 없이 값을 바로 얻어
변수를 초기화하거나, 함수 인자로 넘길때 편리함
-> 선언형으로 코드를 작성하기 쉬움
for 루프
for (int i = 0; i < array.count; i++) {
NSString* str = array[i];
// ...
}
c-style의 전통적인 for 루프
for (int i = 0; i < array.count; i++) {
NSString* str = array[i];
// ...
}
for 루프
c-style의 전통적인 for 루프
for (int i = 0; i < array.count; i++) {
NSString* str = array[i];
// ...
}
직관적이지 않다더라…
심지어 는 ++도 없앰…
for 루프
c-style의 전통적인 for 루프
Iterator와 for 루프
Element
let array = ["Swift", "Kotlin"]
for str in array {
print(str)
}
val array = listOf("Swift", "Kotlin")

for (str in array) {
println(str)
}

index와

Element
for (index, str) in array.enumerated() {
print("(index): (str)")
}
for ((index, str) in array.withIndex()) {
println("$index: $str")
}
index
for i in 0..<100 {
}
for (i in 0 until 100) {
}
Iterator와 for 루프
Element
let array = ["Swift", "Kotlin"]
for str in array {
print(str)
}
val array = listOf("Swift", "Kotlin")

for (str in array) {
println(str)
}

index와

Element
for (index, str) in array.enumerated() {
print("(index): (str)")
}
for ((index, str) in array.withIndex()) {
println("$index: $str")
}
index
for i in 0..<100 {
}
for (i in 0 until 100) {
}
Iterator와 for 루프
Element
let array = ["Swift", "Kotlin"]
for str in array {
print(str)
}
val array = listOf("Swift", "Kotlin")

for (str in array) {
println(str)
}

index와

Element
for (index, str) in array.enumerated() {
print("(index): (str)")
}
for ((index, str) in array.withIndex()) {
println("$index: $str")
}
index
for i in 0..<100 {
}
for (i in 0 until 100) {
}
Iterator와 for 루프
Element
let array = ["Swift", "Kotlin"]
for str in array {
print(str)
}
val array = listOf("Swift", "Kotlin")

for (str in array) {
println(str)
}

index와

Element
for (index, str) in array.enumerated() {
print("(index): (str)")
}
for ((index, str) in array.withIndex()) {
println("$index: $str")
}
index
for i in 0..<100 {
}
for (i in 0 until 100) {
}
Iterator와 for 루프
Element
let array = ["Swift", "Kotlin"]
for str in array {
print(str)
}
val array = listOf("Swift", "Kotlin")

for (str in array) {
println(str)
}

index와

Element
for (index, str) in array.enumerated() {
print("(index): (str)")
}
for ((index, str) in array.withIndex()) {
println("$index: $str")
}
index
for i in 0..<100 {
}
for (i in 0...99) {
}
let swift(17)
함수
함수
func message(status: Int) -> String {
return “TBD"
}
fun message(status: Int) : String {
return "TBD"
}
fun message(status: Int) : String = "TBD"
func message(status: Int) -> String {
switch (status) {
case 200: return "OK"
case 201...299: return "Success"
case 300...399: return "Redirect"
case 400..<500: return "Client error"
case 500..<600: return "Server error"
default: return “Undefined"
}
}
fun message(status: Int) : String =
when (status) {
200 -> "OK"
in 201..299 -> "Success"
in 300..399 -> "Redirect"
in 400 until 500 -> "Client error"
in 500 until 600 -> "Server error"
else -> "Undefined"
}
Named Argument
func insert(name: String, index: Int) {
// check index
storage[index] = name
}
insert(name: "Swift", index: 0)
fun insert(name: String, index: Int) {
// check index
storage[index] = name
}
insert(name = "Kotlin", index = 0)
insert("Kotlin", 0)
insert(index = 0, name = "Kotlin")
func insert(_ name: String, at index: Int) {
// check index
storage[index] = name
}
insert("Swift", at: 0)
함수의 각 파라미터 이름을 붙여 호출할 수 있음
기본값
func insert(name: String, index: Int = 0) {
// check index
storage[index] = name
}
insert(name: "Swift")
fun insert(name: String, index: Int = 0) {
// check index
storage[index] = name
}
insert("Kotlin")
파라미터에 기본값을 줄 수 있음
로컬 함수
로컬 함수
func foo(_ factor: Int) {

func calculate(_ i: Int) -> Int {
return i * factor
}
for i in 1...10 {
print(calculate(i))
}
}
fun foo(factor: Int) {

fun calculate(i: Int) = i * factor
for (i in 1..10) {
println(calculate(i))
}
}
로컬 함수는 로컬 변수에 접근할 수 있음
일급 함수
func length(str: String) -> Int {
return str.characters.count
}
var foo: (String) -> Int
foo = length
print(foo("Swift"))
fun length(str: String): Int = str.length




var foo: (String) -> Int
foo = ::length
println(foo("Kotlin"))
- 함수도 타입이 있고 변수에 할당하고 파라미터로 넘길 수 있다.
일급 함수
func length(str: String) -> Int {
return str.characters.count
}
var foo: (String) -> Int
foo = length
print(foo("Swift"))
foo = { str in Int(str) ?? 0 }
print(foo("Swift"))
fun length(str: String): Int = str.length




var foo: (String) -> Int
foo = ::length
println(foo("Kotlin"))
foo = { str -> str.toIntOrNull() ?: 0 }
println(foo("Kotlin"))
- 함수도 타입이 있고 변수에 할당하고 파라미터로 넘길 수 있다.
- 익명함수를 런타임에 만들 수 있다.
Closure Lambda
함수형 표현
let array = [0, 1, 2, 3]
array.filter { $0 > 0 }
.map { "[index: ($0)]" }
.forEach { print($0) }
val list = listOf(0, 1, 2, 3)
list.filter { it > 0 }
.map { "[index: $it]" }
.forEach { println(it) }
자세한 설명은 세션의 범위를 넘어서므로 생략
보통 Collection 등의 extension에 공통적으로 정의됨
let swift(17)
정리
정리
변수의 타입
타입 추론
Optional / Nullable
Value타입과 Reference타입의 Immutable / Mutable
Extension과 Trait
ARC vs. GC
제어구문의 표현형과 선언형 문법
Iterator를 이용한 for 루프 문법
Closure/Lambda와 함수형 구문
let swift(17)

Más contenido relacionado

La actualidad más candente

Zagor Ludens 149 - Tragičan bijeg
Zagor Ludens  149 - Tragičan bijegZagor Ludens  149 - Tragičan bijeg
Zagor Ludens 149 - Tragičan bijegStripovizijaStripovi
 
Deep dive into Coroutines on JVM @ KotlinConf 2017
Deep dive into Coroutines on JVM @ KotlinConf 2017Deep dive into Coroutines on JVM @ KotlinConf 2017
Deep dive into Coroutines on JVM @ KotlinConf 2017Roman Elizarov
 
KSUG 스프링캠프 2019 발표자료 - "무엇을 테스트할 것인가, 어떻게 테스트할 것인가"
KSUG 스프링캠프 2019 발표자료 - "무엇을 테스트할 것인가, 어떻게 테스트할 것인가"KSUG 스프링캠프 2019 발표자료 - "무엇을 테스트할 것인가, 어떻게 테스트할 것인가"
KSUG 스프링캠프 2019 발표자료 - "무엇을 테스트할 것인가, 어떻게 테스트할 것인가"용근 권
 
Unit Test and TDD
Unit Test and TDDUnit Test and TDD
Unit Test and TDDViet Tran
 
Elastic Search (엘라스틱서치) 입문
Elastic Search (엘라스틱서치) 입문Elastic Search (엘라스틱서치) 입문
Elastic Search (엘라스틱서치) 입문SeungHyun Eom
 
React Lifecycle and Reconciliation
React Lifecycle and ReconciliationReact Lifecycle and Reconciliation
React Lifecycle and ReconciliationZhihao Li
 
Android kotlin coroutines
Android kotlin coroutinesAndroid kotlin coroutines
Android kotlin coroutinesBipin Vayalu
 
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 modelingMario Fusco
 
Towards Functional Programming through Hexagonal Architecture
Towards Functional Programming through Hexagonal ArchitectureTowards Functional Programming through Hexagonal Architecture
Towards Functional Programming through Hexagonal ArchitectureCodelyTV
 
[수정본] 우아한 객체지향
[수정본] 우아한 객체지향[수정본] 우아한 객체지향
[수정본] 우아한 객체지향Young-Ho Cho
 
Idiomatic Kotlin
Idiomatic KotlinIdiomatic Kotlin
Idiomatic Kotlinintelliyole
 
Advanced heap exploitaion
Advanced heap exploitaionAdvanced heap exploitaion
Advanced heap exploitaionAngel Boy
 
애플리케이션 아키텍처와 객체지향
애플리케이션 아키텍처와 객체지향 애플리케이션 아키텍처와 객체지향
애플리케이션 아키텍처와 객체지향 Young-Ho Cho
 
DevNetCreate Workshop - build a react app - React crash course
DevNetCreate Workshop - build a react app - React crash courseDevNetCreate Workshop - build a react app - React crash course
DevNetCreate Workshop - build a react app - React crash courseCisco DevNet
 
Social Engineering the Windows Kernel by James Forshaw
Social Engineering the Windows Kernel by James ForshawSocial Engineering the Windows Kernel by James Forshaw
Social Engineering the Windows Kernel by James ForshawShakacon
 
Paving the road with Jakarta EE and Apache TomEE - JCON 2021
Paving the road with Jakarta EE  and Apache TomEE - JCON 2021Paving the road with Jakarta EE  and Apache TomEE - JCON 2021
Paving the road with Jakarta EE and Apache TomEE - JCON 2021César Hernández
 
우아한 객체지향
우아한 객체지향우아한 객체지향
우아한 객체지향Young-Ho Cho
 
A Brief Introduction to React.js
A Brief Introduction to React.jsA Brief Introduction to React.js
A Brief Introduction to React.jsDoug Neiner
 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with GroovyArturo Herrero
 

La actualidad más candente (20)

Zagor Ludens 149 - Tragičan bijeg
Zagor Ludens  149 - Tragičan bijegZagor Ludens  149 - Tragičan bijeg
Zagor Ludens 149 - Tragičan bijeg
 
Deep dive into Coroutines on JVM @ KotlinConf 2017
Deep dive into Coroutines on JVM @ KotlinConf 2017Deep dive into Coroutines on JVM @ KotlinConf 2017
Deep dive into Coroutines on JVM @ KotlinConf 2017
 
KSUG 스프링캠프 2019 발표자료 - "무엇을 테스트할 것인가, 어떻게 테스트할 것인가"
KSUG 스프링캠프 2019 발표자료 - "무엇을 테스트할 것인가, 어떻게 테스트할 것인가"KSUG 스프링캠프 2019 발표자료 - "무엇을 테스트할 것인가, 어떻게 테스트할 것인가"
KSUG 스프링캠프 2019 발표자료 - "무엇을 테스트할 것인가, 어떻게 테스트할 것인가"
 
Unit Test and TDD
Unit Test and TDDUnit Test and TDD
Unit Test and TDD
 
Elastic Search (엘라스틱서치) 입문
Elastic Search (엘라스틱서치) 입문Elastic Search (엘라스틱서치) 입문
Elastic Search (엘라스틱서치) 입문
 
React Lifecycle and Reconciliation
React Lifecycle and ReconciliationReact Lifecycle and Reconciliation
React Lifecycle and Reconciliation
 
Android kotlin coroutines
Android kotlin coroutinesAndroid kotlin coroutines
Android kotlin coroutines
 
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
 
Towards Functional Programming through Hexagonal Architecture
Towards Functional Programming through Hexagonal ArchitectureTowards Functional Programming through Hexagonal Architecture
Towards Functional Programming through Hexagonal Architecture
 
[수정본] 우아한 객체지향
[수정본] 우아한 객체지향[수정본] 우아한 객체지향
[수정본] 우아한 객체지향
 
Idiomatic Kotlin
Idiomatic KotlinIdiomatic Kotlin
Idiomatic Kotlin
 
Advanced heap exploitaion
Advanced heap exploitaionAdvanced heap exploitaion
Advanced heap exploitaion
 
iOS 메모리관리
iOS 메모리관리iOS 메모리관리
iOS 메모리관리
 
애플리케이션 아키텍처와 객체지향
애플리케이션 아키텍처와 객체지향 애플리케이션 아키텍처와 객체지향
애플리케이션 아키텍처와 객체지향
 
DevNetCreate Workshop - build a react app - React crash course
DevNetCreate Workshop - build a react app - React crash courseDevNetCreate Workshop - build a react app - React crash course
DevNetCreate Workshop - build a react app - React crash course
 
Social Engineering the Windows Kernel by James Forshaw
Social Engineering the Windows Kernel by James ForshawSocial Engineering the Windows Kernel by James Forshaw
Social Engineering the Windows Kernel by James Forshaw
 
Paving the road with Jakarta EE and Apache TomEE - JCON 2021
Paving the road with Jakarta EE  and Apache TomEE - JCON 2021Paving the road with Jakarta EE  and Apache TomEE - JCON 2021
Paving the road with Jakarta EE and Apache TomEE - JCON 2021
 
우아한 객체지향
우아한 객체지향우아한 객체지향
우아한 객체지향
 
A Brief Introduction to React.js
A Brief Introduction to React.jsA Brief Introduction to React.js
A Brief Introduction to React.js
 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with Groovy
 

Similar a 스위프트, 코틀린과 모던언어의 특징 (Swift, Kotlin and Modern Languages)

동기화, 스케줄링
동기화, 스케줄링동기화, 스케줄링
동기화, 스케줄링xxbdxx
 
Feel functional
Feel functionalFeel functional
Feel functionalWonJun Lee
 
liftIO 2022 quasiquote
liftIO 2022 quasiquoteliftIO 2022 quasiquote
liftIO 2022 quasiquoteHyunseok Cho
 
자바 테스트 자동화
자바 테스트 자동화자바 테스트 자동화
자바 테스트 자동화Sungchul Park
 
[NDC 2016] 유니티, iOS에서 LINQ 사용하기
[NDC 2016] 유니티, iOS에서 LINQ 사용하기[NDC 2016] 유니티, iOS에서 LINQ 사용하기
[NDC 2016] 유니티, iOS에서 LINQ 사용하기Daehee Kim
 
Why what how kotlin
Why what how kotlinWhy what how kotlin
Why what how kotlinSewonKo
 
Smalltalk at Altlang 2008
Smalltalk at Altlang 2008Smalltalk at Altlang 2008
Smalltalk at Altlang 2008daliot
 
포트폴리오에서 사용한 모던 C++
포트폴리오에서 사용한 모던 C++포트폴리오에서 사용한 모던 C++
포트폴리오에서 사용한 모던 C++KWANGIL KIM
 
일단 시작하는 코틀린
일단 시작하는 코틀린일단 시작하는 코틀린
일단 시작하는 코틀린Park JoongSoo
 
Do swift: Swift 무작정 해보기
Do swift: Swift 무작정 해보기Do swift: Swift 무작정 해보기
Do swift: Swift 무작정 해보기YoonBong Steve Kim
 
C Language For Arduino
C Language For ArduinoC Language For Arduino
C Language For Arduino영욱 김
 
[C++ Korea 2nd Seminar] Ranges for The Cpp Standard Library
[C++ Korea 2nd Seminar] Ranges for The Cpp Standard Library[C++ Korea 2nd Seminar] Ranges for The Cpp Standard Library
[C++ Korea 2nd Seminar] Ranges for The Cpp Standard LibraryDongMin Choi
 
Hello Swift 2/5 - Basic2
Hello Swift 2/5 - Basic2Hello Swift 2/5 - Basic2
Hello Swift 2/5 - Basic2Cody Yun
 
2013 C++ Study For Students #1
2013 C++ Study For Students #12013 C++ Study For Students #1
2013 C++ Study For Students #1Chris Ohk
 
Swift3 typecasting nested_type
Swift3 typecasting nested_typeSwift3 typecasting nested_type
Swift3 typecasting nested_typeEunjoo Im
 
아두이노 2015-2 한동대학교 공학설계입문
아두이노 2015-2 한동대학교 공학설계입문아두이노 2015-2 한동대학교 공학설계입문
아두이노 2015-2 한동대학교 공학설계입문Sangjun Han
 

Similar a 스위프트, 코틀린과 모던언어의 특징 (Swift, Kotlin and Modern Languages) (20)

동기화, 스케줄링
동기화, 스케줄링동기화, 스케줄링
동기화, 스케줄링
 
Feel functional
Feel functionalFeel functional
Feel functional
 
liftIO 2022 quasiquote
liftIO 2022 quasiquoteliftIO 2022 quasiquote
liftIO 2022 quasiquote
 
Swift의 함수와 메소드
Swift의 함수와 메소드Swift의 함수와 메소드
Swift의 함수와 메소드
 
Kotlin with fp
Kotlin with fpKotlin with fp
Kotlin with fp
 
자바 테스트 자동화
자바 테스트 자동화자바 테스트 자동화
자바 테스트 자동화
 
[NDC 2016] 유니티, iOS에서 LINQ 사용하기
[NDC 2016] 유니티, iOS에서 LINQ 사용하기[NDC 2016] 유니티, iOS에서 LINQ 사용하기
[NDC 2016] 유니티, iOS에서 LINQ 사용하기
 
Why what how kotlin
Why what how kotlinWhy what how kotlin
Why what how kotlin
 
Smalltalk at Altlang 2008
Smalltalk at Altlang 2008Smalltalk at Altlang 2008
Smalltalk at Altlang 2008
 
포트폴리오에서 사용한 모던 C++
포트폴리오에서 사용한 모던 C++포트폴리오에서 사용한 모던 C++
포트폴리오에서 사용한 모던 C++
 
일단 시작하는 코틀린
일단 시작하는 코틀린일단 시작하는 코틀린
일단 시작하는 코틀린
 
Do swift: Swift 무작정 해보기
Do swift: Swift 무작정 해보기Do swift: Swift 무작정 해보기
Do swift: Swift 무작정 해보기
 
C Language For Arduino
C Language For ArduinoC Language For Arduino
C Language For Arduino
 
Ndc12 2
Ndc12 2Ndc12 2
Ndc12 2
 
[C++ Korea 2nd Seminar] Ranges for The Cpp Standard Library
[C++ Korea 2nd Seminar] Ranges for The Cpp Standard Library[C++ Korea 2nd Seminar] Ranges for The Cpp Standard Library
[C++ Korea 2nd Seminar] Ranges for The Cpp Standard Library
 
Hello Swift 2/5 - Basic2
Hello Swift 2/5 - Basic2Hello Swift 2/5 - Basic2
Hello Swift 2/5 - Basic2
 
Swift2
Swift2Swift2
Swift2
 
2013 C++ Study For Students #1
2013 C++ Study For Students #12013 C++ Study For Students #1
2013 C++ Study For Students #1
 
Swift3 typecasting nested_type
Swift3 typecasting nested_typeSwift3 typecasting nested_type
Swift3 typecasting nested_type
 
아두이노 2015-2 한동대학교 공학설계입문
아두이노 2015-2 한동대학교 공학설계입문아두이노 2015-2 한동대학교 공학설계입문
아두이노 2015-2 한동대학교 공학설계입문
 

스위프트, 코틀린과 모던언어의 특징 (Swift, Kotlin and Modern Languages)

  • 1. let swift(17) Swift, Kotlin과 모던 언어의 특징 세미콜론 없는 세상 github.com/inkfyox유용하
  • 3. 목적 Swift vs. Kotlin Swift & Kotlin 문법의 유사성 소개 모던 언어에서의 이슈들을 두 언어가 어떻게 해결하고 있는지 비교 차이점이 생길 수 밖에 없는 기반 시스템 비교
  • 4. Swift & Kotlin Swift •Apple에서 개발 •Objective-C의 다음 세대 언어 •Open source (https://github.com/apple/swift) •주로 사용되는 곳: iOS, macOS, watchOS, tvOS •기타: Linux Kotlin •JetBrains에서 개발 •Java의 다음 세대 언어 (중의 하나) •Open source (https://github.com/JetBrains/kotlin) •주로 사용되는 곳: Android, server, 자바가 쓰이는 곳 어디든 •기타: JVM이 아닌 JavaScript 타겟도 지원함
  • 5. History 1.0.0M1~M14, 1.0 Beta 1~4 안드로이드 공식 지원 프로젝트 공개 오픈소스화 1.1.0 1.0 1.1 1.2 2.0 3.0 3.1 프로젝트 공개 오픈소스화
  • 7. 변수 선언 let number: Int = 1 var any: Any = number val number: Int = 1 var any: Any = number 타입 체크 if any is Int {     // ... } if (any is Int) { // ... } Downcast let num2: Int = any as! Int val num2: Int = any as Int 타입 변환 let long: Int64 = Int64(number) val long: Long = number.toLong() 타입 추론 let number = 1 val number = 1 정적 타입
  • 8. 변수 선언 let number: Int = 1 var any: Any = number val number: Int = 1 var any: Any = number 타입 체크 if any is Int {     // ... } if (any is Int) { // ... } Downcast let num2: Int = any as! Int val num2: Int = any as Int 타입 변환 let long: Int64 = Int64(number) val long: Long = number.toLong() 타입 추론 let number = 1 val number = 1 정적 타입
  • 9. 변수 선언 let number: Int = 1 var any: Any = number val number: Int = 1 var any: Any = number 타입 체크 if any is Int {     // ... } if (any is Int) { // ... } Downcast let num2: Int = any as! Int val num2: Int = any as Int 타입 변환 let long: Int64 = Int64(number) val long: Long = number.toLong() 타입 추론 let number = 1 val number = 1 정적 타입
  • 10. 변수 선언 let number: Int = 1 var any: Any = number val number: Int = 1 var any: Any = number 타입 체크 if any is Int {     // ... } if (any is Int) { // ... } Downcast let num2: Int = any as! Int val num2: Int = any as Int 타입 변환 let long: Int64 = Int64(number) val long: Long = number.toLong() 타입 추론 let number = 1 val number = 1 정적 타입
  • 11. var conference = "LetSwift" conference = "VarSwift" var conference = "ValKotlin" conference = "VarKotlin" let conference: String if isSwift { conference = "LetSwift" } else { conference = "ValKotlin" } val conference: String if (isSwift) { conference = "LetSwift" } else { conference = "ValKotlin" } let conference = "LetSwift" conference = "VarSwift" val conference = "ValKotlin" conference = “VarKotlin" 읽기 전용 변수 읽기 전용 변수 -> 재할당 불가
  • 12. var conference = "LetSwift" conference = "VarSwift" var conference = "ValKotlin" conference = "VarKotlin" let conference: String if isSwift { conference = "LetSwift" } else { conference = "ValKotlin" } val conference: String if (isSwift) { conference = "LetSwift" } else { conference = "ValKotlin" } let conference = "LetSwift" conference = "VarSwift" val conference = "ValKotlin" conference = “VarKotlin" 읽기 전용 변수 읽기 전용 변수 -> 재할당 불가
  • 13. var conference = "LetSwift" conference = "VarSwift" var conference = "ValKotlin" conference = "VarKotlin" let conference: String if isSwift { conference = "LetSwift" } else { conference = "ValKotlin" } val conference: String if (isSwift) { conference = "LetSwift" } else { conference = "ValKotlin" } let conference = "LetSwift" conference = "VarSwift" val conference = "ValKotlin" conference = “VarKotlin" 읽기 전용 변수 컴파일 시점에 값이 정해지는 것은 아님 처음 사용되기 전에 값이 한번 할당된다는 것을 컴파일 시점에 체크
  • 14. 타입 추론 SomeClassWithVeryLongName* bar = [[SomeClassWithVeryLongName alloc] init]; SomeClassWithVeryLongName* other = bar SomeClassWithVeryLongName bar = new SomeClassWithVeryLongName(); SomeClassWithVeryLongName other = bar; ObjC Java
  • 15. 타입 추론 SomeClassWithVeryLongName* bar = [[SomeClassWithVeryLongName alloc] init]; SomeClassWithVeryLongName* other = bar SomeClassWithVeryLongName bar = new SomeClassWithVeryLongName(); SomeClassWithVeryLongName other = bar; ObjC Java 중복된 정보
  • 16. 타입 추론 SomeClassWithVeryLongName* bar = [[SomeClassWithVeryLongName alloc] init]; SomeClassWithVeryLongName* other = bar SomeClassWithVeryLongName bar = new SomeClassWithVeryLongName(); SomeClassWithVeryLongName other = bar; ObjC Java let bar = SomeClassWithVeryLongName() var other = bar val bar = SomeClassWithVeryLongName() var other = bar
  • 17. 타입 추론 SomeClassWithVeryLongName* bar = [[SomeClassWithVeryLongName alloc] init]; SomeClassWithVeryLongName* other = bar SomeClassWithVeryLongName bar = new SomeClassWithVeryLongName(); SomeClassWithVeryLongName other = bar; ObjC Java let bar = SomeClassWithVeryLongName() var other = bar val bar = SomeClassWithVeryLongName() var other = bar other = SomeOtherClass() other = SomeOtherClass() 그래도 정적 타입이니까
  • 18. Optional & Nullable nil/null 값을 가진 변수를 주소값으로 사용했을때 •런타임 에러 발생 •프로그램의 안정성을 해침 (가장 빈번한 에러) •Objc의 경우 sendmsg방식으로 크래시는 안나도 의도치 않은 동작 가능 •100% 안전하려면 항상 변수가 nil/null 인지 확인해야함 •nil/null인 경우가 없는 경우도 체크하게 됨 -> 비효율 •강제가 아니기 때문에 빠뜨릴 수 있음 -> 구멍
  • 19. Optional & Nullable 타입에 nil/null을 가질 수 있는지의 의미도 부여한다면 •nil/null 가질 수 있는 Optional/Nullable 타입: 무조건 체크해야함 •런타임 에러 -> 컴파일타임 에러: 안정성 향상 •not-null 타입: 체크 안하고 안정적으로 사용 •의외로 not-null인 변수를 다루는 경우가 더 많음: 코드가 간결해짐
  • 20. Optional & Nullable 타입 let str = "1234" let num: Int? = Int(str) val str = "1234" val num: Int? = str.toIntOrNull() 기본값 let num2: Int = num ?? -1 val num2: Int = num ?: -1 체이닝 server?.connect().name.capitalized server?.connect()?.name?.capitalize() Downcast let any: Any let number = any as? Int val any: Any val number = any as? Int 강제 Downcast let number = any as! Int val number = any as Int 강제 Unwrap server!.connect().name.capitalized server!!.connect().name.capitalize()
  • 21. Optional & Nullable 타입 let str = "1234" let num: Int? = Int(str) val str = "1234" val num: Int? = str.toIntOrNull() 기본값 let num2: Int = num ?? -1 val num2: Int = num ?: -1 체이닝 server?.connect().name.capitalized server?.connect()?.name?.capitalize() Downcast let any: Any let number = any as? Int val any: Any val number = any as? Int 강제 Downcast let number = any as! Int val number = any as Int 강제 Unwrap server!.connect().name.capitalized server!!.connect().name.capitalize()
  • 22. Optional & Nullable 타입 let str = "1234" let num: Int? = Int(str) val str = "1234" val num: Int? = str.toIntOrNull() 기본값 let num2: Int = num ?? -1 val num2: Int = num ?: -1 체이닝 server?.connect().name.capitalized server?.connect()?.name?.capitalize() Downcast let any: Any let number = any as? Int val any: Any val number = any as? Int 강제 Downcast let number = any as! Int val number = any as Int 강제 Unwrap server!.connect().name.capitalized server!!.connect().name.capitalize()
  • 23. Optional & Nullable 타입 let str = "1234" let num: Int? = Int(str) val str = "1234" val num: Int? = str.toIntOrNull() 기본값 let num2: Int = num ?? -1 val num2: Int = num ?: -1 체이닝 server?.connect().name.capitalized server?.connect()?.name?.capitalize() Downcast let any: Any let number = any as? Int val any: Any val number = any as? Int 강제 Downcast let number = any as! Int val number = any as Int 강제 Unwrap server!.connect().name.capitalized server!!.connect().name.capitalize() ((server?.connect())?.name)?.capitalized
  • 24. Optional & Nullable 타입 let str = "1234" let num: Int? = Int(str) val str = "1234" val num: Int? = str.toIntOrNull() 기본값 let num2: Int = num ?? -1 val num2: Int = num ?: -1 체이닝 server?.connect().name.capitalized server?.connect()?.name?.capitalize() Downcast let any: Any let number = any as? Int val any: Any val number = any as? Int 강제 Downcast let number = any as! Int val number = any as Int 강제 Unwrap server!.connect().name.capitalized server!!.connect().name.capitalize()
  • 25. Optional & Nullable 타입 let str = "1234" let num: Int? = Int(str) val str = "1234" val num: Int? = str.toIntOrNull() 기본값 let num2: Int = num ?? -1 val num2: Int = num ?: -1 체이닝 server?.connect().name.capitalized server?.connect()?.name?.capitalize() Downcast let any: Any let number = any as? Int val any: Any val number = any as? Int 강제 Downcast let number = any as! Int val number = any as Int 강제 Unwrap server!.connect().name.capitalized server!!.connect().name.capitalize() 웬만하면 쓰지말라고 느낌표 2개
  • 26. Optional & Nullable 타입 let str = "1234" let num: Int? = Int(str) val str = "1234" val num: Int? = str.toIntOrNull() 기본값 let num2: Int = num ?? -1 val num2: Int = num ?: -1 체이닝 server?.connect().name.capitalized server?.connect()?.name?.capitalize() Downcast let any: Any let number = any as? Int val any: Any val number = any as? Int 강제 Downcast let number = any as! Int val number = any as Int 강제 Unwrap server!.connect().name.capitalized server!!.connect().name.capitalize()
  • 27. Optional & Nullable func foo(value: String?) { if let value = value { print(value.capitalized) } } 
 fun foo(value: String?) {
 if (value != null) {
 println(value.capitalize())
 }
 }
 func foo(value: String?) { guard let value = value else { return } print(value.capitalized) } 
 fun foo(value: String?) { if (value == null) return println(value.capitalize()) } func foo(value: Any) { if let value = value as? String { print(value.capitalized) } } 
 fun foo(value: Any) { if (value is String) { println(value.capitalize()) } } Smart CastOptional Unwrap
  • 28. Optional & Nullable func foo(value: String?) { if let value = value { print(value.capitalized) } } 
 fun foo(value: String?) {
 if (value != null) {
 println(value.capitalize())
 }
 }
 func foo(value: String?) { guard let value = value else { return } print(value.capitalized) } 
 fun foo(value: String?) { if (value == null) return println(value.capitalize()) } func foo(value: Any) { if let value = value as? String { print(value.capitalized) } } 
 fun foo(value: Any) { if (value is String) { println(value.capitalize()) } } Smart CastOptional Unwrap
  • 29. Optional & Nullable func foo(value: String?) { if let value = value { print(value.capitalized) } } 
 fun foo(value: String?) {
 if (value != null) {
 println(value.capitalize())
 }
 }
 func foo(value: String?) { guard let value = value else { return } print(value.capitalized) } 
 fun foo(value: String?) { if (value == null) return println(value.capitalize()) } func foo(value: Any) { if let value = value as? String { print(value.capitalized) } } 
 fun foo(value: Any) { if (value is String) { println(value.capitalize()) } } Smart CastOptional Unwrap
  • 31. view2 class View location (0.0, 0.0) class Point x: 0.0 y: 0.0 Mutability: 공유 상태의 문제 view1 class View location (0.0, 0.0)
  • 32. view2 class View location (10.0, 0.0) view2.location.x += 10.0 class Point x: 10.0 y: 0.0 view1 class View location (10.0, 0.0) Mutability: 공유 상태의 문제
  • 33. view2 class View location (10.0, 0.0) class Point x: 10.0 y: 0.0 view1 class View location (10.0, 0.0) ??? view2.location.x += 10.0 Mutability: 공유 상태의 문제
  • 34. view2 class View location (0.0, 0.0) class Point readonly x: 0.0 readonly y: 0.0 공유 상태 문제 해결 view1 class View location (0.0, 0.0) ObjC
  • 35. view2 class View location (0.0, 0.0) view1 class View location (0.0, 0.0) view2.location.x += 10.0 재할당 불가능한 변수이기 때문 ObjC class Point readonly x: 0.0 readonly y: 0.0 공유 상태 문제 해결
  • 36. view2 class View location (10.0, 0.0) view1 class View location (0.0, 0.0) view2.location = Point(view.location.x + 10.0, view.location) 기존 객체의 값을 이용해 새로운 객체를 할당 class Point readonly x: 0.0 readonly y: 0.0 class Point readonly x: 10.0 readonly y: 0.0 ObjC *) 실제 View, UIView의 location의 예시는 아님 공유 상태 문제 해결
  • 37. Immutable type 공유되는 변수의 내부 값이 변경 가능할때 생기는 문제 원천 차단 복잡도 감소 •변수의 상태 변화에 대한 트래킹 이슈 없음 성능 향상 •multi-thread에서 lock없이 공유 가능
  • 38. view1 class View location: (0.0, 0.0) Value 타입을 이용하면 애초에 공유될 수가 없음 struct Point x: 0.0 y: 0.0 view2 class View location: (0.0, 0.0) struct Point x: 0.0 y: 0.0 Value 타입을 이용하면 초간단 공유 상태 문제 해결
  • 39. view1 class View location: (0.0, 0.0) struct Point x: 0.0 y: 0.0 view2 class View location: (10.0, 0.0) struct Point x: 10.0 y: 0.0 Value 타입을 이용하면 초간단 view2.location.x += 10.0 공유 상태 문제 해결
  • 40. 숫자, 문자, Boolean Value (Int, Int64, Double, Bool, …) Value (*) / Reference (Int, Long, Double, Boolean, …) String Value Reference Collections Value (Array, Set, Dictionary) Reference (List, Set, Map) Enum Value Reference Struct Value 없음 Tuple Value 없음 Class Reference Reference Function, Closure / Lambda Reference Reference Reference / Value 타입 (*) Kotlin에는 Value 타입의 개념이 없고 JVM에서 원시타입이 Value 타입
  • 41. String Literals 생성 let str = "lettSwiftn" val str = "valtKotlinn" 여러줄 생성 val json = """ { "name": “Swift", "version": (version) } """ val json = """ { "name": "Kotlin", "version": $version } """ 연결 let lang = "Swift" let title = "Hello, " + lang val lang = "Kotlin" val title = "Hello, " + lang 템플릿 let year = 2017 let current = "LetSwift(year)" let previous = "LetSwift(year - 1)” val year = 2017 val current = "ValKotlin$year" val previous = "ValKotlin${year - 1}" (Swift4.0)
  • 42. str1 struct String _storage "Let" String: Mutability … refCount: 1 "Let" let str1 = "Let" public struct String { … }
  • 43. str1 struct String _storage "Let" String: Mutability … refCount: 1 "Let" let str1 = "Let" String은 struct로 value 타입이지만, 내부에 실제 문자열 데이터를 저장할 저장소는 reference 타입일 수 밖에 없다. public struct String { … }
  • 44. str1 struct String _storage "Let" let str1 = "Let" var str2 = str1 … refCount: 2 "Let" str2 struct String _storage "Let" public struct String { … } String: Mutability 재할당할 때마다 저장소를 복사하는 것은 비효율, 일단은 공유한다.
  • 45. str1 struct String _storage "Let" … refCount: 1 "Let" str2 struct String _storage "LetSwift" let str1 = "Let" var str2 = str1 str2.append("Swift") … refCount: 1 “LetSwift" public struct String { … } String: Mutability
  • 46. str1 struct String _storage "Let" … refCount: 1 "Let" str2 struct String _storage "LetSwift" let str1 = "Let" var str2 = str1 str2.append("Swift") … refCount: 1 “LetSwift" Copy-On-Write: (처음) 변경될 때 복사한다. public struct String { … } String: Mutability
  • 47. str1 struct String _storage "Let" … refCount: 1 "Let" str2 struct String _storage "LetSwift" let str1 = "Let" var str2 = str1 str2.append("Swift") … refCount: 1 “LetSwift" public mutating func append(_ other: String) public struct String { … } String: Mutability Copy-On-Write: (처음) 변경될 때 복사한다.
  • 48. let str1 = "Let" let str2 = str1 str2.append("Swift") str1 struct String _storage "Let" … refCount: 1 "Let" str2 struct String _storage "LetSwift" … refCount: 1 “LetSwift" public mutating func append(_ other: String) value 타입은 let / var에 의해 immutable / mutable이 결정 public struct String { … } String: Mutability
  • 49. str1 struct String _storage "Let" … refCount: 1 "Let" str2 struct String _storage “LetSwift17" let str1 = "Let" var str2 = str1 str2.append("Swift") str2.append("17") … refCount: 1 "LetSwift17" public struct String { … } refCount가 1이기 때문 String: Mutability
  • 50. 1. mutable 동작의 API가 없음 2. open class가 아니어서 상속을 할 수 없음 -> String 타입으로 다룰 수 있는 Mutable String을 만드는 것이 불가능 public class String … { … } String: Mutability
  • 51. 1. mutable 동작의 API가 없음 2. open class가 아니어서 상속을 할 수 없음 -> String 타입으로 다룰 수 있는 Mutable String을 만드는 것이 불가능 String은 Map의 key등 상수형으로 많이 쓰임 이런 String의 상태가 변경되는 것은 큰 혼란을 일으킬 수 있음 public class String … { … } String: Mutability
  • 52. val str1 = "Let" var str2 = str1 + "Swift" str2 = str2.replace("Swift", “Kotlin") 1. mutable 동작의 API가 없음 2. open class가 아니어서 상속을 할 수 없음 -> String 타입으로 다룰 수 있는 Mutable String을 만드는 것이 불가능 변경하려면: 변경된 문자열을 가진 새로운 객체를 생성해야 함 public class String … { … } String: Mutability
  • 53. Collection 중복 가능 순서 있음 struct Array<E> interface List<out E> interface MutableList<E> : List<E> (class: ArrayList, …) (*) 중복 불가 struct Set<E> interface Set<out E> interface MutableSet<E> : Set<E> (class: LinkedHashSet, SortedSet, …) Key의 중복 불가 Key, Value의 쌍 struct Dictionary<K, V> interface Map<out K, out V> interface MutableMap<K, V> : Map<K, V> (class: LinkedHashMap, HashMap, …) (*) Array도 존재하지만 JVM array에 대응하는 자료 구조로 Collection과는 성격이 약간 다름
  • 54. Collection 중복 가능 순서 있음 struct Array<E> interface List<out E> interface MutableList<E> : List<E> (class: ArrayList, …) (*) 중복 불가 struct Set<E> interface Set<out E> interface MutableSet<E> : Set<E> (class: LinkedHashSet, SortedSet, …) Key의 중복 불가 Key, Value의 쌍 struct Dictionary<K, V> interface Map<out K, out V> interface MutableMap<K, V> : Map<K, V> (class: LinkedHashMap, HashMap, …) Value 타입
  • 55. Collection 중복 가능 순서 있음 struct Array<E> interface List<out E> interface MutableList<E> : List<E> (class: ArrayList, …) (*) 중복 불가 struct Set<E> interface Set<out E> interface MutableSet<E> : Set<E> (class: LinkedHashSet, SortedSet, …) Key의 중복 불가 Key, Value의 쌍 struct Dictionary<K, V> interface Map<out K, out V> interface MutableMap<K, V> : Map<K, V> (class: LinkedHashMap, HashMap, …) Immutable/Mutable 인터페이스 제공 성격에 따라 다양한 실제 구현 클래스 사용가능 (Java)
  • 56. Immutable Collections Array / List let array: [String] = ["Swift", "Kotlin"]
 
 
 print(array[0])
 
 val list: List<String> =
 listOf("Swift", "Kotlin")
 
 println(list[1])
 
 
 Set let set: Set<String> = ["Swift", "Kotlin"]
 
 
 if set.contains("Objc") { } 
 val set: Set<String> =
 setOf("Swift", "Kotlin")
 
 if ("Java" in set) { }
 
 Dictionary / Map let dic: [String : Double] =
 [“Swift" : 3.1, "Kotlin" : 1.1]
 print(dic["Swift"])
 
 val map: Map<String, Double> = 
 mapOf("Swift" to 3.1, “Kotlin" to 1.1)
 println(map["Kotlin"])

  • 57. Immutable Collections Array / List let array: [String] = ["Swift", "Kotlin"]
 
 
 print(array[0])
 
 val list: List<String> =
 listOf("Swift", "Kotlin")
 
 println(list[1])
 
 
 Set let set: Set<String> = ["Swift", "Kotlin"]
 
 
 if set.contains("Objc") { } 
 val set: Set<String> =
 setOf("Swift", "Kotlin")
 
 if ("Java" in set) { }
 
 Dictionary / Map let dic: [String : Double] =
 [“Swift" : 3.1, "Kotlin" : 1.1]
 print(dic["Swift"])
 
 val map: Map<String, Double> = 
 mapOf("Swift" to 3.1, “Kotlin" to 1.1)
 println(map["Kotlin"])

  • 58. Immutable Collections Array / List let array: [String] = ["Swift", "Kotlin"]
 
 
 print(array[0])
 
 val list: List<String> =
 listOf("Swift", "Kotlin")
 
 println(list[1])
 
 
 Set let set: Set<String> = ["Swift", "Kotlin"]
 
 
 if set.contains("Objc") { } 
 val set: Set<String> =
 setOf("Swift", "Kotlin")
 
 if ("Java" in set) { }
 
 Dictionary / Map let dic: [String : Double] =
 [“Swift" : 3.1, "Kotlin" : 1.1]
 print(dic["Swift"])
 
 val map: Map<String, Double> = 
 mapOf("Swift" to 3.1, “Kotlin" to 1.1)
 println(map["Kotlin"])

  • 59. Immutable Collections Array / List let array: [String] = ["Swift", "Kotlin"]
 
 
 print(array[0])
 
 val list: List<String> =
 listOf("Swift", "Kotlin")
 
 println(list[1])
 
 
 Set let set: Set<String> = ["Swift", "Kotlin"]
 
 
 if set.contains("Objc") { } 
 val set: Set<String> =
 setOf("Swift", "Kotlin")
 
 if ("Java" in set) { }
 
 Dictionary / Map let dic: [String : Double] =
 [“Swift" : 3.1, "Kotlin" : 1.1]
 print(dic["Swift"])
 
 val map: Map<String, Double> = 
 mapOf("Swift" to 3.1, “Kotlin" to 1.1)
 println(map["Kotlin"])

  • 60. Immutable Collections Array / List let array: [String] = ["Swift", "Kotlin"]
 
 
 print(array[0])
 
 val list: List<String> =
 listOf("Swift", "Kotlin")
 
 println(list[1])
 
 
 Set let set: Set<String> = ["Swift", "Kotlin"]
 
 
 if set.contains("Objc") { } 
 val set: Set<String> =
 setOf("Swift", "Kotlin")
 
 if ("Java" in set) { }
 
 Dictionary / Map let dic: [String : Double] =
 [“Swift" : 3.1, "Kotlin" : 1.1]
 print(dic["Swift"])
 
 val map: Map<String, Double> = 
 mapOf("Swift" to 3.1, “Kotlin" to 1.1)
 println(map["Kotlin"])

  • 61. Mutable Collections Array / List var array: [String] = ["Swift", "Kotlin"]
 
 
 print(array[0])
 
 array[0] = "Objc" val list: MutableList<String> =
 mutableListOf("Swift", "Kotlin")
 
 println(list[1])
 
 list[1] = "Java"
 Set var set: Set<String> = ["Swift", "Kotlin"]
 
 
 if set.contains("Objc") { } 
 set.insert("Objc") val set: MutableSet<String> =
 mutableSetOf("Swift", "Kotlin")
 
 if ("Java" in set) { }
 
 set.add("Java") Dictionary / Map var dic: [String : Double] =
 [“Swift" : 3.1, "Kotlin" : 1.1]
 print(dic["Swift"])
 
 dic["Swift"] = 4.0 val map: MutableMap<String, Double> = 
 mutableMapOf("Swift" to 3.1, “Kotlin" to 1.1)
 println(map["Kotlin"])
 
 map["Kotlin"] = 1.2
  • 62. Mutable Collections Array / List var array: [String] = ["Swift", "Kotlin"]
 
 
 print(array[0])
 
 array[0] = "Objc" val list: MutableList<String> =
 mutableListOf("Swift", "Kotlin")
 
 println(list[1])
 
 list[1] = "Java"
 Set var set: Set<String> = ["Swift", "Kotlin"]
 
 
 if set.contains("Objc") { } 
 set.insert("Objc") val set: MutableSet<String> =
 mutableSetOf("Swift", "Kotlin")
 
 if ("Java" in set) { }
 
 set.add("Java") Dictionary / Map var dic: [String : Double] =
 [“Swift" : 3.1, "Kotlin" : 1.1]
 print(dic["Swift"])
 
 dic["Swift"] = 4.0 val map: MutableMap<String, Double> = 
 mutableMapOf("Swift" to 3.1, “Kotlin" to 1.1)
 println(map["Kotlin"])
 
 map["Kotlin"] = 1.2
  • 63. Mutable Collections Array / List var array: [String] = ["Swift", "Kotlin"]
 
 
 print(array[0])
 
 array[0] = "Objc" val list: MutableList<String> =
 mutableListOf("Swift", "Kotlin")
 
 println(list[1])
 
 list[1] = "Java"
 Set var set: Set<String> = ["Swift", "Kotlin"]
 
 
 if set.contains("Objc") { } 
 set.insert("Objc") val set: MutableSet<String> =
 mutableSetOf("Swift", "Kotlin")
 
 if ("Java" in set) { }
 
 set.add("Java") Dictionary / Map var dic: [String : Double] =
 [“Swift" : 3.1, "Kotlin" : 1.1]
 print(dic["Swift"])
 
 dic["Swift"] = 4.0 val map: MutableMap<String, Double> = 
 mutableMapOf("Swift" to 3.1, “Kotlin" to 1.1)
 println(map["Kotlin"])
 
 map["Kotlin"] = 1.2
  • 64. Mutable Collections Array / List var array: [String] = ["Swift", "Kotlin"]
 
 
 print(array[0])
 
 array[0] = "Objc" val list: MutableList<String> =
 mutableListOf("Swift", "Kotlin")
 
 println(list[1])
 
 list[1] = "Java"
 Set var set: Set<String> = ["Swift", "Kotlin"]
 
 
 if set.contains("Objc") { } 
 set.insert("Objc") val set: MutableSet<String> =
 mutableSetOf("Swift", "Kotlin")
 
 if ("Java" in set) { }
 
 set.add("Java") Dictionary / Map var dic: [String : Double] =
 [“Swift" : 3.1, "Kotlin" : 1.1]
 print(dic["Swift"])
 
 dic["Swift"] = 4.0 val map: MutableMap<String, Double> = 
 mutableMapOf("Swift" to 3.1, “Kotlin" to 1.1)
 println(map["Kotlin"])
 
 map["Kotlin"] = 1.2
  • 65. Mutable Collections Array / List var array: [String] = ["Swift", "Kotlin"]
 
 
 print(array[0])
 
 array[0] = "Objc" val list: MutableList<String> =
 mutableListOf("Swift", "Kotlin")
 
 println(list[1])
 
 list[1] = "Java"
 Set var set: Set<String> = ["Swift", "Kotlin"]
 
 
 if set.contains("Objc") { } 
 set.insert("Objc") val set: MutableSet<String> =
 mutableSetOf("Swift", "Kotlin")
 
 if ("Java" in set) { }
 
 set.add("Java") Dictionary / Map var dic: [String : Double] =
 [“Swift" : 3.1, "Kotlin" : 1.1]
 print(dic["Swift"])
 
 dic["Swift"] = 4.0 val map: MutableMap<String, Double> = 
 mutableMapOf("Swift" to 3.1, “Kotlin" to 1.1)
 println(map["Kotlin"])
 
 map["Kotlin"] = 1.2
  • 66. Mutable Collections Array / List var array: [String] = ["Swift", "Kotlin"]
 
 
 print(array[0])
 
 array[0] = "Objc" val list: MutableList<String> =
 mutableListOf("Swift", "Kotlin")
 
 println(list[1])
 
 list[1] = "Java"
 Set var set: Set<String> = ["Swift", "Kotlin"]
 
 
 if set.contains("Objc") { } 
 set.insert("Objc") val set: MutableSet<String> =
 mutableSetOf("Swift", "Kotlin")
 
 if ("Java" in set) { }
 
 set.add("Java") Dictionary / Map var dic: [String : Double] =
 [“Swift" : 3.1, "Kotlin" : 1.1]
 print(dic["Swift"])
 
 dic["Swift"] = 4.0 val map: MutableMap<String, Double> = 
 mutableMapOf("Swift" to 3.1, “Kotlin" to 1.1)
 println(map["Kotlin"])
 
 map["Kotlin"] = 1.2 Value 타입이므로 let -> var 로 Copy-On-Write로 동작
  • 67. Mutable Collections Array / List var array: [String] = ["Swift", "Kotlin"]
 
 
 print(array[0])
 
 array[0] = "Objc" val list: MutableList<String> =
 mutableListOf("Swift", "Kotlin")
 
 println(list[1])
 
 list[1] = "Java"
 Set var set: Set<String> = ["Swift", "Kotlin"]
 
 
 if set.contains("Objc") { } 
 set.insert("Objc") val set: MutableSet<String> =
 mutableSetOf("Swift", "Kotlin")
 
 if ("Java" in set) { }
 
 set.add("Java") Dictionary / Map var dic: [String : Double] =
 [“Swift" : 3.1, "Kotlin" : 1.1]
 print(dic["Swift"])
 
 dic["Swift"] = 4.0 val map: MutableMap<String, Double> = 
 mutableMapOf("Swift" to 3.1, “Kotlin" to 1.1)
 println(map["Kotlin"])
 
 map["Kotlin"] = 1.2 Mutable 전용 인터페이스 이용 var는 단순히 변수를 재할당 가능하다는 의미
  • 68. Swift의 Mutability Value 타입으로 구현 변수의 타입만으로 Immutable / mutable 동작 구분 (let, var) 데이터 저장공간은 Reference type의 멤버 변수로 가짐 Mutable 타입의 경우 내용이 처음 변경될 때 새로운 객체 생성 (이때 저장공간 복사 -> Copy-On-Write)
  • 69. Swift의 Mutability Value 타입으로 구현 변수의 타입만으로 Immutable / mutable 동작 구분 (let, var) 데이터 저장공간은 Reference type의 멤버 변수로 가짐 Mutable 타입의 경우 내용이 처음 변경될 때 새로운 객체 생성 (이때 저장공간 복사 -> Copy-On-Write) 
 var original: [Int] = [1, 2] var mutable = array mutable.append(3) original struct Array<Int> _storage 1, 2 … refCount: 2 [1, 2] mutable struct Array<Int> _storage 1, 2
  • 70. Swift의 Mutability Value 타입으로 구현 변수의 타입만으로 Immutable / mutable 동작 구분 (let, var) 데이터 저장공간은 Reference type의 멤버 변수로 가짐 Mutable 타입의 경우 내용이 처음 변경될 때 새로운 객체 생성 (이때 저장공간 복사 -> Copy-On-Write) 
 var original: [Int] = [1, 2] var mutable = array mutable.append(3) original struct Array<Int> _storage 1, 2 … refCount: 1 [1, 2] mutable struct Array<Int> _storage 1, 2, 3 … refCount: 1 [1, 2, 3]
  • 71. Swift의 Mutability 하지만, 함수로는 var 타입 변수를 넘길 수 없다. (Swift3) 
 func append(var array: [Int]) { array.append(3) }
  • 72. Swift의 Mutability 
 func append(var array: [Int]) { array.append(3) } var mutable: [Int] = [1, 2] append(array: mutable) 어짜피 Value 타입이기 때문에, 본래의 변수가 변하지 않는다 하지만, 함수로는 var 타입 변수를 넘길 수 없다. (Swift3)
  • 73. Swift의 Mutability 
 func append(var array: [Int]) { array.append(3) } var mutable: [Int] = [1, 2] append(array: mutable) 하지만, 값을 변경해야하는 경우마다 데이터를 복사해야하는 것도 비효율적 하지만, 함수로는 var 타입 변수를 넘길 수 없다. (Swift3)
  • 74. Swift의 Mutability Pass by Reference 
 func append(array: inout [Int]) { array.append(3) } var mutable: [Int] = [1, 2] append(array: &mutable)
  • 75. Swift의 Mutability 
 func append(array: inout [Int]) { array.append(3) } var mutable: [Int] = [1, 2] append(array: &mutable) mutable struct Array<Int> _storage 1, 2 … refCount: 1 [1, 2] In-Out 파라미터
  • 76. Swift의 Mutability 
 func append(array: inout [Int]) { array.append(3) } var mutable: [Int] = [1, 2] append(array: &mutable) array (func append) struct Array<Int> _storage 1, 2 … refCount: 1 [1, 2] In-Out 파라미터
  • 77. Swift의 Mutability In-Out 파라미터 
 func append(array: inout [Int]) { array.append(3) } var mutable: [Int] = [1, 2] append(array: &mutable) array (func append) struct Array<Int> _storage 1, 2, 3 … refCount: 1 [1, 2, 3]
  • 78. Swift의 Mutability 
 func append(array: inout [Int]) { array.append(3) } var mutable: [Int] = [1, 2] append(array: &mutable) mutable struct Array<Int> _storage 1, 2, 3 … refCount: 1 [1, 2, 3] Copy없이 데이터를 변경할 수 있음 In-Out 파라미터
  • 79. In-Out과 Reference 
 func increase(_ i: inout Int) { i += 1 } var number = 10 increase(&number) print(number) In-Out 파라미터 원래 변수의 주소가 넘어감 원래 변수의 value를 변경하게 됨
  • 80. In-Out과 Reference 
 func increase(_ i: inout Int) { i += 1 } var number = 10 increase(&number) print(number) 
 class Wrapper(var i: Int) fun increase(wrapper: Wrapper) { wrapper.i += 1 } val number = Wrapper(10) increase(number) println(number.i) 원래 변수의 주소가 넘어감 원래 변수의 value를 변경하게 됨 Wrapper를 이용할 수 밖에 없음 In-Out 파라미터
  • 81. In-Out과 Reference 
 func increase(_ i: inout Int) { i += 1 } var number = 10 increase(&number) print(number) 
 class Wrapper(var i: Int) fun increase(wrapper: Wrapper) { wrapper.i += 1 } val number = Wrapper(10) increase(number) println(number.i) 원래 변수의 주소가 넘어감 원래 변수의 value를 변경하게 됨 Wrapper를 이용할 수 밖에 없음 In-Out 파라미터 이것이 두 언어의 Mutability 구현의 차이
  • 83. Extension extension Int { var length: Int { return String(self).characters.count } func concat(_ to: Int) -> String { return String(self) + String(to) } } print(1234.length) // 4 print(123.concat(456)) // "123456" val Int.length: Int get() = toString().length fun Int.concat(to: Int): String = toString() + to.toString() 
 println(123.length) // 3 
 println(123.concat(456)) // "123456"
 extension 정의 block 사용
  • 84. Extension extension Int { var length: Int { return String(self).characters.count } func concat(_ to: Int) -> String { return String(self) + String(to) } } print(1234.length) // 4 print(123.concat(456)) // "123456" val Int.length: Int get() = toString().length fun Int.concat(to: Int): String = toString() + to.toString() 
 println(123.length) // 3 
 println(123.concat(456)) // "123456"
 extension 정의 block 사용 extension할 각 함수, 프로퍼티 별로 정의
  • 85. Extension extension Int { var length: Int { return String(self).characters.count } func concat(_ to: Int) -> String { return String(self) + String(to) } } print(1234.length) // 4 print(123.concat(456)) // "123456" val Int.length: Int get() = toString().length fun Int.concat(to: Int): String = toString() + to.toString() 
 println(123.length) // 3 
 println(123.concat(456)) // "123456"
 extension 정의 block 사용 extension할 각 함수, 프로퍼티 별로 정의 fun length(receiver: Int) = receiver.toString().length fun concat(receiver: Int, to: Int): String = receiver.toString() + to.toString() 실제로는 아래와 같은 함수로 컴파일 됨
  • 86. Trait class MyClass { } protocol MyProtocol { } extension MyClass: MyProtocol { } let bar: MyProtocol = MyClass() extension MyProtocol { func foo() { } }
  • 87. Trait class MyClass { } protocol MyProtocol { } extension MyClass: MyProtocol { } let bar: MyProtocol = MyClass() extension MyProtocol { func foo() { } } bar.foo() let bar2: MyClass = MyClass() bar2.foo()
  • 88. Trait class MyClass { } protocol MyProtocol { } extension MyClass: MyProtocol { } let bar: MyProtocol = MyClass() extension MyProtocol { func foo() { } } bar.foo() let bar2: MyClass = MyClass() bar2.foo() AKA: Protocol Oriented Programming
  • 89. class MyClass { } protocol MyProtocol { } extension MyClass: MyProtocol { } let bar: MyProtocol = MyClass() extension MyProtocol { func foo() { } } bar.foo() let bar2: MyClass = MyClass() bar2.foo() interface MyProtocol { fun foo() { } } class MyClass : MyProtocol val bar: MyProtocol = MyClass() bar.foo() AKA: Protocol Oriented Programming Trait
  • 90. class MyClass { } protocol MyProtocol { } extension MyClass: MyProtocol { } let bar: MyProtocol = MyClass() extension MyProtocol { func foo() { } } bar.foo() let bar2: MyClass = MyClass() bar2.foo() interface MyProtocol { fun foo() { } } class MyClass : MyProtocol val bar: MyProtocol = MyClass() bar.foo() fun MyProtocol.foo2() { } bar.foo2() val bar2: MyClass = MyClass() bar2.foo2() AKA: Protocol Oriented Programming Trait
  • 91. class MyClass { } protocol MyProtocol { } extension MyClass: MyProtocol { } let bar: MyProtocol = MyClass() extension MyProtocol { func foo() { } } bar.foo() let bar2: MyClass = MyClass() bar2.foo() interface MyProtocol { fun foo() { } } class MyClass : MyProtocol val bar: MyProtocol = MyClass() bar.foo() fun MyProtocol.foo2() { } bar.foo2() val bar2: MyClass = MyClass() bar2.foo2() AKA: Protocol Oriented Programming 미리 인터페이스가 클래스에 적용이 되어야함 Trait
  • 92. Trait extension String: MyProtocol { } "Swift".foo() 정의되어 있는 class/struct에도 trait 가능 class MyClass { } protocol MyProtocol { } extension MyClass: MyProtocol { } let bar: MyProtocol = MyClass() extension MyProtocol { func foo() { } } bar.foo() let bar2: MyClass = MyClass() bar2.foo() interface MyProtocol { fun foo() { } } class MyClass : MyProtocol val bar: MyProtocol = MyClass() bar.foo() fun MyProtocol.foo2() { } bar.foo2() val bar2: MyClass = MyClass() bar2.foo2() AKA: Protocol Oriented Programming 미리 인터페이스가 클래스에 적용이 되어야함
  • 93. Trait extension String: MyProtocol { } "Swift".foo() // ... // ... // ... 정의되어 있는 class/struct에도 trait 가능 안됨 class MyClass { } protocol MyProtocol { } extension MyClass: MyProtocol { } let bar: MyProtocol = MyClass() extension MyProtocol { func foo() { } } bar.foo() let bar2: MyClass = MyClass() bar2.foo() interface MyProtocol { fun foo() { } } class MyClass : MyProtocol val bar: MyProtocol = MyClass() bar.foo() fun MyProtocol.foo2() { } bar.foo2() val bar2: MyClass = MyClass() bar2.foo2() AKA: Protocol Oriented Programming 미리 인터페이스가 클래스에 적용이 되어야함
  • 94. 유틸리티를 위한 extension 
 fun <T> T.apply(block: T.() -> Unit): T { block(); return this } val sum = 1.apply { println("get 1") } + 2 // 3 
 fun <T, R> T.let(block: (T) -> R): R = block(this) val file = "filename".let { File(it) } 
 fun CharSequence?.isNullOrBlank(): Boolean = this == null || this.isBlank() val str: String? = null if (str.isNullOrBlank()) { } Nullable에 대한 extension 모든 타입에 대한 넘나 편리한 유틸리티 선언형 표현에 크게 도움이 됨
  • 96. Heap 
 func foo() { let subview: UIView = UIView(rect: CGRect.zero) self.view.addSubview(subview) subview.removeFromSuperview() } ARC class UIView refCount: 1 … Stack subview: class UIViewController refCount: 1 subview: …
  • 97. Heap 
 func foo() { let subview: UIView = UIView(rect: CGRect.zero) self.view.addSubview(subview) subview.removeFromSuperview() } ARC class UIView refCount: 2 … Stack subview: class UIViewController refCount: 1 subview: …
  • 98. Heap 
 func foo() { let subview: UIView = UIView(rect: CGRect.zero) self.view.addSubview(subview) subview.removeFromSuperview() } ARC class UIView refCount: 1 … Stack subview: class UIViewController refCount: 1 subview: …
  • 99. Heap 
 func foo() { let subview: UIView = UIView(rect: CGRect.zero) self.view.addSubview(subview) subview.removeFromSuperview() } ARC class UIView refCount: 0 … Stack subview: class UIViewController refCount: 1 subview: …
  • 100. Heap 
 func foo() { let subview: UIView = UIView(rect: CGRect.zero) self.view.addSubview(subview) subview.removeFromSuperview() } ARC Stack class UIViewController refCount: 1 subview: …
  • 101. Heap 
 fun foo() {
 val subview = View(context)
 
 this.viewGroup.addView(subview)
 
 this.viewGroup.removeView(subview)
 } GC class View … Stack subview: class ViewGroup child: … GC task thread
  • 102. Heap 
 fun foo() {
 val subview = View(context)
 
 this.viewGroup.addView(subview)
 
 this.viewGroup.removeView(subview)
 } GC class View … Stack subview: class ViewGroup child: … GC task thread
  • 103. Heap 
 fun foo() {
 val subview = View(context)
 
 this.viewGroup.addView(subview)
 
 this.viewGroup.removeView(subview)
 } GC class View … Stack subview: class ViewGroup child: … GC task thread
  • 104. Heap 
 fun foo() {
 val subview = View(context)
 
 this.viewGroup.addView(subview)
 
 this.viewGroup.removeView(subview)
 } GC class View … Stack subview: class ViewGroup child: … GC task thread
  • 105. Heap 
 fun foo() {
 val subview = View(context)
 
 this.viewGroup.addView(subview)
 
 this.viewGroup.removeView(subview)
 } GC class View … Stack class ViewGroup child: … GC task thread 바로 해제되지 않는다.
  • 106. Heap 
 fun foo() {
 val subview = View(context)
 
 this.viewGroup.addView(subview)
 
 this.viewGroup.removeView(subview)
 } GC class View … Stack class ViewGroup child: … No ref? GC task thread
  • 107. Heap 
 fun foo() {
 val subview = View(context)
 
 this.viewGroup.addView(subview)
 
 this.viewGroup.removeView(subview)
 } GC class View … Stack class ViewGroup child: … No ref? GC task thread
  • 108. Heap 
 fun foo() {
 val subview = View(context)
 
 this.viewGroup.addView(subview)
 
 this.viewGroup.removeView(subview)
 } GC Stack class ViewGroup child: … GC task thread
  • 109. ARC vs GC: ReactiveX var disposeBag = DisposeBag() func startCount() { Observable<Int>.interval(1.0, scheduler: s) .subscribe(onNext: { print("next: ($0)") }) .addDisposableTo(disposeBag) } func stopCount() { disposeBag = DisposeBag() }
 private val disposables = CompositeDisposable()
 
 fun startCount() {
 Observable.interval(0, 1, TimeUnit.SECONDS)
 .subscribe { Log.d(TAG, "next: $it") }
 .let { disposables.add(it) }
 }
 
 fun stopCount() {
 disposables.clear()
 } 1. disposeBag 변수에 다른 값을 할당 Subscription을 명시적으로 끝내야할 때
  • 110. ARC vs GC: ReactiveX var disposeBag = DisposeBag() func startCount() { Observable<Int>.interval(1.0, scheduler: s) .subscribe(onNext: { print("next: ($0)") }) .addDisposableTo(disposeBag) } func stopCount() { disposeBag = DisposeBag() }
 private val disposables = CompositeDisposable()
 
 fun startCount() {
 Observable.interval(0, 1, TimeUnit.SECONDS)
 .subscribe { Log.d(TAG, "next: $it") }
 .let { disposables.add(it) }
 }
 
 fun stopCount() {
 disposables.clear()
 } 1. disposeBag 변수에 다른 값을 할당 2. 기존 DisposeBag 객체는 refcount == 0 이 됨 Subscription을 명시적으로 끝내야할 때
  • 111. ARC vs GC: ReactiveX var disposeBag = DisposeBag() func startCount() { Observable<Int>.interval(1.0, scheduler: s) .subscribe(onNext: { print("next: ($0)") }) .addDisposableTo(disposeBag) } func stopCount() { disposeBag = DisposeBag() }
 private val disposables = CompositeDisposable()
 
 fun startCount() {
 Observable.interval(0, 1, TimeUnit.SECONDS)
 .subscribe { Log.d(TAG, "next: $it") }
 .let { disposables.add(it) }
 }
 
 fun stopCount() {
 disposables.clear()
 } 1. disposeBag 변수에 다른 값을 할당 2. 기존 DisposeBag 객체는 refcount == 0 이 됨 3. 즉시 메모리 해제가 되며 deinit이 불림 Subscription을 명시적으로 끝내야할 때
  • 112. ARC vs GC: ReactiveX var disposeBag = DisposeBag() func startCount() { Observable<Int>.interval(1.0, scheduler: s) .subscribe(onNext: { print("next: ($0)") }) .addDisposableTo(disposeBag) } func stopCount() { disposeBag = DisposeBag() }
 private val disposables = CompositeDisposable()
 
 fun startCount() {
 Observable.interval(0, 1, TimeUnit.SECONDS)
 .subscribe { Log.d(TAG, "next: $it") }
 .let { disposables.add(it) }
 }
 
 fun stopCount() {
 disposables.clear()
 } 1. disposeBag 변수에 다른 값을 할당 2. 기존 DisposeBag 객체는 refcount == 0 이 됨 3. 즉시 메모리 해제가 되며 deinit이 불림 4. 가지고 있던 구독을 dispose 함 Subscription을 명시적으로 끝내야할 때 
 public final class DisposeBag: DisposeBase { … deinit { dispose() } }
  • 113. ARC vs GC: ReactiveX var disposeBag = DisposeBag() func startCount() { Observable<Int>.interval(1.0, scheduler: s) .subscribe(onNext: { print("next: ($0)") }) .addDisposableTo(disposeBag) } func stopCount() { disposeBag = DisposeBag() }
 private val disposables = CompositeDisposable()
 
 fun startCount() {
 Observable.interval(0, 1, TimeUnit.SECONDS)
 .subscribe { Log.d(TAG, "next: $it") }
 .let { disposables.add(it) }
 }
 
 fun stopCount() {
 disposables.clear()
 } 1. disposeBag 변수에 다른 값을 할당 2. 기존 DisposeBag 객체는 refcount == 0 이 됨 3. 즉시 메모리 해제가 되며 deinit이 불림 4. 가지고 있던 구독을 dispose 함 GC에서는 언제 해제될지 예측할 수 없다. Subscription을 명시적으로 끝내야할 때
  • 114. ARC vs GC: ReactiveX var disposeBag = DisposeBag() func startCount() { Observable<Int>.interval(1.0, scheduler: s) .subscribe(onNext: { print("next: ($0)") }) .addDisposableTo(disposeBag) } func stopCount() { disposeBag = DisposeBag() }
 private val disposables = CompositeDisposable()
 
 fun startCount() {
 Observable.interval(0, 1, TimeUnit.SECONDS)
 .subscribe { Log.d(TAG, "next: $it") }
 .let { disposables.add(it) }
 }
 
 fun stopCount() {
 disposables.clear()
 } 1. disposeBag 변수에 다른 값을 할당 2. 기존 DisposeBag 객체는 refcount == 0 이 됨 3. 즉시 메모리 해제가 되며 deinit이 불림 4. 가지고 있던 구독을 dispose 함 GC에서는 언제 해제될지 예측할 수 없다. -> 명시적으로 CompositeDisposable 이용 Subscription을 명시적으로 끝내야할 때
  • 115. ARC vs GC: ReactiveX var disposeBag = DisposeBag() func startCount() { Observable<Int>.interval(1.0, scheduler: s) .subscribe(onNext: { print("next: ($0)") }) .addDisposableTo(disposeBag) } func stopCount() { disposeBag = DisposeBag() }
 private val disposables = CompositeDisposable()
 
 fun startCount() {
 Observable.interval(0, 1, TimeUnit.SECONDS)
 .subscribe { Log.d(TAG, "next: $it") }
 .let { disposables.add(it) }
 }
 
 fun stopCount() {
 disposables.clear()
 } 1. disposeBag 변수에 다른 값을 할당 2. 기존 DisposeBag 객체는 refcount == 0 이 됨 3. 즉시 메모리 해제가 되며 deinit이 불림 4. 가지고 있던 구독을 dispose 함 GC에서는 언제 해제될지 예측할 수 없다. -> 명시적으로 CompositeDisposable 이용 Subscription을 명시적으로 끝내야할 때 *) RxSwift3에도 CompositeDisposable은 있으나 clear가 없이 dispose만 있다. 재활용이 불가능
  • 116. ARC vs GC: 순환 참조 
 class MyClass { var closure: (() -> Void)? init() { closure = { self.foo() } } func foo() { } } var c: MyClass? = MyClass() c = nil class MyClass { var lambda: ((Unit) -> Unit)? init { lambda = { this.foo() } } fun foo() { } } var c: MyClass? = MyClass() c = null
  • 117. ARC vs GC: 순환 참조 
 class MyClass { var closure: (() -> Void)? init() { closure = { self.foo() } } func foo() { } } var c: MyClass? = MyClass() c = nil class MyClass { var lambda: ((Unit) -> Unit)? init { lambda = { this.foo() } } fun foo() { } } var c: MyClass? = MyClass() c = null
  • 118. ARC vs GC: 순환 참조 
 class MyClass { var closure: (() -> Void)? init() { closure = { self.foo() } } func foo() { } } var c: MyClass? = MyClass() c = nil class MyClass { var lambda: ((Unit) -> Unit)? init { lambda = { this.foo() } } fun foo() { } } var c: MyClass? = MyClass() c = null 순환 참조 발생 -> 런타임 메모리 누수 발생
  • 119. ARC vs GC: 순환 참조 
 class MyClass { var closure: (() -> Void)? init() { closure = { self.foo() } } func foo() { } } var c: MyClass? = MyClass() c = nil class MyClass { var lambda: ((Unit) -> Unit)? init { lambda = { this.foo() } } fun foo() { } } var c: MyClass? = MyClass() c = null 순환 참조 발생 -> 런타임 메모리 누수 발생 왜일까?
  • 120. ARC vs GC: 순환 참조 
 class MyClass { var closure: (() -> Void)? init() { closure = { self.foo() } } func foo() { } } var c: MyClass? = MyClass() c = nil
  • 121. c: ARC vs GC: 순환 참조 
 class MyClass { var closure: (() -> Void)? init() { closure = { self.foo() } } func foo() { } } var c: MyClass? = MyClass() c = nil class MyClass refCount: 1 closure: … Closure refCount: 1 “self”: …
  • 122. c: ARC vs GC: 순환 참조 
 class MyClass { var closure: (() -> Void)? init() { closure = { self.foo() } } func foo() { } } var c: MyClass? = MyClass() c = nil class MyClass refCount: 1 closure: … Closure refCount: 1 “self”: …
  • 123. c: ARC vs GC: 순환 참조 
 class MyClass { var closure: (() -> Void)? init() { closure = { self.foo() } } func foo() { } } var c: MyClass? = MyClass() c = nil class MyClass refCount: 2 closure: … Closure refCount: 1 “self”: …
  • 124. c: ARC vs GC: 순환 참조 
 class MyClass { var closure: (() -> Void)? init() { closure = { self.foo() } } func foo() { } } var c: MyClass? = MyClass() c = nil class MyClass refCount: 2 closure: … Closure refCount: 1 “self”: … 순환 참조 발생
  • 125. c: ARC vs GC: 순환 참조 
 class MyClass { var closure: (() -> Void)? init() { closure = { self.foo() } } func foo() { } } var c: MyClass? = MyClass() c = nil class MyClass refCount: 2 closure: … Closure refCount: 1 “self”: …
  • 126. c: ARC vs GC: 순환 참조 
 class MyClass { var closure: (() -> Void)? init() { closure = { self.foo() } } func foo() { } } var c: MyClass? = MyClass() c = nil class MyClass refCount: 1 closure: … Closure refCount: 1 “self”: …
  • 127. c: ARC vs GC: 순환 참조 
 class MyClass { var closure: (() -> Void)? init() { closure = { self.foo() } } func foo() { } } var c: MyClass? = MyClass() c = nil class MyClass refCount: 1 closure: … Closure refCount: 1 “self”: … 이건 이제 어느 누구도 해제할 수 없다. -> 메모리 누수!!
  • 128. c: ARC vs GC: 순환 참조 
 class MyClass { var closure: (() -> Void)? init() { closure = {[weak self] in self?.foo()} } func foo() { } } var c: MyClass? = MyClass() c = nil class MyClass refCount: 1 closure: … Closure refCount: 1 “self”: …
  • 129. c: ARC vs GC: 순환 참조 
 class MyClass { var closure: (() -> Void)? init() { closure = {[weak self] in self?.foo()} } func foo() { } } var c: MyClass? = MyClass() c = nil class MyClass refCount: 1 closure: … Closure refCount: 1 “self”: …
  • 130. c: ARC vs GC: 순환 참조 
 class MyClass { var closure: (() -> Void)? init() { closure = {[weak self] in self?.foo()} } func foo() { } } var c: MyClass? = MyClass() c = nil class MyClass refCount: 1 closure: … Closure refCount: 1 “self”: … weak 참조, refCount 증가시키지 않음 (unowned도 비슷)
  • 131. c: ARC vs GC: 순환 참조 
 class MyClass { var closure: (() -> Void)? init() { closure = {[weak self] in self?.foo()} } func foo() { } } var c: MyClass? = MyClass() c = nil class MyClass refCount: 1 closure: … Closure refCount: 1 “self”: …
  • 132. c: ARC vs GC: 순환 참조 
 class MyClass { var closure: (() -> Void)? init() { closure = {[weak self] in self?.foo()} } func foo() { } } var c: MyClass? = MyClass() c = nil class MyClass refCount: 0 closure: … Closure refCount: 1 “self”: …
  • 133. c: ARC vs GC: 순환 참조 
 class MyClass { var closure: (() -> Void)? init() { closure = {[weak self] in self?.foo()} } func foo() { } } var c: MyClass? = MyClass() c = nil Closure refCount: 0 “self”: nil …
  • 134. c: ARC vs GC: 순환 참조 
 class MyClass { var closure: (() -> Void)? init() { closure = {[weak self] in self?.foo()} } func foo() { } } var c: MyClass? = MyClass() c = nil
  • 135. ARC vs GC: 순환 참조 
 class MyClass { var closure: (() -> Void)? init() { closure = {[weak self] in self?.foo()} } func foo() { } } var c: MyClass? = MyClass() c = nil
  • 136. ARC vs GC: 순환 참조 class MyClass { var lambda: ((Unit) -> Unit)? init { lambda = { this.foo() } } fun foo() { } } var c: MyClass? = MyClass() c = null c: class MyClass lambda … Lambda “self”: …
  • 137. ARC vs GC: 순환 참조 class MyClass { var lambda: ((Unit) -> Unit)? init { lambda = { this.foo() } } fun foo() { } } var c: MyClass? = MyClass() c = null c: class MyClass lambda … Lambda “self”: …
  • 138. ARC vs GC: 순환 참조 class MyClass { var lambda: ((Unit) -> Unit)? init { lambda = { this.foo() } } fun foo() { } } var c: MyClass? = MyClass() c = null c: class MyClass lambda … Lambda “self”: …
  • 139. ARC vs GC: 순환 참조 class MyClass { var lambda: ((Unit) -> Unit)? init { lambda = { this.foo() } } fun foo() { } } var c: MyClass? = MyClass() c = null c: class MyClass lambda … Lambda “self”: … No ref? GC task thread
  • 140. ARC vs GC: 순환 참조 class MyClass { var lambda: ((Unit) -> Unit)? init { lambda = { this.foo() } } fun foo() { } } var c: MyClass? = MyClass() c = null c: class MyClass lambda … Lambda “self”: … GC task thread
  • 141. ARC vs GC: 순환 참조 class MyClass { var lambda: ((Unit) -> Unit)? init { lambda = { this.foo() } } fun foo() { } } var c: MyClass? = MyClass() c = null c: GC task thread
  • 142. ARC vs GC: 순환 참조 class MyClass { var lambda: ((Unit) -> Unit)? init { lambda = { this.foo() } } fun foo() { } } var c: MyClass? = MyClass() c = null
  • 143. ARC vs GC: 순환 참조 
 class MyClass { var closure: (() -> Void)? init() { closure = {[weak self] in self?.foo()} } func foo() { } } var c: MyClass? = MyClass() c = nil class MyClass { var lambda: ((Unit) -> Unit)? init { lambda = { this.foo() } } fun foo() { } } var c: MyClass? = MyClass() c = null
  • 144. ­ 부록 “너무 길어서 통편집된 주제들”
  • 146. switch / when let index = 100
 let validRange = 0...1000 let special: Set<Int> = [100, 101] switch index { case 0...10, 20, 30: print("0~10, 20, 30") case 11, 22, 33: print("11, 22, 33") case _ where special.contains(index): print("special") case validRange: print("valid") default: print("invalid") } val index = 11
 val validRange = 0..1000 val special = setOf(100, 101) when (index) { !in validRange -> println("invalid") in 0..10, 20, 30 -> println("0~10, 20, 30") 11, 22, 33 -> println("11, 22, 33") in special -> println("special") else -> println("valid") } 공통점: break 필요없음. 주의점: Swift의 switch에 익숙해지면 다른 언어 (Java, C, C++) switch에서 break 빼먹기 쉬움 -> 컴파일 에러 안남, 버그
  • 147. switch / when let index = 100
 let validRange = 0...1000 let special: Set<Int> = [100, 101] switch index { case 0...10, 20, 30: print("0~10, 20, 30") case 11, 22, 33: print("11, 22, 33") case _ where special.contains(index): print("special") case validRange: print("valid") default: print("invalid") } val index = 11
 val validRange = 0..1000 val special = setOf(100, 101) when (index) { !in validRange -> println("invalid") in 0..10, 20, 30 -> println("0~10, 20, 30") 11, 22, 33 -> println("11, 22, 33") in special -> println("special") else -> println("valid") } - enum의 associated value 가능 - tuple 가능
  • 148. switch / when let index = 100
 let validRange = 0...1000 let special: Set<Int> = [100, 101] switch index { case 0...10, 20, 30: print("0~10, 20, 30") case 11, 22, 33: print("11, 22, 33") case _ where special.contains(index): print("special") case validRange: print("valid") default: print("invalid") } val index = 11
 val validRange = 0..1000 val special = setOf(100, 101) when (index) { !in validRange -> println("invalid") in 0..10, 20, 30 -> println("0~10, 20, 30") 11, 22, 33 -> println("11, 22, 33") in special -> println("special") else -> println("valid") } - enum의 associated value 가능 - tuple 가능 
 when { str.isEmpty() -> println("str empty") str.length > 100 -> println("str too long") File(str).exists() -> println("file exists") else -> println("file not found") } if .. else if .. else if … else 의 가독성 개선
  • 149. 제어 구문과 Expression Expression: 값을 가진 구문 index + 3 "Kotlin $version” str.length + 10 str.isEmpty()
  • 150. 제어 구문과 Expression Expression: 값을 가진 구문 index + 3 "Kotlin $version” str.length + 10 str.isEmpty() if (count == 0) { "Empty" } else { "Count: $count" } if…else 도 Expression!
  • 151. 제어 구문과 Expression Expression: 값을 가진 구문 index + 3 "Kotlin $version” str.length + 10 str.isEmpty() if (count == 0) { "Empty" } else { "Count: $count" } 
 val str = if (count == 0) "Empty" else "Count: $count"
 
 let str = count == 0 ? "Empty" : "Count: (count)"
 if…else 도 Expression!
  • 152. 제어 구문과 Expression Expression: 값을 가진 구문 index + 3 "Kotlin $version” str.length + 10 str.isEmpty() if (count == 0) { "Empty" } else { "Count: $count" } 
 val str = if (count == 0) "Empty" else "Count: $count"
 
 let str = count == 0 ? "Empty" : "Count: (count)"
 if…else 도 Expression!
  • 153. 제어 구문과 Expression 
 val str = if (count == 0) { notifyEmpty() "Empty" } else { total++ "Count: $count" } 맨 마지막 expression이 Block의 값
  • 154. 제어 구문과 Expression 
 val str = if (count == 0) { notifyEmpty() "Empty" } else { total++ "Count: $count" } 다른 작업을 할 수 있음
  • 155. 제어 구문과 Expression 
 val str = if (count == 0) { notifyEmpty() "Empty" } else { total++ "Count: $count" } 
 val message = when { str.isEmpty() -> "empty" str.length > 100 -> "too long" File(str).exists() -> "file exists" else -> "file not found" } when 도 expression 중간의 임시 변수 없이 값을 바로 얻어 변수를 초기화하거나, 함수 인자로 넘길때 편리함 -> 선언형으로 코드를 작성하기 쉬움
  • 156. for 루프 for (int i = 0; i < array.count; i++) { NSString* str = array[i]; // ... } c-style의 전통적인 for 루프
  • 157. for (int i = 0; i < array.count; i++) { NSString* str = array[i]; // ... } for 루프 c-style의 전통적인 for 루프
  • 158. for (int i = 0; i < array.count; i++) { NSString* str = array[i]; // ... } 직관적이지 않다더라… 심지어 는 ++도 없앰… for 루프 c-style의 전통적인 for 루프
  • 159. Iterator와 for 루프 Element let array = ["Swift", "Kotlin"] for str in array { print(str) } val array = listOf("Swift", "Kotlin")
 for (str in array) { println(str) }
 index와
 Element for (index, str) in array.enumerated() { print("(index): (str)") } for ((index, str) in array.withIndex()) { println("$index: $str") } index for i in 0..<100 { } for (i in 0 until 100) { }
  • 160. Iterator와 for 루프 Element let array = ["Swift", "Kotlin"] for str in array { print(str) } val array = listOf("Swift", "Kotlin")
 for (str in array) { println(str) }
 index와
 Element for (index, str) in array.enumerated() { print("(index): (str)") } for ((index, str) in array.withIndex()) { println("$index: $str") } index for i in 0..<100 { } for (i in 0 until 100) { }
  • 161. Iterator와 for 루프 Element let array = ["Swift", "Kotlin"] for str in array { print(str) } val array = listOf("Swift", "Kotlin")
 for (str in array) { println(str) }
 index와
 Element for (index, str) in array.enumerated() { print("(index): (str)") } for ((index, str) in array.withIndex()) { println("$index: $str") } index for i in 0..<100 { } for (i in 0 until 100) { }
  • 162. Iterator와 for 루프 Element let array = ["Swift", "Kotlin"] for str in array { print(str) } val array = listOf("Swift", "Kotlin")
 for (str in array) { println(str) }
 index와
 Element for (index, str) in array.enumerated() { print("(index): (str)") } for ((index, str) in array.withIndex()) { println("$index: $str") } index for i in 0..<100 { } for (i in 0 until 100) { }
  • 163. Iterator와 for 루프 Element let array = ["Swift", "Kotlin"] for str in array { print(str) } val array = listOf("Swift", "Kotlin")
 for (str in array) { println(str) }
 index와
 Element for (index, str) in array.enumerated() { print("(index): (str)") } for ((index, str) in array.withIndex()) { println("$index: $str") } index for i in 0..<100 { } for (i in 0...99) { }
  • 165. 함수 func message(status: Int) -> String { return “TBD" } fun message(status: Int) : String { return "TBD" } fun message(status: Int) : String = "TBD" func message(status: Int) -> String { switch (status) { case 200: return "OK" case 201...299: return "Success" case 300...399: return "Redirect" case 400..<500: return "Client error" case 500..<600: return "Server error" default: return “Undefined" } } fun message(status: Int) : String = when (status) { 200 -> "OK" in 201..299 -> "Success" in 300..399 -> "Redirect" in 400 until 500 -> "Client error" in 500 until 600 -> "Server error" else -> "Undefined" }
  • 166. Named Argument func insert(name: String, index: Int) { // check index storage[index] = name } insert(name: "Swift", index: 0) fun insert(name: String, index: Int) { // check index storage[index] = name } insert(name = "Kotlin", index = 0) insert("Kotlin", 0) insert(index = 0, name = "Kotlin") func insert(_ name: String, at index: Int) { // check index storage[index] = name } insert("Swift", at: 0) 함수의 각 파라미터 이름을 붙여 호출할 수 있음
  • 167. 기본값 func insert(name: String, index: Int = 0) { // check index storage[index] = name } insert(name: "Swift") fun insert(name: String, index: Int = 0) { // check index storage[index] = name } insert("Kotlin") 파라미터에 기본값을 줄 수 있음
  • 168. 로컬 함수 로컬 함수 func foo(_ factor: Int) {
 func calculate(_ i: Int) -> Int { return i * factor } for i in 1...10 { print(calculate(i)) } } fun foo(factor: Int) {
 fun calculate(i: Int) = i * factor for (i in 1..10) { println(calculate(i)) } } 로컬 함수는 로컬 변수에 접근할 수 있음
  • 169. 일급 함수 func length(str: String) -> Int { return str.characters.count } var foo: (String) -> Int foo = length print(foo("Swift")) fun length(str: String): Int = str.length 
 
 var foo: (String) -> Int foo = ::length println(foo("Kotlin")) - 함수도 타입이 있고 변수에 할당하고 파라미터로 넘길 수 있다.
  • 170. 일급 함수 func length(str: String) -> Int { return str.characters.count } var foo: (String) -> Int foo = length print(foo("Swift")) foo = { str in Int(str) ?? 0 } print(foo("Swift")) fun length(str: String): Int = str.length 
 
 var foo: (String) -> Int foo = ::length println(foo("Kotlin")) foo = { str -> str.toIntOrNull() ?: 0 } println(foo("Kotlin")) - 함수도 타입이 있고 변수에 할당하고 파라미터로 넘길 수 있다. - 익명함수를 런타임에 만들 수 있다. Closure Lambda
  • 171. 함수형 표현 let array = [0, 1, 2, 3] array.filter { $0 > 0 } .map { "[index: ($0)]" } .forEach { print($0) } val list = listOf(0, 1, 2, 3) list.filter { it > 0 } .map { "[index: $it]" } .forEach { println(it) } 자세한 설명은 세션의 범위를 넘어서므로 생략 보통 Collection 등의 extension에 공통적으로 정의됨
  • 173. 정리 변수의 타입 타입 추론 Optional / Nullable Value타입과 Reference타입의 Immutable / Mutable Extension과 Trait ARC vs. GC 제어구문의 표현형과 선언형 문법 Iterator를 이용한 for 루프 문법 Closure/Lambda와 함수형 구문