Contents
- Swift Brief Introduction
- The Basic Values
- Operators
- Control Flow
- Function & Closures
- Class & Structure
- Properties
- Method
- Inheritance
- Initialization
Introduction to Swift
- Apple’s code: objective-C -> swift (2014)
- compiled language
- LLVM compiler
- IDE(Integrated Development Environment) : Xcode (2003)
- Package: UIKit, SwiftUI
Basic Values
type safe language
- 변수의 type을 명시해야함. 변수에 명시된 type 외의 값을 넣을 수 없음. 단, swift는 type inference를 지원하기때문에 C언어처럼 모든 변수에 type을 선언할 필요는 없음. Compile 과정에서 swift가 변수에 할당된 값을 보고 type을 유추하기 때문.
variable
- syntax
var
- naming convention
- lower camel case (ex.
thisIsAnExample
)
- lower camel case (ex.
- usage
- 변수의 값(value)이 변경되는 경우 사용
- constant의 type(ex.
Double
)과 value의 type(ex.70
)이 일치 해야 함
constant
- syntax
let
- usage
- 변수의 값(value)가 변하지 않을 경우 사용. 즉, 고정된 하나의 값이 프로그램 내에 반복적으로 사용될 때 필요함.
- constant의 type(ex.
Double
)과 value의 type(ex.70
)이 일치 해야 함 (굳이 type을 정의하지 않아도 컴파일러가 value의 type을 보고 constant의 타입을 지정함=>Type Inference
)
let implicitDouble = 70.0
let explicitDouble: Double = 70
types
Int, Float, Double
var implicitDouble = 70.0
let explicitDouble: Double = 70
String
- syntax
- string 내부에서 변수 사용
"\(variable)"
- multiple lines
"""string"""
- string 내부에서 변수 사용
var apple:Int = 1
var orange:Int = 3
print("I have \(apple) apples and \(orange) oranges")
// I have 1 apples and 3 oranges
Bool
Array & Dictionary
- syntax
[]
- array
var shoppingList = ["water","snack"] shoppingList.append("orange") // list append
- dictionary
var occupations = [ "Christina" : "programmer", "Daewang" : "puppy" ] occupations["Zooho"] = "data scientist" print(occupations) // ["Daewang": "puppy", "Zooho": "data scientist", "Christina": "programmer"]
tuples
- syntax
()
- usage
- 여러 값들을 그룹에 담을 때 사용함. 서로 다른 타입의 값도 같은 tuple로 묶일 수 있음.
let httpStatus = (statusCode:200, description: "okay")
print("status code is \(httpStatus.statusCode) and messgae is \(httpStatus.description)}")
Initializer
- initializer
- int, float, double, string
- 값을 할당해 initialize
- ex:
var x = 1
- ex:
- type 할당을 먼저한 후 값을 지정하여 initialize
- ex:
var x: Int; x = 1
- ex:
- 값을 할당해 initialize
- list :
[]()
- dictionary :
[:]()
- int, float, double, string
// dictionary
var emptyDictionary = [String : Float]()
emptyDictionary["name"] = 1
print(emptyDictionary)
// ["name": 1.0]
// list
var tempt = [Any]()
tempt.append("a")
tempt.append(1)
print(tempt)
// ["a", 1]
Optionals
- definition
- 값(value)이 있을 수도 없을 수도 있는 타입. C 언어에서는 없었던 개념으로 swift만의 강점이라고 할 수 있음.
- 값이 있는 경우는 optional을 풀어서 값을 얻음.
- 값이 없는 경우는
nil
(=값이 없음)을 얻음.
- syntax
String?
- initialize
- optional에 값을 할당하지 않고 initialize한 경우 초깃값은
nil
로 세팅됨.var testNil : Int?
- optinal에 초깃값을 할당
var test: Int? = Int(8)
- optional에 값을 할당하지 않고 initialize한 경우 초깃값은
forced unwrapping
- optional에 값이 확실히 존재할 때, 그 값을 가져오는 방법을 forced unwrapping이라고 함.
- syntax
- optional 변수명 뒤에 느낌표
!
를 붙이면 optional의 값만 가져옴.- ex.
test!
- ex.
- optional 변수명 뒤에 느낌표
optional binding
- optional에 값 존재 여부에 따라 분기문을 이용해 다르게 처리하는 방법.
- syntax
if let constantName = someOptional { statement } else {statement}
- [주의]
constantName
변수는 if문 내에서만 사용 가능.
let possibleNumber = "123"
if let actualNumber = Int(possibleNumber) {
print(print("The string \"\(possibleNumber)\" has an integer value of \(actualNumber)"))
}else{
print("The string \"\(possibleNumber)\" couldn't be converted to an integer")
}
// "The string "123" has an integer value of 123"
nil-coalescing Operator
- optional에 값이 존재하지 않을 때 (=nil), nil 대신 부여할 값을 지정하는 연산자
- syntax
someOptional ?? substituteValue
let optionalInt: Int?
print(optionalInt)
// nil
if let number = optionalInt {
print("value is assgined!")
}
// (nothing printed)
let number: Int? = Int("42")
print(number)
// Optional(42)
print("upwrap the number : \(number!)")
// 42
let defaultValue = "default"
let outputOptional = optionalInt ?? defaultValue
print(outputOptional)
// default
Implicitly Unwrapped Optionals
- definition
- 항상 값이 존재하는 optional.
- optional과 같은 타입이지만, 값이 존재하는지 확인하는 과정을 건너뛸 수 있다는 점에서 optional과 다름. 즉, 항상 forced-upwrapping(
!
)을 할 수 있는 optional.
- syntax
String!
let assumedString : String! = "implicitly unwrapped optional string"
let optionalString = assumedString
let implicitString: String = assumedString // implicitString가 타입을 String으로 명시했기 때문에 assumedString(implicitly unwrapped optinal)가 값을 forced-upwrapping한 후 변수에 할당함
print(optionalString)
// Optional("implicitly unwrapped optional string") // 여전히 optinal 타입
print(implicitString)
// implicitly unwrapped optional string
Operators
ternary conditional operator
- syntax
question ? answer1 : answer2
- definition
- ternary operator란 피연산자(operands)를 3개 갖는 연산자를 의미함.
(unary=> 1개, binary=>2개, ternary=>3개) if question; then answer1 else; answer2; fi
조건문을 한 줄로 처리할 수 있는 연산자.
- ternary operator란 피연산자(operands)를 3개 갖는 연산자를 의미함.
- example
let contentHeight = 40 let hasHeader = true let rowHeight = contentHeight + (hasHeader ? 50 : 20) // if hasHeader is true; return 50; else 20 print(rowHeight) // 90
nil-coalescing operator
- syntax
a ?? b
- definition
- 만약 optional 변수의 값이 존재하면 (!= nil) 그 값을 반환하고 그렇지 않으면 nil 대신 다른 값을 반환하는 연산자.
a != nil ? a! : b
코드를 처리함.
- example
let defaultColorName = "red" var userDefindedColorName: String? // default is nil var colorNameToUse = userDefindedColorName ?? defaultColorName print(colorNameToUse) // red userDefindedColorName = "green" // optionalString에 string 값을 할당함 colorNameToUse = userDefindedColorName ?? defaultColorName print(colorNameToUse) // green
range operator
- syntax
- closed:
1...5
- 1 이상, 5 이하
- half-opened:
1..<5
- 1 이상, 5 미만
- 파이썬의
range(1,5)
와 동일
- one-sided:
1...
- 1 이상의 모든 값
- 시작 값이 없는 경우 (ex.
...100
)는 iteration이 불가능 - 끝 값이 없는 경우 (ex.
2...
)는 iteration이 가능함
- closed:
- example
let names = ["Anna","Alex", "Brian", "Jack"]
let numberOfPeople = names.count
for i in 0..<numberOfPeople {
print("Person \(i+1) is called \(names[i])")
}
//Person 1 is called Anna
//Person 2 is called Alex
//Person 3 is called Brian
//Person 4 is called Jack
for name in names[2...]{
print(name)
}
//Brian
//Jack
let oneSideRange = ...5
print(oneSideRange.contains(7))
// false
Control Flow
template
- syntax
aaa
- definition
- aaa
- example
aaa
conditional
- if
let individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
if score > 50 {
teamScore += 3
} else {
teamScore += 1
}
}
print(teamScore)
//11
- switch
let x where [condition]
구문은 Python의x if lambda x : [condition] else False
와 같다. 즉,vegetable
변수가 특정 condition을 만족하면 다음 코드를 실행하도록 제어한다.
let vegetable = "red pepper"
switch vegetable {
case "celery":
print("throw it away")
case "cucumber", "watercress":
print("make a sandwitch")
case let x where x.hasSuffix("pepper"): // assign value to x if value has "pepper" at the back
print("Is it a spicy \(x)?")
default:
"everything goes well with soup."
}
// Is it a spicy red pepper?
loops
- for-in
let interestingNumbers = [
"Prime" : [2,3,5,7,11,13],
"Fibonacci" : [1,1,2,3,5,8],
"Square" : [1,4,9,16,25]
]
var largest = 0
var largestKeys : String?
for (key, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number
largestKeys = key
}
}
}
print("largest number : \(largest) in key : \(largestKeys)")
//largest number : 25 in key : Optional("Square")
- while
var n = 2
while n < 100 {
n *= 2
}
print(n)
// 128
- repeat-while
- 반복을 최소 1번은 이루어진다는 가정 하에 반복문이 조건문보다 앞에 나올 수 있다.
var m = 2
repeat {
m *= 2
} while m < 100
print(m)
// 128
..<
&...
a..<b
- Python의 range(a,b)와 동일하다. 즉, a 이상, b 미만의 수를 생성한다.
a...b
- Python의 range(a,b+1)과 동일하다. 즉, a 이상, b 이하의 수를 생성한다.
var total = 0
for i in 0..<4 {
total += i
}
print(total)
// 6
total = 0
for i in 0...4{
total += i
}
print(total)
// 10
Functions & Closures
functions
parameters
- keyword argument
func function_name(parameter_name : type)
- ex.
func greet(person: String, day: String) -> String
- no argument label
func function_name(_ parameter_name : type)
- ex.
func menu(_ person: String) -> String
- customized argument label
func function_name(customized_label parameter_name : type)
- ex.
func menu(lunch meal: String) -> String
func greet(person: String, day: String) -> String {
return "Hello \(person), today is \(day)."
}
print(greet(person: "Christina", day: "Sunday"))
// Hello Christina, today is Sunday.
func menu(_ person: String, lunch meal: String) -> String {
return "Hello \(person), today's meal is \(meal)."
}
print(menu("Chris", lunch: "salad"))
// Hello Chris, today's meal is salad.
returned values
- 함수의 반환값이 여러개 인 경우 (multiple values), tuple로 반환한다.
- 반환된 tuple 값은 변수명이나 변수의 인덱스로 얻을 수 있다.
func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
var min = scores[0]
var max = scores[0]
var sum = 0
for score in scores {
if score > max {
max = score
} else if score < min {
min = score
}
sum += score
}
return (min, max, sum)
}
let statistics = calculateStatistics(scores: [5,3,100,3,9])
print(statistics.min)
// 3
print(statistics.0)
// 3
nested functions
-
함수는 first-class type이다. first-class type이란 다른 함수의 argument로 입력될 수 있고, 다른 함수에서 반환될 수 있는 타입을 말한다.
-
함수가 다른 함수의 arguments로 입력되는 경우
func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {
for item in list {
if condition(item) {
return true
}
}
return false
}
func lessThanTen(number: Int) -> Bool {
return number < 10
}
var numbers = [20,19,7,12]
print(hasAnyMatches(list: numbers, condition: lessThanTen))
//true
- 함수가 다른 함수에서 반환되는 경우
- 함수의 반환값이
(Int) -> Int
라면, 이 함수는 다른 함수를 반환하는 함수이다.
- 함수의 반환값이
func makeIncrementer() -> ((Int) -> Int) {
func addOne(number: Int) -> Int {
return 1 + number
}
return addOne
}
var increment = makeIncrementer()
print(increment(7)) // increment 변수는 곧 addOne 함수
// 8
closure
- 함수는 closure이다.
- closure 설명 추가…
{}
- 함수명이 없는 closure 함수 생성
var numbers = [20,19,7,12]
let oddNumbers = numbers.map({ (number: Int) -> Int in
if number % 2 == 1 {
return 0
} else {
return number
}
})
print(oddNumbers)
//[20, 0, 0, 12]
// simple closure(No parameter type, return type, and return statement) when closure has a single statement
let mappedNumbers = numbers.map({ number in 3 * number
})
print(mappedNumbers)
// [60, 57, 21, 36]
// simple closure using parameter index
let ascendingNumbers = numbers.sorted{ $0 < $1 }
print(ascendingNumbers)
// [7, 12, 19, 20]
Object and Classes
property
- property에 value assigning 방법
- declaration: class 내부에서 값을 할당 (ex.
numberOfSides
) - initializer : initializer로 값을 할당. initializer 내부에서는 property 앞에
self
를 붙여 arguement 변수와 구분해줌 (ex.self.name
)
- declaration: class 내부에서 값을 할당 (ex.
class NamedShape {
var numberOfSides: Int = 0
var name: String // require initializer
init(name: String) { // initializer
self.name = name
}
func simpleDescription() -> String { // method
return "A shape with \(numberOfSides) sides."
}
}
var namedShape = NamedShape(name: "Triangle") // instance
namedShape.numberOfSides = 3
print(namedShape.simpleDescription())
// A shape with 3 sides.
superclass and subclass
- overriding
- initializer :
super.init()
- method :
override func
- initializer :
class Square: NamedShape {
var sideLength: Double
init(sideLength: Double, name: String){
self.sideLength = sideLength
super.init(name: name) // overrid initializer
numberOfSides = 4
}
func area() -> Double {
return sideLength * sideLength
}
override func simpleDescription() -> String { // override method
return "A square with sides of length \(sideLength)"
}
}
let test = Square(sideLength: 5.2, name: "my test square")
print(test.area())
// A shape triangle with 3 sides.
print(test.simpleDescription())
// A shape with 3 sides.
getter and setter
- property에 계산의 결과값을 할당하고 싶을 때, getter와 setter를 사용한다.
- setter
- property(ex.
perimeter
)에 값이 할당되면 이 값은newValue
라는 변수에 할당된다.
- property(ex.
class EquilateralTriangle: NamedShape {
var sideLength: Double = 0.0
init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name)
numberOfSides = 3
}
var perimeter: Double {
get {
return 3.0 * sideLength
}
set {
sideLength = newValue / 3.0
}
}
override func simpleDescription() -> String {
return "A equilateral triangle with sides of length \(sideLength)"
}
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
print(triangle.perimeter)
// 9.3
triangle.perimeter = 9.9
print(triangle.sideLength)
// 3.3
- property에 계산한 값을 반환할 필요는 없지만, property에 값을 할당하기 전과 후의 값이 모두 필요할 때
willSet
과didSet
을 사용한다. willSet
과didSet
은 instance의 property 값이 변경되는 순간에 작동한다.
// willSet을 사용해 triangle과 square의 sideLength가 항상 일치시키기
class TriangleAndSquare {
var triangle: EquilateralTriangle {
willSet {
square.sideLength = newValue.sideLength
}
}
var square: Square {
willSet {
triangle.sideLength = newValue.sideLength
}
}
init(size: Double, name: String){
square = Square(sideLength: size, name: name)
triangle = EquilateralTriangle(sideLength: size, name: name)
}
}
var triangleAndSquare = TriangleAndSquare(size: 10, name: "another teset shape")
print(triangleAndSquare.square.sideLength)
// 10
print(triangleAndSquare.triangle.sideLength)
// 10
triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
print(triangleAndSquare.triangle.sideLength)
// 50