๐ฆ ํผ์ํ๋ Swift ๊ณต๋ถ -2-
๐ Swift
์ ํ ๋์์ฑ The Swift Programming Language (Swift 5.1)๋ฅผ ์ฐธ๊ณ ํ๋ฉฐ ๊ณต๋ถํ๋ค.
์ด์ ๊ธ ๐ ํผ์ํ๋ Swift ๊ณต๋ถ -1- ๋ณด๋ฌ๊ฐ๊ธฐ
Inner function
func func1() -> Int{
let a = 10
func func2() -> Int{
return a + 5
}
return func2()
}
print(func1())
15
ํจ์ ์์ ํจ์๋ฅผ ์ ์ธํด์ ์ธ ์๋ ์๋ค.
## Inner function return
func makeIncrement() -> ((Int) -> Int){
func addOne(number : Int) -> Int{
return 1 + number
}
return addOne
}
var increment = makeIncrement()
print(increment(7))
8
makeIncrement()ํจ์๊ฐ addOne()ํจ์ ์์ฒด๋ฅผ ๋ฐํํ๋ค. ๋ฐํํ์ ๋ณด๋ฉด -> ((Int) -> Int) ์ธ๋ฐ ์ด๋ ์ธ์๋ก Int๋ฅผ ๋ฐ์ Int๋ฅผ ๋ฐํํ๋ ํจ์๋ฅผ ๋ฐํํ๋ค๋ ๋ป์ผ๋ก ๋ณผ ์ ์๋ค. ๋ณ์ increment๋ makeIncrement()ํจ์๋ฅผ ํตํด addOne()ํจ์๋ฅผ ์ ๋ฌ๋ฐ์๊ณ , ์ด๋ฅผ ํจ์์ฒ๋ผ ์ธ ์ ์๊ฒ ๋๊ฒ. ์์ ์์๋ ์ธ์๋ก 7์ ๋ฃ์ด์คฌ๊ธฐ ๋๋ฌธ์ 8์ด ๋ฐํ๋์๋ค.
Hand over function as argument
func hasMatch(givenList: [Int], condition: ((Int) -> Bool)) -> Bool{
for number in givenList{
if condition(number){
return true
}
}
return false
}
func lessThanTen(number: Int) -> Bool{
if number < 11{
return true
}
return false
}
func equalsTen(number: Int) -> Bool{
if number == 10{
return true
}
return false
}
var list = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21]
print(hasMatch(givenList: list, condition: lessThanTen))
print(hasMatch(givenList: list, condition: equalsTen))
true
false
ํจ์ hasMatch()์ ๋๋ฒ์งธ ์ธ์ condition์ ํ์
์ด ์์์ ๋ฐํํ์ ๋ํ๋ผ ๋ ์ฒ๋ผ ((Int) -> Bool) ๋ฐฉ์์ผ๋ก ๋์ด์์์ ์ ์ ์๋ค. ์ด๋ condition์ด Int๋ฅผ ์
๋ ฅ๋ฐ์ Bool์ ๋ฐํํ๋ ํจ์์ฌ์ผํ๋ค๋๊ฑธ ๋ํ๋ด๋๊ฒ. ์ฆ Int๋ฅผ ๋ฐ์ Bool์ ๋ฐํํ๋ ํจ์๋ฅผ condition์ผ๋ก ์ ๋ฌํ ์ ์๋ ๊ฒ์ด๋ค. ์์ ์์ ์์ ์ฒซ๋ฒ์งธ ์ถ๋ ฅ์ lessThanTen์ ์กฐ๊ฑด์ผ๋ก list์ ์ผ์นํ๋๊ฒ์ด ์๋๊ฐ๋ฅผ ์ถ๋ ฅํ ๊ฒ์ด๊ณ , ๋๋ฒ์งธ ์ถ๋ ฅ์ equalsTen()์ ์กฐ๊ฑด์ผ๋ก list์ ์ผ์นํ๋๊ฒ์ด ์๋๊ฐ๋ฅผ ์ถ๋ ฅํ ๊ฒ์ด๋ค.
Closure
var list2 = list.map{(number: Int) -> Int in
let result = 2 * number
return result
}
var list3 = list.map{number in 3 * number}
var list4 = list.map{4 * $0}
var list5 = list.sorted{$0 > $1}
var list6 = list.sorted{$0 < $1}
print(list2)
print(list3)
print(list4)
print(list5)
print(list6)
[42, 2, 22, 26, 30, 6, 38, 10, 14, 18, 34]
[63, 3, 33, 39, 45, 9, 57, 15, 21, 27, 51]
[84, 4, 44, 52, 60, 12, 76, 20, 28, 36, 68]
[21, 19, 17, 15, 13, 11, 9, 7, 5, 3, 1]
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21]
์ฌ์ค swift์์ ํจ์๋ ํน๋ณํ ํํ์ closure๋ค. ํจ์๊ฐ ์ต์ํ ์ฐ๋ฆฌ๋ ์ฝ๊ฒ ์ดํดํ๊ธฐ ์ํด์ ํจ์๋ช
์ด ์์ด ๊ฐ๋จํ๊ฒ ์ฌ์ฉํ๋ ํจ์๋ผ๊ณ ์๊ฐํ๋ฉด ๋จ. closure๋ฅผ ํตํด ๋ง์ ๋ถ๋ถ๋ค์ ์๋ตํ ์ ์๋๋ฐ, ๊ธฐ๋ณธ์ ์ผ๋ก ์ธ์์ ๋ฐํํ์ ์๋ตํ ์ ์๊ณ , statement์์ ์ฌ์ฉํ ๋ณ์๋ ๊ทธ๋ฅ ๊ฐ๋จํ๊ฒ $0, $1, $2 โฆ๋ก ์๋ต์ด ๊ฐ๋ฅํ๋ค.
Class, Instantiation
class shape{
var name = ""
var height = 0
var width = 0
init(height: Int, width: Int){
self.name = self.toString()
self.heightGetterSetter = height
self.widthGetterSetter = width
}
init(name: String, height: Int, width: Int){
self.name = name
self.heightGetterSetter = height
self.widthGetterSetter = width
}
var heightGetterSetter: Int{
get{
return self.height
}
set{
if newValue < 1{
print("height must higher than 0")
}
else{
self.height = newValue
}
}
}
var widthGetterSetter: Int{
get{
return self.width
}
set{
if newValue < 1{
print("width must longer than 0")
}
else{
self.width = newValue
}
}
}
deinit{
print("\(name) is deinited")
}
func toString() -> String{
return "Shape"
}
func area() -> Int{
return 0
}
func introduce(){
print("\(self.name)'s height is \(self.heightGetterSetter), and width is \(self.widthGetterSetter) and area is \(self.area())")
}
}
class square: shape{
override func toString() -> String{
return "Square"
}
override func area() -> Int{
return self.height * self.width
}
}
class triangle: shape{
override func toString() -> String{
return "Triangle"
}
override func area() -> Int{
return (self.height * self.width) / 2
}
}
let shape1 = square(height: 12, width: 8)
let shape2 = triangle(name: "Semo", height: 9, width: 14)
shape1.introduce()
shape2.introduce()
Squareโs height is 12, and width is 8 and area is 96
Semoโs height is 9, and width is 14 and area is 63
- ๋น์ฐํ๊ฒ๋ class์ ์์ฑ์๋ ์ฌ๋ฌ๋ฐฉ์์ผ๋ก ๊ตฌํํ ์ ์๋ค. ์ถ์ ํจ์๋ ๋ฐ๋ก ์กด์ ํ์ง ์๋๋ค.
override๋ฅผ ํตํด ํจ์์ ์ฌ ์ ์๊ฐ ๊ฐ๋ฅํ๋ค.:์ ํตํด class๊ฐ์ ์์์ด ๊ฐ๋ฅํ๋ค.- python์ฒ๋ผ
this๋์self๋ฅผ ์ฌ์ฉํ๋ค. - ์์ฑ์๋
init()์ผ๋ก, ์๋ฉธ์๋deinit()์ผ๋ก ์ฌ์ฉํ๋ค. ์๋ฉธ์์ ๊ฒฝ์ฐ ๋ช ์์ ์ผ๋ก ํธ์ถํ๋๊ฒ ์๋๋ผ reference count๊ฐ 0์ด๋๋ฉด ์๋์ผ๋ก ์ํ๋๋ค. - getter์ setter๋ ๋ฉค๋ฒ๋ณ์์ ์์ ๋ณ์๋ฅผ ์ ์ธํด closure์์์
get,set์ ํตํด์ ์ ์ธํ ์ ์๋ค. ํด๋น ๋ณ์๋ฅผ ํตํด ๊ฐ์ ๋ฐ๊พธ๊ฑฐ๋ ์ ์ดํ๋ฉดget,set์ ์ ์๋๋๋ก ์ํ๋๋ค.
Observer
class observerTest{
var name = ""{
didSet{
print("[didSet] name old value \(oldValue), currentValue \(self._name)")
}
willSet{
print("[willSet] name new value \(newValue), currentValue \(self._name)")
}
}
var age = 0 {
didSet{
print("[didSet] age old value \(oldValue), currentValue \(self._age)")
}
willSet{
print("[willSet] age new value \(newValue), currentValue \(self._age)")
}
}
init(name: String, age: Int){
self._age = age
self._name = name
}
var _name: String{
get{
return self.name
}
set{
self.name = newValue
}
}
var _age: Int{
get{
return self.age
}
set{
self.age = newValue
}
}
func toString(){
print("\(self._name) is age of \(self._age)")
}
}
var tester = observerTest(name: "seunghun", age: 23)
tester.toString()
print()
tester._age = 24
tester._name = "Seunghun Yang"
tester.toString()
[willSet] age new value 24, currentValue 23
[didSet] age old value 23, currentValue 24
[willSet] name new value Seunghun Yang, currentValue seunghun
[didSet] name old value seunghun, currentValue Seunghun Yang
Seunghun Yang is age of 24
Class, Instantiation์์ ๋ณธ getter, setter์ฒ๋ผ ๋ณ์์ closure๋ก didSet, willSet์ ์ฌ์ฉํด ํ์๋ฅผ ์ ์ํด์ฃผ๋ฉด observer๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์๋ค. observer๋ ๊ฐ์ ๋ณํ๊ฐ ๋ฐ์ํ๋ฉด ์ํ๋๋๋ฐ, didSet์ ๊ฐ์ด ๋ณํ ์งํ์, willSet์ ๊ฐ์ด ๋ณํ๊ธฐ ์ง์ ์ ์ํ๋๋ค.
Enum
print()
enum Rank: Int{
case ace = 1; //explicitly set Integer value of enum element
case two, three, four, five, six, seven, eight, nine, ten, jack, queen, king
func description() -> String{
switch self{
case .ace:
return "ace"
case .jack:
return "jack"
case .queen:
return "queen"
case .king:
return "king"
default:
return String(self.rawValue)
}
}
func isSpecial() -> String{
switch self{
case .ace, .jack, .queen, .king:
return "special"
default:
return "not special"
}
}
}
let card1 = Rank.three
print("\(card1.description()) and it is \(card1.isSpecial())")
if let card2 = Rank(rawValue: 11) { //rawValue is naive value of element in enum, it returns optional
print("\(card2.description()) and it is \(card2.isSpecial())")
}
else{
print("value is nil!!")
}
if let card3 = Rank(rawValue: 14){
print("\(card3.description()) and it is \(card3.isSpecial())")
}
else{
print("value is nil!!")
}
let card4: Rank? = Rank(rawValue: 12)
print("\(card4!.description()) and it is \(card4!.isSpecial())") //it may be nil and if it is, it occurs fatal error
3 and it is not special
jack and it is special
value is nil!!
queen and it is special
swift์์ ์ด๊ฑฐํ์ 0๋ถํฐ ์์ํ๋ค. ์์ ace์ ๊ฒฝ์ฐ์ฒ๋ผ ๋ช
์์ ์ผ๋ก 1๋ถํฐ ์์ํ๋๋ก ํด ์ค ์๋ ์๋ค. enum์ ์ธ์๋ก rawValue๋ฅผ ์ฃผ๋ฉด ๊ทธ ๊ฐ์ ํด๋นํ๋ ๊ฒ์ ์ป์ ์ ์๋ค. ์ด๋ nil์ผ ์๋ ์๊ธฐ ๋๋ฌธ์ optionalํ ๊ฐ์ด๋ค.
Value associated Enum
enum ServerResponse{
case onoffTime(Int, Int)
case serverFailed(String)
case broadCast(String)
func toString() -> String{
switch self{
case let .onoffTime(onTime, offTime):
return "server on at \(onTime) and it offs at \(offTime)"
case let .serverFailed(message):
return "server failed because of \(message)"
case let .broadCast(message):
return "[BroadCast] \(message)"
}
}
}
let serverMessage1 = ServerResponse.onoffTime(6, 23)
let serverMessage2 = ServerResponse.serverFailed("out of memory")
let serverMessage3 = ServerResponse.broadCast("Hello")
print(serverMessage1.toString())
print(serverMessage2.toString())
print(serverMessage3.toString())
server on at 6 and it offs at 23
server failed because of out of memory
[BroadCast] Hello
๊ฐ๊ณผ ์ฐ๊ด๋๋๋ก enum์ ์ ์ํด์ค ์ ์๋ค. ์ธ์์ ๋งค์นญ๋๋ ๊ฒ์ ์ํํ๋๋ก ์ฝ๋๋ฅผ ์งค ์ ์๋ค.
Struct
struct structTest{
var count = 0{
didSet{
print("changed from \(oldValue) to \(self.count)")
}
}
init(givenCount: Int){
self.count = givenCount
}
}
class classTest{
var count = 0{
didSet{
print("changed from \(oldValue) to \(self.count)")
}
}
init(givenCount: Int){
self.count = givenCount
}
}
//func incrementStruct(target: structTest){
// target.count += 1
//}
func incrementClass(target: classTest){
target.count += 1
}
var test1 = structTest(givenCount: 0)
var test2 = classTest(givenCount: 0)
//incrementStruct(target: test1)
incrementClass(target: test2)
changed from 0 to 1
struct๋ class์ ๋์ผํ๊ฒ ์์ฑ, ์ค์ ๋์ง๋ง ์ธ์๋ก ์ ๋ฌํ๋ ๊ฒ์์ ์ฐจ์ด๊ฐ ์๋ค. class๋ ์ฐธ์กฐ๋ฅผ ์ ๋ฌํ์ง๋ง struct๋ ๋ณต์ฌํ์ฌ ์ ๋ฌ๋๋ค(C++์์ ์์๋ณต์ฌ์ ์ ์ฌํจ). ์์ ์ฝ๋์์ class ๋ฅผ ์ ๋ฌ๋ฐ์ count๋ฅผ ์ฆ๊ฐ์ํจ๊ฒ์ด struct์๋ ๋ถ๊ฐ๋ฅํ๋ค.
Protocol
protocol animal{
var name: String{get set}
func speak()
}
class dog: animal{
var name: String = ""
init(givenName: String){
self.name = givenName;
}
func speak(){
print("\(self.name) : bark bark")
}
}
class cat: animal{
var name: String = ""
init(givenName: String){
self.name = givenName;
}
func speak(){
print("\(self.name) : meow")
}
}
var doggy = dog(givenName: "Peter")
var kitty = cat(givenName: "Tom")
doggy.speak()
kitty.speak()
Peter : bark bark
Tom : meow
protocol์ ์์๋ฐ์ ๊ตฌํ๋์ด์ผ ํ๋๊ฒ์ ์ด๊ฑฐํ๋ค. ์ผ์ข ์ ์ถ์ ํด๋์ค์ ๊ฐ๋ค๊ณ ์๊ฐํ๋ฉด ๋ ๊ฒ ๊ฐ๋ค . struct๋ class๊ฐ ๊ทธ๊ฑธ ์์๋ฐ์ protocol๋ก ๋ช ์๋๊ฑธ ๊ตฌํํ์ง ์์ผ๋ฉด ์๋ฌ๊ฐ ๋ฐ์ํ๋ค.
Extension
protocol speak{
func toString()
}
extension Int: speak{
func toString(){
print("I am \(self)")
}
}
extension dog: speak{
func toString(){
print("Hi, my name is \(self.name)")
}
}
var number = 3
number.toString()
5.toString()
doggy.toString()
I am 3
I am 5
Hi, my name is Peter
protocol์ ๋ง๋ค๊ณ extension์ ํตํด ๊ทธ๋ฅผ ํ์ฅํ ์ ์๋ค. ์์ ์์ ์์๋ Int์ dog๊ฐ speak๋ฅผ extensionํ์ฌ toString()ํจ์์ ๊ธฐ๋ฅ์ ๊ตฌํํ ๊ฒ์ด๋ค.
Protocol type variables
var doggyProtocol: animal = doggy
doggyProtocol.speak()
Peter : bark bark
protocol์ธ animal๊ฐ์ฒด doggyProtocol์ doggy๋ก ๋ณต์ฌ์์ฑํ๊ณ speak()๋ฅผ ํธ์ถํ๋ฉด extension์ผ๋ก ์ ์๋ speak()ํจ์๊ฐ ์๋ ์๋์ ํจ์๊ฐ ํธ์ถ๋๋ค.
Error Handling
enum errorList: Error{
case errorTwo
case errorThree
}
func errorChecker(inputNumber: Int) throws -> String{
if inputNumber % 2 != 0{
throw errorList.errorTwo
}
else if inputNumber % 3 != 0{
throw errorList.errorThree
}
return "your input handled normally"
}
do{
let errorCheck1 = try errorChecker(inputNumber: 6)
print(errorCheck1)
let errorCheck2 = try errorChecker(inputNumber: 133)
print(errorCheck2)
}
catch errorList.errorTwo{
print("errorTwo raised")
}
catch errorList.errorThree{
print("errorThree raised")
}
your input handled normally
errorTwo raised
Error๋ฅผ ์์๋ฐ๋ enum์ ๋ง๋ค์ด ์๋ฌ๋ฅผ ์ ์ํด์ค ์ ์๋ค. error๋ฅผ ๋ฐ์์ํค๋ ํจ์๋ Java์์์ฒ๋ผ throws๋ฅผ ํตํด ๋ช
์ํด์ค๋ค. ์๋ฌ๋ฅผ ๋ฐ์์ํฌ ๋ถ๋ถ์์ throw๋ฅผ ํตํด ์๋ฌ๋ฅผ ๋ฐ์์ํฌ ์ ์๋ค. ํด๋น ํจ์๊ฐ ์คํ๋์ด error๋ฅผ handlingํ ๋์๋ error๊ฐ ๋ฐ์ํ ์ ์๋ ์ฝ๋ ๊ตฌ๋ฌธ์ do๋ก ๊ฐ์ธ๊ณ ๊ทธ ์์์ ์๋ฌ๊ฐ ๋ฐ์ํ๋ ์ค์ try๋ฅผ ํตํด ์ฒ๋ฆฌํ๋ค. do ๋ฐ์์๋ catch๋ฅผ ํตํด ๊ฐ๊ฐ์ error์ ๋ํ ์ฒ๋ฆฌ๋ฅผ ์ ์ํด์ค ์ ์๋ค.
Deffer
func testingDeffer(){
print("first sentence")
defer{
print("last sentence")
}
print("second sentence")
print("third sentence")
}
testingDeffer()
first sentence
second sentence
third sentence
last sentence
deffer๋ฅผ ์ฌ์ฉํ๋ฉด ๊ทธ scope์์ชฝ์ ์ฝ๋๊ฐ ๋งจ ๋ง์ง๋ง์ ์ํ๋๋๊ฒ์ ๋ณด์ฅํ ์ ์๋ค. error๊ฐ ๋ฐ์ํ๋๋ผ๋ ๋ง์ง๋ง์ ์ํ๋๋ค.
Generic
func bulletBelt<Bullet>(bullet: Bullet, numberOfBullets: Int) -> [Bullet]{
var beltOfBullets = [Bullet]()
for _ in 0..<numberOfBullets{
beltOfBullets.append(bullet)
}
return beltOfBullets
}
func fireAllBullets<Bullet>(bulletBelt: [Bullet]){
for _ in 0..<bulletBelt.endIndex{
print("Bang!!")
}
}
var beltOfBullets = bulletBelt(bullet: "5.56mm", numberOfBullets: 15)
fireAllBullets(bulletBelt: beltOfBullets)
Bang!!
Bang!!
Bang!!
Bang!!
Bang!!
Bang!!
Bang!!
Bang!!
Bang!!
Bang!!
Bang!!
Bang!!
Bang!!
Bang!!
Bang!!
Java์ Generic, C++์ Template๊ณผ ๋์ผํ ๋ฐฉ์์ผ๋ก ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค.
Where
func commonElements<T: Sequence>(_ left: T,_ right: T) -> [T.Element] where T.Element: Equatable{
var found = [T.Element]()
for leftElement in left{
for rightElement in right{
if leftElement == rightElement{
found.append(leftElement)
print("found common element \(leftElement)")
}
}
}
return found
}
commonElements([1, 3, 5, 7, 9, 11, 13], [1, 1, 2, 3, 5, 8, 13])
print()
commonElements("strawberry", "tangerine")
found common element 1
found common element 1
found common element 3
found common element 5
found common element 13found common element t
found common element r
found common element a
found common element e
found common element e
found common element r
found common element r
where๋ฅผ ํตํด ์๊ตฌ์ฌํญ์ ์ถ๊ฐํ ์ ์๋ค. commonElement<T: Sequence>์์ : Sequence๋ถ๋ถ๋ ์๊ตฌ์ฌํญ ์ค ํ๋๋ก, ๋ค์ด์ฌ type์ธ T๊ฐ ์ฐ์์ ์ด๋ฉฐ ์ํ ๊ฐ๋ฅํ ๊ฒ์ด์ด์ผ ํ๋ค๋ ์๋ฏธ์ด๋ค. where๋ค์ ๋์ค๋ T.Element: Equatable์ T์ ์์๊ฐ ๋น๊ต๊ฐ๋ฅํด์ผํ๋ค๋ ์๋ฏธ์ด๋ค. ์ข
ํฉํด๋ณด๋ฉด T๋ ์ฐ์์ ์ด์ด์ผํ๊ณ , ๊ทธ ์์๋ค์ ๋น๊ต๊ฐ๋ฅํ ๊ฒ๋ค์ด์ด์ผ ํ๋ค๋ ๋ป์ด๋ค.
Comments