[Swift][공식문서 털기] - Sample Value, Control Flow, Functions and Closures, Objects and Classes

dongle·2022년 12월 24일

Sample Value

let상수 var를 만들고 변수를 만드는 데 사용 합니다.
상수의 값은 컴파일 타임에 알 필요가 없지만 값을 정확하게 한 번 할당해야 합니다.
상수를 사용한다면 한 번 그 값을 할당하지만, 여러 곳에서 사용하는 값의 이름을 지정할 수 있음을 의미합니다.

var myVariable = 42 // 변수 선언
myVariable = 50
let myConstant = 42 // 상수 선언

상수 또는 변수는 할당하려는 값과 유형이 같아야 합니다.
그러나 항상 형식을 명시적으로 작성할 필요는 없습니다.(상수나 변수를 만들 때 값을 제공하면 컴파일러에서 해당 유형을 유추하기 때문)
위의 예에서 컴파일러는 myVariable초기 값이 정수이기 때문에 정수라고 추론합니다.

초기 값이 충분한 정보를 제공하지 않는 경우(또는 초기 값이 없는 경우) 콜론으로 구분하여 변수 뒤에 작성하여 유형을 지정할 수 있습니다.

let explicitDouble: Double = 70

형변환

let label = "The width is "
let width = 94
let widthLabel = label + String(width)

String()으로 Int형인 width를 감싸 String형으로 변환시켜줌

문자열에 값을 포함하는 간단한 방법
괄호 안에 값을 쓰고 괄호 앞에 백슬래시( )사용

let apples = 3
let oranges = 5
let appleSummary = "I have \(apples) apples."
let fruitSummary = "I have \(apples + oranges) pieces of fruit."

여러 줄을 차지하는 문자열 에는 세 개의 큰따옴표( )를 사용

let quotation = """
I said "I have \(apples) apples."
And then I said "I have \(apples + oranges) pieces of fruit."
"""

괄호( )를 사용하여 배열과 사전을 만들고 괄호 안에 []인덱스 또는 키를 작성하여 해당 요소에 액세스합니다.
마지막 요소 뒤에 쉼표가능

var fruits = ["strawberries", "limes", "tangerines"]
fruits[1] = "grapes"

var occupations = [
    "Malcolm": "Captain",
    "Kaylee": "Mechanic",
]
occupations["Jayne"] = "Public Relations"

요소를 추가하면 배열이 자동으로 커집니다.

fruits.append("blueberries")
print(fruits)

빈 배열이나 사전을 만들려면 이니셜라이저 구문 사용

let emptyArray: [String] = []
let emptyDictionary: [String: Float] = [:]

유형 정보를 유추할 수 있는 경우 빈 배열을 로 [], 빈 딕셔너리를 로 작성가능 [:]
예를 들어 변수에 새 값을 설정하거나 함수에 인수를 전달할 때 사용

fruits = []
occupations = [:]

Control Flow

if 문이나 switch문을 사용해 조건을 만들고, for- in, while및 repeat- while를 사용하여 루프를 만듭니다.

let individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
    if score > 50 {
        teamScore += 3
    } else {
        teamScore += 1
    }
}
print(teamScore)
// Prints "11"

if명령문에서 조건은 bool 표현식이어야 합니다.

if let을 사용해 옵셔널 값(nil값)을 바인딩해 사용할 수 있음

var optionalString: String? = "Hello"
print(optionalString == nil)
// Prints "false"

var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
    greeting = "Hello, \(name)"
}

옵셔널 값이 nil인 경우 조건은 false이고 중괄호 안의 코드는 건너뜁니다. 그렇지 않은 경우엔 옵셔널 값이 언래핑되고 뒤에 상수에 할당되어 let언래핑된 값을 코드 블록 내에서 사용할 수 있습니다.

옵셔널 값을 처리하는 또 다른 방법은 연산자 ?? 를 사용하여 기본값을 제공하는 것 입니다. 선택적 값이 누락된 경우 기본값이 대신 사용됩니다.

let nickname: String? = nil
let fullName: String = "John Appleseed"
let informalGreeting = "Hi \(nickname ?? fullName)"

언래핑된 값에 동일한 이름을 사용하여 더 짧은 철자를 사용해 언래핑을 할 수 있음

if let nickname {
    print("Hey, \(nickname)")
}

Switch 는 모든 종류의 데이터와 다양한 비교 작업을 지원합니다.

let vegetable = "red pepper"
switch vegetable {
case "celery":
    print("Add some raisins and make ants on a log.")
case "cucumber", "watercress":
    print("That would make a good tea sandwich.")
case let x where x.hasSuffix("pepper"):
    print("Is it a spicy \(x)?")
default:
    print("Everything tastes good in soup.")
}
// Prints "Is it a spicy red pepper?"

일치하는 switch 케이스 내부의 코드를 실행한 후 프로그램은 switch 문을 종료합니다. 실행은 다음 케이스로 계속되지 않으므로 각 케이스의 코드 끝에서 스위치를 명시적으로 중단할 필요가 없습니다.(break 사용 안함)

각 키-값 쌍에 사용할 이름 쌍을 제공하여 사전의 항목을 반복 하려면 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
for (_, numbers) in interestingNumbers {
    for number in numbers {
        if number > largest {
            largest = number
        }
    }
}
print(largest)
// Prints "25"

while
조건이 변경될 때까지 코드 블록을 반복하는 데 사용합니다.
루프의 조건이 끝에 있을 수 있으므로 루프가 한 번 이상 실행가능하게 짜여집니다.

var n = 2
while n < 100 {
    n *= 2
}
print(n)
// Prints "128"

var m = 2
repeat {
    m *= 2
} while m < 100
print(m)
// Prints "128"

..<
인덱스 범위를 만들기 위해 ..<를 사용하여 루프에서 인덱스를 유지시킬 수 있습니다.

var total = 0
for i in 0..<4 {
    total += i
}
print(total)
// Prints "6"

Functions and Closures

func
함수를 선언하는 데 사용.
괄호 안의 인수 목록과 함께 이름 다음에 함수를 호출합니다.
->
함수의 반환 유형에서 매개변수 이름 및 유형을 구분하는 데 사용 합니다.

func greet(person: String, day: String) -> String {
    return "Hello \(person), today is \(day)."
}
greet(person: "Bob", day: "Tuesday")

기본적으로 함수는 매개변수 이름을 인수의 레이블로 사용합니다.
매개변수 이름 앞에 사용자 정의 인수 레이블을 작성하거나 _를 사용해 인수 레이블을 사용하지 않을 수도 있습니다.

func greet(_ person: String, on day: String) -> String {
    return "Hello \(person), today is \(day)."
}
greet("John", on: "Wednesday")

튜플
복합 값을 만듭니다.
함수로부터 여러 값을 반환합니다. 튜플의 요소는 이름이나 번호로 참조할 수 있습니다.

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.sum)
// Prints "120"
print(statistics.2)
// Prints "120"

함수는 중첩될 수 있습니다.
중첩된 함수는 외부 함수에서 선언된 변수에 액세스할 수 있으며, 중첩 함수를 사용하여 길거나 복잡한 함수의 코드를 구성할 수 있습니다.

func returnFifteen() -> Int {
    var y = 10
    func add() {
        y += 5
    }
    add()
    return y
}
returnFifteen()

함수는 일급 유형(객체)입니다.
이는 함수가 다른 함수를 값으로 반환할 수 있음을 의미합니다.

func makeIncrementer() -> ((Int) -> Int) {
    func addOne(number: Int) -> Int {
        return 1 + number
    }
    return addOne
}
var increment = makeIncrementer()
increment(7)

함수는 인수로 다른 함수를 사용할 수 있습니다.

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]
hasAnyMatches(list: numbers, condition: lessThanTen)

함수는 클로저의 특별한 케이스라고 볼 수 있습니다.
나중에 호출할 수 있는 코드 블록으로 클로저의 코드는 클로저가 실행될 때 다른 범위에 있더라도 클로저가 생성된 범위에서 사용할 수 있는 변수 및 함수와 같은 것에 사용할 수 있습니다.

numbers.map({ (number: Int) -> Int in
    let result = 3 * number
    return result
})

클로저의 타입을 이미 알고있다면 매개변수의 유형, 반환 유형 또는 둘 다 생략할 수 있습니다.

let mappedNumbers = numbers.map({ number in 3 * number })
print(mappedNumbers)
// Prints "[60, 57, 21, 36]"

이름 대신 번호로 매개변수를 참조할 수 있습니다.
이 접근 방식은 매우 짧은 클로저에서 유용합니다.
함수의 마지막 인수로 전달된 클로저는 괄호 바로 뒤에 나타날 수 있습니다.
클로저가 함수의 유일한 인수인 경우 괄호를 완전히 생략할 수 있습니다.

let sortedNumbers = numbers.sorted { $0 > $1 }
print(sortedNumbers)
// Prints "[20, 19, 12, 7]"

Objects and Classes

클래스를 만들려면 class 뒤에 만들고자 하는 클래스 이름을 적어줍니다.

클래스의 속성 선언은 클래스 컨텍스트에 있다는 점을 제외하면 상수 또는 변수 선언과 동일한 방식으로 작성됩니다.

마찬가지로 메서드 및 함수 선언도 같은 방식으로 작성됩니다.

class Shape {
    var numberOfSides = 0
    func simpleDescription() -> String {
        return "A shape with \(numberOfSides) sides."
    }
}

클래스 이름 뒤에 괄호를 넣어 클래스의 인스턴스를 만듭니다. 점(.) 구문을 사용하여 인스턴스의 속성 및 메서드에 액세스할 수 있습니다.

var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()

인스턴스가 생성될 때 클래스를 설정하는 초기화 하는 부분이 없는 프로그램으로 init을 사용해 하나 만들어 줍니다.

class NamedShape {
    var numberOfSides: Int = 0
    var name: String

    init(name: String) {
        self.name = name
    }

    func simpleDescription() -> String {
        return "A shape with \(numberOfSides) sides."
    }
}

init 대한 인수는 클래스의 인스턴스를 만들 때 함수 호출처럼 전달됩니다. 모든 속성에는 선언( with 와 같이 ) 또는 이니셜라이저( with 와 같이) 에 할당된 값이 필요합니다

deinit
개체 할당이 취소되기 전에 일부 정리를 수행해야 하는 경우 초기화 해제를 만드는 데 사용 합니다.

하위 클래스에는 클래스 이름 뒤에 콜론으로 구분된 수퍼 클래스 이름이 포함됩니다. 클래스가 표준 루트 클래스를 서브클래싱할 필요가 없으므로 필요에 따라 슈퍼클래스를 포함하거나 생략할 수 있습니다.

슈퍼클래스의 구현을 재정의하는 하위 클래스의 메서드는 로 표시 override됩니다.

실수로 메서드를 재정의하는 override를 하게 되면 컴파일러에서 오류로 감지됩니다.

class Square: NamedShape {
    var sideLength: Double

    init(sideLength: Double, name: String) {
        self.sideLength = sideLength
        super.init(name: name)
        numberOfSides = 4
    }

    func area() -> Double {
        return sideLength * sideLength
    }

    override func simpleDescription() -> String {
        return "A square with sides of length \(sideLength)."
    }
}
let test = Square(sideLength: 5.2, name: "my test square")
test.area()
test.simpleDescription()

저장된 단순 속성 외에도 속성에는 getter 및 setter가 있을 수 있습니다.

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 "An equilateral triangle with sides of length \(sideLength)."
    }
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
print(triangle.perimeter)
// Prints "9.3"
triangle.perimeter = 9.9
print(triangle.sideLength)
// Prints "3.3000000000000003"

setter perimeter에서 새 값은 암시적 이름인 newValue를 가집니다.
set 뒤 괄호 안에 명시적인 이름을 줄수 있습니다.

클래스 의 이니셜라이저 EquilateralTriangle에는 세 가지 단계가 있습니다.

1.하위 클래스가 선언하는 속성 값을 설정하기
2. 슈퍼클래스의 이니셜라이저를 호출하기
3. 슈퍼클래스에 의해 정의된 속성의 값을 변경하기(메서드, 게터 또는 세터를 사용하는 추가 설정 작업도 이 시점에서 수행할 수 있음)

새 값을 설정하기 전과 후에 실행되는 코드를 제공해야 하는 경우 willSet및 didSet을 사용합니다.

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 test shape")
print(triangleAndSquare.square.sideLength)
// Prints "10.0"
print(triangleAndSquare.triangle.sideLength)
// Prints "10.0"
triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
print(triangleAndSquare.triangle.sideLength)
// Prints "50.0"

옵셔널 값으로 작업할 때 메서드, 속성 및 첨자와 같은 작업 전에 작성할 수 있습니다. 앞의 값?이 nil이면 뒤의 모든 값은 무시되고 전체 표현식의 값은 nil이 됩니다.

그렇지 않으면 선택적 값이 언래핑되고 언래핑된 값에 따라 작동하는 모든 항목이 풀리게 됩니다.
두 경우 모두 전체 표현식의 값은 옵셔널 값입니다.

let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
let sideLength = optionalSquare?.sideLength
profile
개발자를 꿈꾸는 학생입니다!

0개의 댓글