Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

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

2,601 views

Published on

Let'Swift 2017 발표자료입니다.
스위프트, 코틀린의 문법의 유사성을 소개하며,
모던 언어에서의 이슈들을 두 언어가 어떻게 해결하고 있는지, 차이점이 생길 수 밖에 없는 기반 시스템을 비교합니다.

Published in: Software
  • Be the first to comment

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

  1. 1. let swift(17) Swift, Kotlin과 모던 언어의 특징 세미콜론 없는 세상 github.com/inkfyox유용하
  2. 2. let swift(17)
  3. 3. 목적 Swift vs. Kotlin Swift & Kotlin 문법의 유사성 소개 모던 언어에서의 이슈들을 두 언어가 어떻게 해결하고 있는지 비교 차이점이 생길 수 밖에 없는 기반 시스템 비교
  4. 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. 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 프로젝트 공개 오픈소스화
  6. 6. let swift(17) 타입 시스템
  7. 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. 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. 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. 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. 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. 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. 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. 14. 타입 추론 SomeClassWithVeryLongName* bar = [[SomeClassWithVeryLongName alloc] init]; SomeClassWithVeryLongName* other = bar SomeClassWithVeryLongName bar = new SomeClassWithVeryLongName(); SomeClassWithVeryLongName other = bar; ObjC Java
  15. 15. 타입 추론 SomeClassWithVeryLongName* bar = [[SomeClassWithVeryLongName alloc] init]; SomeClassWithVeryLongName* other = bar SomeClassWithVeryLongName bar = new SomeClassWithVeryLongName(); SomeClassWithVeryLongName other = bar; ObjC Java 중복된 정보
  16. 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. 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. 18. Optional & Nullable nil/null 값을 가진 변수를 주소값으로 사용했을때 •런타임 에러 발생 •프로그램의 안정성을 해침 (가장 빈번한 에러) •Objc의 경우 sendmsg방식으로 크래시는 안나도 의도치 않은 동작 가능 •100% 안전하려면 항상 변수가 nil/null 인지 확인해야함 •nil/null인 경우가 없는 경우도 체크하게 됨 -> 비효율 •강제가 아니기 때문에 빠뜨릴 수 있음 -> 구멍
  19. 19. Optional & Nullable 타입에 nil/null을 가질 수 있는지의 의미도 부여한다면 •nil/null 가질 수 있는 Optional/Nullable 타입: 무조건 체크해야함 •런타임 에러 -> 컴파일타임 에러: 안정성 향상 •not-null 타입: 체크 안하고 안정적으로 사용 •의외로 not-null인 변수를 다루는 경우가 더 많음: 코드가 간결해짐
  20. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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
  30. 30. let swift(17) 자료 구조와 Mutability
  31. 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. 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. 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. 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. 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. 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. 37. Immutable type 공유되는 변수의 내부 값이 변경 가능할때 생기는 문제 원천 차단 복잡도 감소 •변수의 상태 변화에 대한 트래킹 이슈 없음 성능 향상 •multi-thread에서 lock없이 공유 가능
  38. 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. 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. 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. 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. 42. str1 struct String _storage "Let" String: Mutability … refCount: 1 "Let" let str1 = "Let" public struct String { … }
  43. 43. str1 struct String _storage "Let" String: Mutability … refCount: 1 "Let" let str1 = "Let" String은 struct로 value 타입이지만, 내부에 실제 문자열 데이터를 저장할 저장소는 reference 타입일 수 밖에 없다. public struct String { … }
  44. 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. 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. 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. 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. 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. 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. 50. 1. mutable 동작의 API가 없음 2. open class가 아니어서 상속을 할 수 없음 -> String 타입으로 다룰 수 있는 Mutable String을 만드는 것이 불가능 public class String … { … } String: Mutability
  51. 51. 1. mutable 동작의 API가 없음 2. open class가 아니어서 상속을 할 수 없음 -> String 타입으로 다룰 수 있는 Mutable String을 만드는 것이 불가능 String은 Map의 key등 상수형으로 많이 쓰임 이런 String의 상태가 변경되는 것은 큰 혼란을 일으킬 수 있음 public class String … { … } String: Mutability
  52. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 68. Swift의 Mutability Value 타입으로 구현 변수의 타입만으로 Immutable / mutable 동작 구분 (let, var) 데이터 저장공간은 Reference type의 멤버 변수로 가짐 Mutable 타입의 경우 내용이 처음 변경될 때 새로운 객체 생성 (이때 저장공간 복사 -> Copy-On-Write)
  69. 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. 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. 71. Swift의 Mutability 하지만, 함수로는 var 타입 변수를 넘길 수 없다. (Swift3) 
 func append(var array: [Int]) { array.append(3) }
  72. 72. Swift의 Mutability 
 func append(var array: [Int]) { array.append(3) } var mutable: [Int] = [1, 2] append(array: mutable) 어짜피 Value 타입이기 때문에, 본래의 변수가 변하지 않는다 하지만, 함수로는 var 타입 변수를 넘길 수 없다. (Swift3)
  73. 73. Swift의 Mutability 
 func append(var array: [Int]) { array.append(3) } var mutable: [Int] = [1, 2] append(array: mutable) 하지만, 값을 변경해야하는 경우마다 데이터를 복사해야하는 것도 비효율적 하지만, 함수로는 var 타입 변수를 넘길 수 없다. (Swift3)
  74. 74. Swift의 Mutability Pass by Reference 
 func append(array: inout [Int]) { array.append(3) } var mutable: [Int] = [1, 2] append(array: &mutable)
  75. 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. 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. 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. 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. 79. In-Out과 Reference 
 func increase(_ i: inout Int) { i += 1 } var number = 10 increase(&number) print(number) In-Out 파라미터 원래 변수의 주소가 넘어감 원래 변수의 value를 변경하게 됨
  80. 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. 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 구현의 차이
  82. 82. let swift(17) Extension
  83. 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. 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. 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. 86. Trait class MyClass { } protocol MyProtocol { } extension MyClass: MyProtocol { } let bar: MyProtocol = MyClass() extension MyProtocol { func foo() { } }
  87. 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. 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. 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. 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. 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. 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. 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. 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 모든 타입에 대한 넘나 편리한 유틸리티 선언형 표현에 크게 도움이 됨
  95. 95. let swift(17) 메모리 관리: ARC vs. GC
  96. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 120. ARC vs GC: 순환 참조 
 class MyClass { var closure: (() -> Void)? init() { closure = { self.foo() } } func foo() { } } var c: MyClass? = MyClass() c = nil
  121. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 142. ARC vs GC: 순환 참조 class MyClass { var lambda: ((Unit) -> Unit)? init { lambda = { this.foo() } } fun foo() { } } var c: MyClass? = MyClass() c = null
  143. 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. 144. ­ 부록 “너무 길어서 통편집된 주제들”
  145. 145. let swift(17) 제어 구문
  146. 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. 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. 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. 149. 제어 구문과 Expression Expression: 값을 가진 구문 index + 3 "Kotlin $version” str.length + 10 str.isEmpty()
  150. 150. 제어 구문과 Expression Expression: 값을 가진 구문 index + 3 "Kotlin $version” str.length + 10 str.isEmpty() if (count == 0) { "Empty" } else { "Count: $count" } if…else 도 Expression!
  151. 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. 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. 153. 제어 구문과 Expression 
 val str = if (count == 0) { notifyEmpty() "Empty" } else { total++ "Count: $count" } 맨 마지막 expression이 Block의 값
  154. 154. 제어 구문과 Expression 
 val str = if (count == 0) { notifyEmpty() "Empty" } else { total++ "Count: $count" } 다른 작업을 할 수 있음
  155. 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. 156. for 루프 for (int i = 0; i < array.count; i++) { NSString* str = array[i]; // ... } c-style의 전통적인 for 루프
  157. 157. for (int i = 0; i < array.count; i++) { NSString* str = array[i]; // ... } for 루프 c-style의 전통적인 for 루프
  158. 158. for (int i = 0; i < array.count; i++) { NSString* str = array[i]; // ... } 직관적이지 않다더라… 심지어 는 ++도 없앰… for 루프 c-style의 전통적인 for 루프
  159. 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. 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. 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. 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. 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) { }
  164. 164. let swift(17) 함수
  165. 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. 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. 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. 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. 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. 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. 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에 공통적으로 정의됨
  172. 172. let swift(17) 정리
  173. 173. 정리 변수의 타입 타입 추론 Optional / Nullable Value타입과 Reference타입의 Immutable / Mutable Extension과 Trait ARC vs. GC 제어구문의 표현형과 선언형 문법 Iterator를 이용한 for 루프 문법 Closure/Lambda와 함수형 구문
  174. 174. let swift(17)

×