옵셔널 체이닝(Optional Chaining)

자바스크립트에서 객체의 속성 접근을 더 안전하게 하는 방법

이 기능을 사용하면 객체의 속성이 존재하지 않을 때 발생하는 오류를 방지할 수 있음

// 옵셔널 문자열을 선언하고 "Hi"로 초기화합니다.
var x: String? = "Hi" // x는 옵셔널이므로 nil일 수 있습니다.

// x의 값을 출력합니다. x!는 강제로 언래핑하여 nil이 아닐 경우 값을 가져옵니다.
print(x, x!) // 출력: Optional("Hi") Hi (옵셔널 x의 값과 강제로 언래핑한 값)

// if-let 구문을 사용하여 x가 nil이 아닐 경우에만 a에 값을 할당합니다.
if let a = x {
    print(a) // 출력: Hi (x가 nil이 아닐 경우, a의 값을 출력합니다.)
}

// 강제로 언래핑하여 x의 문자 개수를 가져옵니다. x가 nil이면 런타임 오류가 발생합니다.
let b = x!.count // x가 nil이 아니므로, x의 문자 개수를 가져옵니다.
print(type(of: b), b) // 출력: Int 2 (b의 타입과 값을 출력합니다. Hi의 길이는 2)

// 옵셔널 체이닝을 사용하여 x의 문자 개수를 가져옵니다. x가 nil이면 nil이 반환됩니다.
let b1 = x?.count // x가 nil인 경우, b1은 nil이 됩니다.
print(type(of: b1), b1, b1!) // 출력: Optional<Int> Optional(2) 2 (b1의 타입과 값을 출력합니다. b1은 nil이 아니므로 강제로 언래핑 가능)

// nil 병합 연산자를 사용하여 x가 nil일 경우 빈 문자열을 할당합니다.
let c = x ?? "" // x가 nil이면 c는 빈 문자열이 됩니다.
print(c) // 출력: Hi (x가 nil이 아니므로 c는 x의 값을 그대로 사용)

?.해서 일반적임
근데 print할때는 !로 풀어줘야됨

 

var x : int //선언문
x=10//실행문
var x : int? //선언문
var x : int! //선언문
//공통점: 둘다 옵셔널 형임, 선언문에서 자료형 다음에 ?! 찍을 수 있음  
//!는 자동으로 언래핑함, 일반적으로는 ?를 사용함 

var x : int! = 10
실행문에 !는 변수 뒤에 씀 ex) x!

//실행문에서의 x?란
//풀긴풀되, 조심해서 푼다
//최종적인 값을 한번 더 풀어서 써야한다는 단점

//옵셔널 체인일때
.count같은

//!는 옵셔널을 푸는것
//?는 옵셔널을 풀긴하지만 조심스럽게 푸는 것

//--------------------------
// 정수형 변수 x 선언
var x: Int // 선언문

// x에 10을 할당
x = 10 // 실행문

// 옵셔널 정수형 변수 x 선언 (값이 nil일 수 있음)
var x: Int? // 선언문

// 암시적 언래핑 옵셔널 변수 x 선언 (nil이 아닐 것이라 가정)
var x: Int! // 선언문

// 공통점: 두 변수 모두 옵셔널 형식임
// 선언문에서 자료형 다음에 ? 또는 !를 사용할 수 있음

// 암시적 언래핑 옵셔널 변수 x에 10을 할당
var x: Int! = 10

// 실행문에서 !는 변수 뒤에 사용하여 값을 언래핑함
// 예시: x!

// 실행문에서 x?는 옵셔널 값을 풀긴 하지만 조심스럽게 다루어야 함
// 이 경우, 최종적인 값을 한번 더 풀어서 사용해야 함

// 옵셔널 체인 사용 예시
// 예: x?.count (x가 nil이 아닐 때만 count를 호출)

// !는 옵셔널을 강제로 언래핑함
// ?는 옵셔널을 안전하게 풀지만 nil인 경우 처리해야 함
class Person {
    var name: String
    var age: Int
    
    // 초기화 메서드
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

// Person 객체 kim 생성
let kim: Person = Person(name: "Kim", age: 20)
print(kim.age) // kim의 나이 출력

// 옵셔널 Person 객체 han 생성
let han: Person? = Person(name: "Han", age: 25) // 옵셔널 Person

// han의 나이를 출력할 때 옵셔널을 강제로 언래핑해야 함
print(han!.age) // han이 nil이 아닐 경우, 나이를 출력 (강제 언래핑)
//옵셔널이기 때문에 !로 풀어줘야됨 안하면 error/ ?는 옵쳐널 체이닝 이경우 또 한번 아래에 풀어줘야됨
//print((han?.age)!) 또는 아래 if처럼 풀어줌


// 옵셔널 체이닝을 사용할 경우
// print(han?.age) // Optional(25), han이 nil일 경우 nil 반환

// 옵셔널 체이닝 후 강제 언래핑
print((han?.age)!) // han이 nil이 아닐 경우, 나이를 출력

// 옵셔널 바인딩을 사용하여 안전하게 언래핑
if let hanAge = han?.age {
    print(hanAge) // han이 nil이 아닐 경우, hanAge 출력
} else {
    print("nil") // han이 nil일 경우 "nil" 출력
}

6주차 9p X

 

// 옵셔널 체이닝: 점 앞에 ? 사용
class Company {
    var ceo: Person? // 회사의 CEO는 Person 타입이지만, nil일 수도 있음
}

class Person {
    var name: String // 사람의 이름을 저장하는 변수
    
    // 초기화 메서드
    init(name: String) {
        self.name = name // 주어진 이름으로 초기화
    }
}

// Company 객체 apple 생성
let apple = Company()

// apple의 CEO를 Person 객체로 설정
apple.ceo = Person(name: "Kim") // Kim이라는 이름의 CEO를 설정

// 다음은 오류가 발생함
// print(apple.ceo.name) // apple.ceo가 nil일 수도 있기 때문에 오류 발생

// 옵셔널 체이닝 없이 CEO의 이름을 안전하게 가져오는 방법
if let ceo = apple.ceo { // apple.ceo가 nil이 아닐 경우
    print(ceo.name) // CEO의 이름을 출력 (이 경우 "Kim")
}

// 강제 언래핑을 사용하여 CEO의 이름을 가져옴
print(apple.ceo!.name) // "Kim"을 출력 (apple.ceo가 nil이 아닐 것이라 가정)

// 옵셔널 체이닝을 사용하여 CEO의 이름을 가져옴
print(apple.ceo?.name) // "Optional("Kim")"을 출력 (옵셔널로 감싸져 있음)

// 옵셔널 체이닝을 사용하여 CEO의 이름을 안전하게 가져오는 방법
if let name = apple.ceo?.name { // apple.ceo가 nil이 아닐 경우
    print(name) // "Kim"을 출력
}

// 옵셔널 체이닝과 nil 병합 연산자를 사용
print(apple.ceo?.name ?? "CEO가 없습니다") // "Kim"을 출력 (apple.ceo가 nil일 경우 "CEO가 없습니다" 출력)

 

옵셔널 체이닝 장점

안전성: 옵셔널 체이닝을 사용하면, 객체가 nil인지 확인하면서 안전하게 값을 가져올 수 있습니다. 따라서 런타임 오류를 예방할 수 있습니다.

코드 간결성: 옵셔널 체이닝을 사용하면 코드가 더 간결해집니다. if let 구문 없이도 간단하게 값을 가져올 수 있습니다.

 

조건부 실행: 옵셔널 체이닝을 사용하면, 체인이 끊어지는 순간 nil을 반환하므로, 조건에 따라 다음 메서드나 프로퍼티를 안전하게 호출할 수 있습니다.

 

단점

옵셔널 값으로 반환: 옵셔널 체이닝을 사용하면 결과가 항상 옵셔널로 반환되기 때문에, 이를 사용하려면 다시 언래핑해야 합니다. 즉, if let 또는 !를 사용하여 값을 풀어줘야 합니다.

 

가독성 저하: 여러 개의 옵셔널 체이닝이 중첩될 경우, 코드의 가독성이 떨어질 수 있습니다. 이런 경우, 어떤 부분이 nil인지 추적하기 어려워질 수 있습니다.

 

강제 언래핑의 위험: !를 사용하여 강제로 언래핑할 경우, nil인 경우 런타임 오류가 발생할 수 있어 주의가 필요합니다.

 

?과 !이 실행문일 때, 선언문일 때 뭐가 다른지 표로 정리해줘

예외처리를 하고 싶을때 try?나 try!를 사용,

?를 쓰게 되면 리턴 값이 옵셔널로 나옴, 에러를 간단히 무시하거나 실패 여부만 확인하고 싶을때

!는 에러가 절대 발생하지 않을 것이라고 가정할떄, 만약 에러가 발생하면 프로그램이 크래시( 보통 사용안함)

 

 

throws 키워드

사용 방법: 함수의 매개변수나 반환값에 throws 키워드가 붙어 있으면, 해당 함수는 오류를 발생시킬 수 있다는 의미입니다.
특징: throws가 있는 함수는 반드시 try, try?, 또는 try!로 호출해야 하며, 예외 처리를 해주어야 합니다.

throws 키워드가 있으면 반드시 예외 처리해야됨

 

그냥 호출 안되고 앞에는 try를 써주고 앞 뒤에 do ~try ~catch를 써줌

예외가 발생할 수 있는 코드는 do 블록 안에 작성합니다.
try를 사용하여 함수를 호출하고, 오류가 발생하면 catch 블록에서 처리합니다.
이 구조를 통해 프로그램이 중단되지 않고 오류를 안전하게 처리할 수 있습니다.

 

*

오버로딩: 같은 이름의 함수가 여러 개 존재하며, 매개변수의 타입이나 개수로 구분됩니다.
중첩: 함수 안에 다른 함수를 정의하여 사용할 수 있으며, 중첩된 함수는 외부 함수의 범위 내에서만 호출 가능합니다.

 

 

Generic<>

소괄호 (): 함수 호출, 수학적 표현의 우선순위 지정.
대괄호 []: 배열, 리스트, 인덱스 접근.
중괄호 {}: 코드 블록 정의.
꺾쇠 괄호 <>: 제네릭 타입 정의, HTML 태그 등.

 

// 제네릭 함수를 정의합니다. T는 어떤 타입이든 될 수 있습니다.
func myPrint<T>(a: T, b: T) {
    // b와 a를 출력합니다. 매개변수의 순서를 바꿉니다.
    print(b, a)
}

// 정수 타입의 인수를 사용하여 함수 호출
myPrint(a: 1, b: 2) // 출력: 2 1

// 실수 타입의 인수를 사용하여 함수 호출
myPrint(a: 2.5, b: 3.5) // 출력: 3.5 2.5

// 문자열 타입의 인수를 사용하여 함수 호출
myPrint(a: "Hi", b: "Hello") // 출력: Hello Hi

 

 

빈배열 만들기 3가지 방법

// 방법 1: 타입과 함께 빈 배열을 선언합니다.
// 'x'는 Int 타입의 빈 배열입니다.
var x: [Int] = [] // 빈 배열 생성

// 방법 2: 타입을 명시하지 않고 배열을 생성합니다.
// 'y'는 Int 타입의 빈 배열입니다. Swift가 타입을 자동으로 추론합니다.
var y = [Int]() // 빈 배열 생성

// 방법 3: Array 제네릭 타입을 사용하여 빈 배열을 선언합니다.
// 'z'는 Int 타입의 빈 배열입니다. Array<Int>는 Int 타입의 요소를 가지는 배열을 의미합니다.
var z: Array<Int> = [] // 빈 배열 생성

 

 

컬렉션 타입(Collection Type)은 여러 값을 한 곳에 저장할 수 있는 데이터 구조를 의미

1. 배열 (Array)
정의: 순서가 있는 값들의 리스트입니다.
특징:
같은 타입의 요소를 저장합니다.
인덱스를 사용하여 요소에 접근합니다.
예시: [1, 2, 3, 4]
2. 집합 (Set)
정의: 중복되지 않는 값들의 모음입니다.
특징:
순서가 없으며, 각 요소는 유일합니다.
주로 중복 제거와 관련된 작업에 사용됩니다.
예시: Set([1, 2, 3])
3. 사전 (Dictionary)
정의: 키-값 쌍으로 이루어진 컬렉션입니다.
특징:
각 키는 유일하며, 이를 통해 값에 접근합니다.
키를 사용하여 데이터를 빠르게 검색할 수 있습니다.
예시: ["name": "Alice", "age": 30]

 

 

-Swift의 Array에서 자주 사용하는 프로퍼티와 메소드를간단정리

 

 

Array 프로퍼티 (속성)
count: 배열의 요소 개수.
예: let count = array.count
isEmpty: 배열이 비어 있는지 여부.
예: let isEmpty = array.isEmpty
first: 배열의 첫 번째 요소.
예: let firstElement = array.first


Array 메소드 (함수)
append(_:): 배열의 끝에 요소 추가.

예: array.append(newElement)
remove(at:): 특정 인덱스의 요소 제거.

예: array.remove(at: index)
contains(_:): 배열에 특정 요소가 있는지 확인.

예: let hasElement = array.contains(element)
sort(): 배열의 요소를 정렬.

예: array.sort()

 

// 타입 추론을 이용하여 빈 배열을 생성합니다.
// Swift가 자동으로 타입을 추론하여 Array<Int> 타입으로 설정됩니다.
let number = [1, 2, 3, 4] 

// 타입을 명시적으로 지정하여 Int 타입의 배열을 생성합니다.
let odd: [Int] = [1, 3, 5] 

// Array 제네릭 타입을 사용하여 Int 타입의 배열을 생성합니다.
let even: Array<Int> = [2, 4, 6] 

// number의 타입을 출력합니다. 결과는 Array<Int>입니다.
print(type(of: number)) // 출력: Array<Int>

// number 배열의 내용을 출력합니다.
print(number) // 출력: [1, 2, 3, 4]

// odd의 타입을 출력합니다. 결과는 Array<Int>입니다.
print(type(of: odd)) // 출력: Array<Int>

// odd 배열의 내용을 출력합니다.
print(odd) // 출력: [1, 3, 5]

// even의 타입을 출력합니다. 결과는 Array<Int>입니다.
print(type(of: even)) // 출력: Array<Int>

// even 배열의 내용을 출력합니다.
print(even) // 출력: [2, 4, 6]

// 문자열 배열을 생성합니다. 타입은 자동으로 추론됩니다.
let animal = ["dog", "cat", "cow"]

// animal의 타입을 출력합니다. 결과는 Array<String>입니다.
print(type(of: animal)) // 출력: Array<String>

// animal 배열의 내용을 출력합니다.
print(animal) // 출력: ["dog", "cat", "cow"]

 

 

빈 배열(empty array) 주의 사항

var number : [Int] = []
//빈 배열을 let으로 만들 수는 있지만 초기값에서 변경 불가이니 배열의 의미 없음
var odd = [Int]() //빈배열은 let이 아닌 var로 써야됨, 가장 많이 사용
var even : Array<Int> = Array()
print(number) //[]
//print(number[0]) //오류, 빈 배열을 값을 넣은 다음에 접근
number.append(100) //let으로 선언한 불변형 배열이라 추가 불가능, 반드시 append를 통해 방을 만들어야함, append는 하면할수록 방이 늘어남
//error: cannot use mutating member on immutable value: 'number' is a 'let' constant
print(number[0])
number.append(200)
print(number[0], number[1],number)

 

 

가변형(mutable)

배열의 내용을 변경할 수 있는 형태

var animal = ["dog", "cat", "cow"]
animal.append("bird") // 배열에 "bird" 추가 가능
print(animal) // 출력: ["dog", "cat", "cow", "bird"]

 

불변형 (immutable)

초기화 후 변경 불가

let animal1 = ["dog", "cat", "cow"]
// animal1.append("bird") // 오류 발생: 변경할 수 없음
print(animal1) // 출력: ["dog", "cat", "cow"]

 

빈 배열 주의사항

var number: [Int] = [] // Int 타입의 빈 배열을 var로 선언

// number[0] = 1 // 오류 발생: 빈 배열이므로 직접 접근할 수 없음

// append() 메소드를 사용하여 배열에 값을 추가
number.append(1) // 1을 배열에 추가
print(number) // 출력: [1]

// 이제 배열에 값이 있으므로, 인덱스를 사용하여 값을 변경할 수 있음
number[0] = 10 // 첫 번째 요소를 10으로 변경
print(number) // 출력: [10]

빈 배열: 초기 상태에서 요소가 없으므로 직접 인덱스를 사용하여 값을 설정할 수 없습니다.
append(): 배열에 요소를 추가하는 메소드로, 이 메소드를 사용해야만 배열에 값을 넣을 수 있습니다.
인덱스 접근: 배열에 요소가 추가된 후에는 인덱스를 사용하여 값을 수정할 수 있습니다.

 

 

 

Array(repeating:count:)  특정값(repeating)으로 원하는 개수(count)만큼 초기화

// Int 타입의 배열을 5개의 0으로 초기화
var x = [0, 0, 0, 0, 0]
print(x) // 출력: [0, 0, 0, 0, 0]

// Array 생성자를 사용하여 0으로 초기화된 배열을 생성
var x1 = Array(repeating: 0, count: 5)
print(x1) // 출력: [0, 0, 0, 0, 0]

// [Int] 타입의 배열을 3개의 1로 초기화
var x2 = [Int](repeating: 1, count: 3)
print(x2) // 출력: [1, 1, 1]

// [String] 타입의 배열을 4개의 "A"로 초기화
var x3 = [String](repeating: "A", count: 4)
print(x3) // 출력: ["A", "A", "A", "A"]

 

 

배열 항목 가져오기: for~in문

// 문자열 배열을 생성하여 색상 목록을 초기화
let colors = ["red", "green", "blue"]
print(colors) // 출력: ["red", "green", "blue"]

// 배열의 각 요소를 반복(iterate)하여 출력하는 for 루프
for color in colors {
    print(color) // 각 색상을 출력
}
// 출력:
// red
// green
// blue

 

 

항목이 몇 개인지(count), 비어있는지(isEmpty) 알아내기

// Int 타입의 배열을 초기화
let num = [1, 2, 3, 4]

// 빈 Int 배열을 생성
var x = [Int]()

// num 배열이 비어있는지 확인하고 출력
print(num.isEmpty) // 배열이 비어있나? false (num 배열에는 요소가 있음)

// x 배열이 비어있는지 확인하고 출력
print(x.isEmpty) // 배열이 비어있나? true (x는 빈 배열)

// num 배열이 비어있으면 메시지를 출력
if num.isEmpty {
    print("비어 있습니다") // num 배열이 비어있다면 이 메시지가 출력됨
} else {
    // num 배열의 요소 개수를 출력
    print(num.count) // 배열 항목의 개수 (출력: 4)
}

 

 

first와 last 프로퍼티

// Int 타입의 배열을 초기화
let num = [1, 2, 3, 4]

// 빈 Int 배열을 생성
let num1 = [Int]()

// num 배열의 첫 번째 요소와 마지막 요소를 출력
// Optional로 감싸져서 출력됨
print(num.first, num.last) // 출력: Optional(1) Optional(4)

// num1 배열은 빈 배열이므로 첫 번째와 마지막 요소는 nil
print(num1.first, num1.last) // 출력: nil nil

// num 배열의 첫 번째와 마지막 요소를 안전하게 추출
if let f = num.first, let l = num.last {
    // f와 l이 각각 첫 번째와 마지막 요소를 가리킴
    print(f, l) // 출력: 1 4
}

// 배열의 first와 last는 둘 다 일반적으로 옵셔널 값으로 나옴
// 빈 배열이기 때문

 

첨자(subscript)로 항목 접근(셤)

// Int 타입의 배열을 초기화
var num = [1, 2, 3, 4]

// 배열의 첫 번째와 네 번째 요소를 출력
print(num[0], num[3]) // 출력: 1 4

// 배열의 첫 번째 요소를 안전하게 출력 (옵셔널 언래핑)
print(num.first!) // 출력: 1

// for 루프를 사용하여 배열의 모든 요소를 출력
for i in 0...num.count-1 {
    print(num[i]) // 출력: 1, 2, 3, 4 (각 요소를 한 줄씩 출력)
}

// 배열의 일부 범위를 출력 (1번과 2번 인덱스의 요소)
print(num[1...2]) // 출력: [2, 3]

// 배열의 0, 1, 2 인덱스 요소를 [10, 20, 30]으로 교체
num[0...2] = [10, 20, 30]

// 변경된 배열을 출력
print(num) // 출력: [10, 20, 30, 4]

 

 

 

Array: 추가 /제거

// let x = [1, 2, 3, 4] // 불변 배열은 초기값에서 변경 불가
// x.append(5) // 오류 발생: let으로 선언된 배열에 추가할 수 없음

// 가변 배열을 초기화
var num = [1, 2, 3]
print(num) // 출력: [1, 2, 3]

// 배열에 4를 추가
num.append(4)
print(num) // 출력: [1, 2, 3, 4]

// 여러 요소를 배열의 끝에 추가
num.append(contentsOf: [6, 7, 8])
print(num) // 출력: [1, 2, 3, 4, 6, 7, 8]

// 5를 4번 인덱스에 삽입
num.insert(5, at: 4)
print(num) // 출력: [1, 2, 3, 4, 5, 6, 7, 8]

// 3번 인덱스의 요소를 제거
num.remove(at: 3)
print(num) // 출력: [1, 2, 3, 5, 6, 7, 8]

// 마지막 요소를 제거
num.removeLast()
print(num) // 출력: [1, 2, 3, 5, 6, 7]

// 배열에서 2의 첫 번째 인덱스를 찾기
print(num.firstIndex(of: 2)) // 출력: Optional(1), 2는 1번 인덱스에 위치

// 2의 인덱스를 안전하게 가져와서 값을 20으로 변경
if let i = num.firstIndex(of: 2) {
    num[i] = 20 // num[1] = 20
}
print(num) // 출력: [1, 20, 3, 5, 6, 7]

// 배열을 자신과 더하여 중복된 요소를 만듦
num = num + num
print(num) // 출력: [1, 20, 3, 5, 6, 7, 1, 20, 3, 5, 6, 7]

// [8, 9]를 배열에 추가
num += [8, 9]
print(num) // 출력: [1, 20, 3, 5, 6, 7, 1, 20, 3, 5, 6, 7, 8, 9]

// 배열의 모든 요소를 제거
num.removeAll()
print(num) // 출력: []

let x: 주석 처리된 불변 배열. 변경할 수 없음을 설명합니다.
var num: 가변 배열을 초기화하여 요소를 추가하고 수정할 수 있습니다.
append(): 배열의 끝에 요소를 추가합니다.
append(contentsOf:): 여러 요소를 한 번에 추가합니다.
insert(): 특정 인덱스에 요소를 삽입합니다.
remove(at:): 특정 인덱스의 요소를 제거합니다.
removeLast(): 배열의 마지막 요소를 제거합니다.
firstIndex(of:): 특정 값의 첫 번째 인덱스를 찾습니다.
if let: 안전하게 옵셔널 값을 언래핑하여 요소를 수정합니다.
num + num: 배열을 자신과 더하여 중복된 요소를 만듭니다.
+=: 배열에 여러 요소를 추가합니다.
removeAll(): 배열의 모든 요소를 제거합니다.

 

 

Array는 구조체이므로 값 타입

// Int 타입의 배열을 초기화
var num = [1, 2, 3]

// num 배열의 복사본을 x에 할당. x는 num과 별개의 배열
var x = num 

// num 배열의 첫 번째 요소를 100으로 변경
num[0] = 100

// num 배열을 출력
print(num) // 출력: [100, 2, 3]

// x 배열을 출력
print(x) // 출력: [1, 2, 3] (x는 num의 복사본이므로 원래 값 유지)

 

 

배열(Array)에서 최댓값 최솟값 구하기

var num = [1,2,3,10,20]
print(num)
print(num.min())
print(num.max())
print(num.min()!)
print(num.max()!)

 

 

Array 요소의 정렬

var num = [1,5,3,2,4]
num.sort() //오름차순 정렬하여 원본 변경
print(num) //[1, 2, 3, 4, 5]
num[0...4] = [2,3,4,5,1]
num.sort(by:>) //내림차순 정렬하여 원본 변경
print(num) //[5, 4, 3, 2, 1]
num[0...4] = [2,3,4,5,1]
num.reverse() //반대로 정렬하여 원본 변경
print(num) //[1, 5, 4, 3, 2]
print(num.sorted()) //오름차순 정렬 결과를 리턴하고, 원본은 그대로, var x = num.sorted()
//[1, 2, 3, 4, 5]
print(num) //[1, 5, 4, 3, 2]
print(num.sorted(by:>)) //내림차순 정렬 결과를 리턴하고, 원본은 그대로
//[5, 4, 3, 2, 1]
print(num)//[1, 5, 4, 3, 2]

sort(): 배열을 직접 수정하여 정렬 (원본 변경).
sorted(): 새로운 배열을 반환하여 정렬 (원본 유지).
내림차순 정렬: sort(by: >) 또는 sorted(by: >)를 사용.

 

swift 접근제어 비교표

1. open

  • 최고 수준의 접근 제어입니다.
  • 모듈 외부에서도 해당 클래스나 메서드를 사용할 수 있고, 상속오버라이드가 가능합니다.
  • 예시: open class SomeClass {}

2. public

  • 모듈 외부에서 사용할 수 있지만, 상속이나 오버라이드는 할 수 없습니다.
  • 외부에서 접근할 수 있지만, 그 내부 동작을 변경할 수는 없어요.
  • 예시: public class SomeClass {}

3. internal (기본값)

  • 해당 모듈 내에서만 접근 가능합니다.
  • 다른 모듈에서는 접근할 수 없으며, 기본적으로 internal로 설정됩니다.
  • 예시: internal class SomeClass {} 또는 접근 제어를 생략한 경우

4. fileprivate

  • 해당 파일 내에서만 접근 가능합니다.
  • 다른 파일에서는 사용할 수 없고, 동일 파일 내에서만 제한적으로 사용됩니다.
  • 예시: fileprivate class SomeClass {}

5. private

  • 가장 제한적인 접근 제어입니다.
  • 같은 블록(즉, 같은 클래스나 구조체 내) 또는 extension에서만 접근할 수 있습니다.
  • 예시: private class SomeClass {}

6. package (Swift 6.0부터)

  • 같은 패키지 내에서만 접근할 수 있습니다.
  • 패키지 외부에서는 사용할 수 없습니다.
  •  
public class SomePublicClass {}        // 외부에서 사용 가능
internal class SomeInternalClass {}   // 같은 모듈 내에서만 사용 가능
fileprivate class SomeFilePrivateClass {} // 같은 파일 내에서만 사용 가능
private class SomePrivateClass {}     // 같은 클래스나 extension에서만 사용 가능

public var somePublicVariable = 0
internal let someInternalConstant = 0
fileprivate func someFilePrivateFunction() {}
private func somePrivateFunction() {}

Swift에서 기본 접근 제어는 **internal**입니다. 즉, 접근 제어를 명시적으로 지정하지 않으면 기본적으로 internal이 적용됩니다. 이 접근 수준은 해당 모듈 내에서만 사용할 수 있도록 제한됩니다.

internal 접근 제어의 특징:

  • 같은 모듈 내에서 모든 소스 파일에서 접근할 수 있습니다.
  • 다른 모듈(즉, 다른 앱이나 다른 프레임워크, 라이브러리)에서는 접근할 수 없습니다.

즉, internal 접근 수준은 프로젝트 내에서만 접근이 가능하고, 외부에서는 사용할 수 없다는 것입니다.

어디서 접근할 수 있나?

  • 같은 프로젝트같은 프레임워크 내의 다른 파일에서 접근이 가능합니다.
  • 다른 프레임워크나 앱에서는 접근할 수 없습니다.

'Swift' 카테고리의 다른 글

iOS프로그래밍 실무 5주차  (0) 2025.04.02
iOS실무 프로그래밍 4주차  (0) 2025.03.26
iOS프로그래밍 실무 3주차  (0) 2025.03.19
iOS 프로그래밍 실무 2주차  (0) 2025.03.17
iOS 프로그래밍 실무 1주차  (0) 2025.03.05

 

테이블 뷰는 두 개의 프로토콜을 가질 수 있으며, 프로토콜은 여러 개 채택할 수 있음

부모 프로토콜: 프로토콜은 하나의 부모를 가질 수 있으며, 부모가 없을 수도 있음

프로토콜 정의:

특정 클래스와 관련 없는 프로퍼티 및 메서드 선언의 집합.
함수(메서드)의 정의는 포함되지 않음.
기능이나 속성에 대한 설계도 역할.
프로토콜 채택: 클래스, 구조체, 열거형에서 프로토콜을 채택하여 해당 메서드를 구현해야 함

UITableViewDataSource프로토콜 필수 메소드: numberOfRowsInSection(row개수), cellForRowAt


UITableViewDataSource프로토콜 : 선택적 메서드

-numberOfSections(in:)
테이블 뷰에 섹션 수를 지정


-tableView(_:titleForHeaderInSection:)
각 섹션의 헤더에 표시될 텍스트를 지정

 

-tableView(_:titleForFooterInSection:)

각 섹션의 푸터에 표시될 텍스트를 지정


-tableView(_:canEditRowAt:)
셀을 삭제하거나 추가할 수 있는지 여부를 결정


-tableView(_:canMoveRowAt:)
셀의 순서를 변경할 수 있는지 여부를 결정

 


테이블 뷰에 사용하는 두번째 프로토콜은

TableView의 Delegate: UITableViewDelegate프로토콜

테이블 뷰 컨트롤러에는 테이블 뷰와 테이블 뷰 셀이 이미 들어가 있음

table view를 화면에 꽉차게 하는 법: add new constraints를 모두 0으로 맞추고, constrain to margins는 체크 해제

 

 

***필수 메소드를 구현하지 않았다는 뜻***
fix누른 후 수정된 코드

섹션은 1

행(row)5


import UIKit // UIKit 프레임워크를 임포트, UI 관련 요소가 포함되어 있음

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    // 테이블 뷰의 섹션 수를 반환하는 메서드
    func numberOfSections(in tableView: UITableView) -> Int {
        return 3 // 섹션 수를 3으로 설정
    }
    
    // 각 섹션에 있는 행(row)의 수를 반환하는 메서드
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10 // 각 섹션에 10개의 행을 설정
    }
    
    // 각 행에 대한 셀을 구성하는 메서드
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell.init(style: .default, reuseIdentifier: "myCell") // 기본 스타일의 셀 생성
        cell.textLabel?.text = indexPath.description // 셀의 텍스트를 섹션 번호와 행 번호로 설정
        return cell // 구성한 셀을 반환
    }
    
    // IBOutlet으로 연결된 테이블 뷰
    @IBOutlet weak var table: UITableView!
    
    // 뷰가 로드될 때 호출되는 메서드
    override func viewDidLoad() {
        super.viewDidLoad() // 부모 클래스의 viewDidLoad 호출
        table.delegate = self // 테이블 뷰의 delegate를 현재 클래스(ViewController)로 설정
        table.dataSource = self // 테이블 뷰의 dataSource를 현재 클래스(ViewController)로 설정
    }
}

indexPath.description //앞에는 섹션번호(0부터 시작), 뒤에는 row


import UIKit // UIKit 프레임워크를 임포트, UI 관련 요소가 포함되어 있음

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    // 테이블 뷰의 섹션 수를 반환하는 메서드
    func numberOfSections(in tableView: UITableView) -> Int {
        return 3 // 섹션 수를 3으로 설정
    }
    
    // 각 섹션에 있는 행(row)의 수를 반환하는 메서드
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10 // 각 섹션에 10개의 행을 설정
    }
    
    // 각 행에 대한 셀을 구성하는 메서드
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell.init(style: .subtitle, reuseIdentifier: "myCell") // 서브타입 스타일의 셀 생성
        cell.textLabel?.text = "\(indexPath.row)" // 셀의 주요 텍스트를 현재 행 번호로 설정
        cell.detailTextLabel?.text = indexPath.description // 셀의 세부 텍스트를 섹션과 행 정보를 설정
        cell.imageView?.image = UIImage(named: "smile.png") // 셀의 이미지 뷰에 "smile.png" 이미지를 설정
        return cell // 구성한 셀을 반환
    }
    
    // IBOutlet으로 연결된 테이블 뷰
    @IBOutlet weak var table: UITableView!
    
    // 뷰가 로드될 때 호출되는 메서드
    override func viewDidLoad() {
        super.viewDidLoad() // 부모 클래스의 viewDidLoad 호출
        table.delegate = self // 테이블 뷰의 delegate를 현재 클래스(ViewController)로 설정
        table.dataSource = self // 테이블 뷰의 dataSource를 현재 클래스(ViewController)로 설정
    }
}

 

 


import UIKit // UIKit 프레임워크를 임포트, UI 관련 요소가 포함되어 있음

// 이미지, 음식 이름, 가격을 저장하는 배열
var image = ["1.png", "2.png", "3.png", "4.png", "5.png"] // 음식 이미지 파일 이름 배열
var foodName = ["한식", "간식", "학식", "중식", "집밥"] // 음식 이름 배열
var price = ["1000", "2000", "3000", "4000", "5000"] // 음식 가격 배열

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    // 테이블 뷰의 섹션 수를 반환하는 메서드
    func numberOfSections(in tableView: UITableView) -> Int {
        return 6 // 섹션 수를 6으로 설정
    }
    
    // 각 섹션에 있는 행(row)의 수를 반환하는 메서드
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 5 // 각 섹션에 5개의 행을 설정
    }
    
    // 각 행에 대한 셀을 구성하는 메서드
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell.init(style: .subtitle, reuseIdentifier: "myCell") // 서브타입 스타일의 셀 생성
        cell.textLabel?.text = foodName[indexPath.row] // 셀의 주요 텍스트를 음식 이름으로 설정
        cell.detailTextLabel?.text = price[indexPath.row] // 셀의 세부 텍스트를 가격으로 설정
        cell.imageView?.image = UIImage(named: image[indexPath.row]) // 셀의 이미지 뷰에 해당 음식 이미지 설정
        return cell // 구성한 셀을 반환
    }
    
    // IBOutlet으로 연결된 테이블 뷰
    @IBOutlet weak var table: UITableView!
    
    // 뷰가 로드될 때 호출되는 메서드
    override func viewDidLoad() {
        super.viewDidLoad() // 부모 클래스의 viewDidLoad 호출
        table.delegate = self // 테이블 뷰의 delegate를 현재 클래스(ViewController)로 설정
        table.dataSource = self // 테이블 뷰의 dataSource를 현재 클래스(ViewController)로 설정
    }
}

 

 


constraints확인

 

 


import UIKit // UIKit 프레임워크를 임포트, UI 관련 요소가 포함되어 있음

// 이미지, 음식 이름, 가격을 저장하는 배열
var image = ["1.png", "2.png", "3.png", "4.png", "5.png"] // 음식 이미지 파일 이름 배열
var foodName = ["1한식", "2간식", "3학식", "4중식", "5집밥"] // 음식 이름 배열
var price = ["1000", "2000", "3000", "4000", "5000"] // 음식 가격 배열

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    // 테이블 뷰의 섹션 수를 반환하는 메서드
    func numberOfSections(in tableView: UITableView) -> Int {
        return 6 // 섹션 수를 6으로 설정
    }
    
    // 각 섹션에 있는 행(row)의 수를 반환하는 메서드
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 5 // 각 섹션에 5개의 행을 설정
    }
    
    // 각 행에 대한 셀을 구성하는 메서드
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        // 재사용 가능한 셀을 큐에서 가져오고, MyTableViewCell 타입으로 캐스팅
        let cell = tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath) as! MyTableViewCell
        
        // 셀의 라벨에 음식 이름을 설정
        cell.myLabel.text = foodName[indexPath.row]
        
        // 현재 행의 인덱스를 출력 (디버깅용)
        print(indexPath.description)
        
        return cell // 구성한 셀을 반환
    }
    
    // IBOutlet으로 연결된 테이블 뷰
    @IBOutlet weak var table: UITableView!
    
    // 뷰가 로드될 때 호출되는 메서드
    override func viewDidLoad() {
        super.viewDidLoad() // 부모 클래스의 viewDidLoad 호출
        table.delegate = self // 테이블 뷰의 delegate를 현재 클래스(ViewController)로 설정
        table.dataSource = self // 테이블 뷰의 dataSource를 현재 클래스(ViewController)로 설정
    }
}

cellForRowAt메소드: 각각에 대한 셀 정보를 만드는 일을 함

 




import UIKit//ui붙은거 전부 uikit안에 있음
var image = ["1.png", "2.png", "3.png", "4.png", "5.png"]
var foodName = ["1한식","2간식","3학식","4중식","5집밥"]
var price = ["1000","2000","3000","4000","5000"]
class ViewController: UIViewController ,UITableViewDelegate,UITableViewDataSource{
    
    func numberOfSections(in tableView: UITableView) -> Int {
        return 6
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 5
    }
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print(indexPath.description)
    }//테이블 뷰에서 셀을 눌렀을때 자동으로 호출되는 메소드
    
  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//        let cell = UITableViewCell.init(style:.subtitle, reuseIdentifier: "myCell")
//        cell.textLabel?.text=foodName[indexPath.row]
//        cell.detailTextLabel?.text = price[indexPath.row]
//        cell.imageView?.image = UIImage(named: image[indexPath.row])//indexPath.row라고 해야됨
      let cell=tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath) as! MyTableViewCell
      cell.myLabel.text = foodName[indexPath.row]
      print(indexPath.description)
        return cell
    }
    //부모(UIViewController), 프로토콜(UITableViewDelegate)


    @IBOutlet weak var table: UITableView!
    override func viewDidLoad() {
        super.viewDidLoad()
        table.delegate = self
        table.dataSource = self
    }


}

didSelectRowAt:

테이블 뷰에서 셀을 눌렀을때 자동으로 호출되는 메소드

 

//
//  ViewController.swift
//  Table
//
//  Created by 소프트웨어컴퓨터 on 2025/04/02.
//

import UIKit//ui붙은거 전부 uikit안에 있음
var image = ["1.png", "2.png", "3.png", "4.png", "5.png"]
var foodName = ["1한식","2간식","3학식","4중식","5집밥"]
var price = ["1000","2000","3000","4000","5000"]
class ViewController: UIViewController ,UITableViewDelegate,UITableViewDataSource{
    
    func numberOfSections(in tableView: UITableView) -> Int {
        return 6
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 5
    }
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print(indexPath.description)
    }//테이블 뷰에서 셀을 눌렀을때 자동으로 호출되는 메소드
    
  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//        let cell = UITableViewCell.init(style:.subtitle, reuseIdentifier: "myCell")
//        cell.textLabel?.text=foodName[indexPath.row]
//        cell.detailTextLabel?.text = price[indexPath.row]
//        cell.imageView?.image = UIImage(named: image[indexPath.row])//indexPath.row라고 해야됨
      let cell=tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath) as! MyTableViewCell
      cell.myLabel.text = foodName[indexPath.row]
      cell.myImage.image = UIImage(named: image[indexPath.row])
      print(indexPath.description)
        return cell
    }
    //부모(UIViewController), 프로토콜(UITableViewDelegate)


    @IBOutlet weak var table: UITableView!
    override func viewDidLoad() {
        super.viewDidLoad()
        table.delegate = self
        table.dataSource = self
    }


}

'Swift' 카테고리의 다른 글

iOS프로그래밍 실무 6주차  (0) 2025.04.09
iOS실무 프로그래밍 4주차  (0) 2025.03.26
iOS프로그래밍 실무 3주차  (0) 2025.03.19
iOS 프로그래밍 실무 2주차  (0) 2025.03.17
iOS 프로그래밍 실무 1주차  (0) 2025.03.05

ViewController.swift

//
//  ViewController.swift
//  aa
//
//  Created by 소프트웨어컴퓨터 on 2025/03/26.
//

import UIKit // UIKit 프레임워크를 임포트하여 UI 요소를 사용할 수 있도록 함

// ViewController 클래스를 정의, UIViewController를 상속받음
class ViewController: UIViewController {

    // 뷰가 메모리에 로드될 때 호출되는 메서드
    override func viewDidLoad() {
        super.viewDidLoad() // 부모 클래스의 viewDidLoad() 메서드를 호출하여 기본 초기화 수행
        
        // 뷰가 로드된 후 추가적인 설정을 할 수 있는 곳
        // 여기에서 UI 요소를 초기화하거나 데이터를 설정할 수 있음
    }
}

 

 

AppDelegate.swift

//
//  AppDelegate.swift
//  aa
//
//  Created by 소프트웨어컴퓨터 on 2025/03/26.
//

import UIKit // UIKit 프레임워크를 임포트하여 UI 관련 기능을 사용 가능하게 함

@main // 이 클래스가 프로그램의 진입점임을 나타냄
class AppDelegate: UIResponder, UIApplicationDelegate { // AppDelegate 클래스 정의, UIResponder 및 UIApplicationDelegate 프로토콜을 준수

    // 애플리케이션이 시작될 때 호출되는 메서드
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // 애플리케이션이 실행된 후 사용자 정의를 위한 오버라이드 포인트
        return true // 애플리케이션이 성공적으로 시작되었음을 나타냄
    }

    // MARK: UISceneSession Lifecycle // UISceneSession 생명주기 관련 메서드 구분을 위한 주석

    // 새로운 장면 세션이 생성될 때 호출되는 메서드
    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        // 새로운 장면을 생성하기 위한 설정을 선택하는 메서드
        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) // 기본 설정을 사용하여 새로운 장면 구성 반환
    }

    // 사용자가 장면 세션을 폐기할 때 호출되는 메서드
    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
        // 애플리케이션이 실행 중이지 않을 때 세션이 폐기되면, 이 메서드가 호출됨
        // 폐기된 장면에 특정한 자원을 해제하는 데 사용
    }
}
 func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
  • _의 사용: _를 사용하면 외부 이름 생략 가능

 

  • configurationForConnecting connectingSceneSession: 

      -configurationForConnecting은 메서드를 호출할 때 사용되는 argument로, 메서드의 목적을 명확히 설명

      -connectingSceneSession은 메서드 정의에서 사용되는 parameter로, 메서드 내부에서 해당 값을 참조하는 데 사용

 

  • options는 application(_:configurationForConnecting:options:) 메서드의 매개변수 중 하나로, 새로운 장면 세션을 연결할 때 사용할 수 있는 추가적인 설정이나 정보를 포함하는 객체

 

  •  Set<UISceneSession>: 제네릭 (집합)

 

 

 

  • 함수에서 정의부의 값을 매개변수, 호출시 값을 아규먼트라고 부름

        함수 내부에서 사용: parameter

        argument함수 에서 호출할때

 

  • 함수 명: application(_:configurationForConnecting:options:)

1. 아규먼트 레이블 (Argument Label)

 

  • _ application:
    외부에서 이 매개변수를 호출할 때 사용할 아규먼트 레이블입니다. _가 붙어있어 이 레이블이 생략된다는 것을 의미합니다. 즉, 호출 시에는 application이라는 이름을 사용하지 않고, 단순히 매개변수의 타입만 사용합니다.
  • configurationForConnecting:
    이 매개변수의 외부 이름으로, 메서드를 호출할 때 사용됩니다. 이 이름은 메서드의 목적을 설명합니다.
  • options:
    이 매개변수의 외부 이름으로, 메서드 호출 시 사용됩니다. 여기서도 호출 시 options라는 이름이 사용됩니다.

 

2. 아규먼트 네임 (Argument Name)

 

  • application:
    메서드 본문에서 사용할 내부 이름입니다. UIApplication 타입의 객체를 참조하기 위해 사용됩니다.

 

  • connectingSceneSession:
    메서드 본문 내에서 사용할 내부 이름입니다. UISceneSession 타입의 객체를 참조합니다.

 

  • options:
    메서드 본문 내에서 사용할 내부 이름입니다. UIScene.ConnectionOptions 타입의 객체를 참조합니다.

 

3. 자료형 (Type)

 

  • UIApplication:
    application 매개변수의 타입입니다. 현재 실행 중인 애플리케이션의 인스턴스를 나타냅니다.

 

  • UISceneSession:
    connectingSceneSession 매개변수의 타입입니다. 새로운 장면 세션을 나타내며, 사용자가 새 장면을 여는 과정에서 생성되는 객체입니다.

 

  • UIScene.ConnectionOptions:
    options 매개변수의 타입입니다. 장면 세션을 연결할 때 사용할 수 있는 추가적인 설정이나 정보를 포함하는 객체입니다.

 

4. 반환 타입 (Return Type)

 

  • -> UISceneConfiguration:
    이 메서드가 반환하는 타입입니다. UISceneConfiguration 객체를 반환하여 새로운 장면의 설정을 정의합니다.

import UIKit

//함수 정의
func sayHello() -> Void{//리턴값이 없는 경우는 ->void는 생략 가능
    print("Hello")
}
sayHello()//호출

 

 

 

import UIKit

//함수 정의
func sayHello() -> Void{//리턴값이 없는 경우는 ->void는 생략 가능
    print("Hello")
}
sayHello()//호출

//int add(int x, int y) { //C, C++
//    return(x+y);
//}
//add(10,20);

// commend+/주석처리

func add(x:Int, y:Int) -> Int {
    return x+y
}
add(x: 10,y: 20)

 

func add(x:Int, y:Int) -> Int {
    return x+y
}
print(add(x: 10,y: 20))//30
var x = 10
print(type(of: x))//Int
print(type(of: add))// (Int, Int) -> Int

함수의 타입 (자료형,자료형,…) -> 리턴형 (Int, Int) -> Int 리턴형이 Void형이면 ()

 

 

func add(xx x:Int, yy y:Int) -> Int {//첫번째는 호출(argument label), 두번째는 함수 정의 (parameter name)
    return x+y
}
print(add(xx: 10,yy: 20))//30


func add(x:Int, y:Int) -> Int {//하나만 있을땐, 내부 외부 전부 같은거
    return x+y
}
print(add(x: 10,y: 20))//30

//#1
func add(xx x:Int, yy y:Int) -> Int {//첫번째는 호출(argument label), 두번째는 함수 정의 (parameter name)
    print(#function)//add(xx:yy:)
    return x+y
}
print(add(xx: 10,yy: 20))//30

//#2
func add(x:Int, y:Int) -> Int {//하나만 있을땐, 내부 외부 전부 같은거
    print(#function)//add(x:y:)
    return x+y
}
print(add(x: 10,y: 20))//30

//#3
func add(_ x:Int, _ y:Int) -> Int {//
    print(#function)//add(_:_:)
    return x+y
}
print(add(1,2))//3

//#4
func add(_ x:Int, with y:Int) -> Int {//
    return x+y
}
print(add(5,with:3))//8

함수의 이름은 다 다름

:의 개수가 매개변수의 개수다, 콤마 없음

 

class Man {
    var age : Int = 0
    //클래스 안에 있는 변수를 프로퍼티라고 하는데 값이 있어야됨, =0 이런식으로 (값이 없으면 에러남)
    //옵셔널 방법도 있음 var age : Int?
}
var x : Int
var han : Man = Man()
han.age = 10
print(han.age)//10

 

메서드 정의

class Man{
    var age : Int = 1
    var weight : Double = 3.5
    //init(){}
    func display(){ //인스턴스 메서드
        print("나이=\(age), 몸무게=\(weight)")
    }
}

var han : Man = Man()
han.display()

 

class Man { // 'Man'이라는 클래스 정의
    var age: Int // 'age'라는 저장 속성 정의 (정수형)
    var weight: Double // 'weight'라는 저장 속성 정의 (실수형)
    
    // 'display' 메서드 정의 - Man 객체의 나이와 몸무게를 출력
    func display() {
        print("나이=\(age), 몸무게=\(weight)") // 나이와 몸무게를 출력
    }
    
    // Designated initializer - Man 객체를 초기화하는 메서드
    init(age: Int, weight: Double) {
        self.age = age // 매개변수 'age'를 저장 속성 'age'에 할당
        self.weight = weight // 매개변수 'weight'를 저장 속성 'weight'에 할당
    } // 초기화 메서드는 객체 생성 시 자동으로 호출됨
}

// 'Man' 클래스의 인스턴스를 생성하고 'han'이라는 변수에 할당
var han: Man = Man(age: 20, weight: 35.5)

// 'han' 인스턴스의 'display' 메서드를 호출하여 나이와 몸무게를 출력
han.display()

designated initializer는 클래스의 주요 초기화 메서드로, 클래스의 모든 속성을 초기화하는 책임을 가진 초기화자

 

class Man{
    var age : Int
    var weight : Double
    func display(){
        print("나이=\(age), 몸무게=\(weight)")
    }
    init(age: Int, weight : Double){
        self.age = age
        self.weight = weight
    } //designated initializer//init메소드는 자동 호출
}
class Student : Man{
    
}
var kim : Student = Student(age: 25, weight: 55.5)
//print(kim.age)//25
kim.display()//나이=25, 몸무게=55.5
var han : Man = Man(age: 20, weight: 35.5)
han.display()//나이=20, 몸무게=35.5

 

class Man{
    var age : Int
    var weight : Double
    func display(){
        print("나이=\(age), 몸무게=\(weight)")
    }
    init(age: Int, weight : Double){
        self.age = age
        self.weight = weight
    }
}
class Student : Man {
    var name : String
    func displayS() {
        print("이름=\(name), 나이=\(age), 몸무게=\(weight)")
    }
    init(age: Int, weight : Double, name : String){
        self.name = name
        super.init(age:age, weight:weight) //이 줄을 안쓰면?
    }//error:'super.init' isn't called on all paths before returning from initializer
} //자식 클래스에서 designated initializer를 만들면 부모 init()상속 안됨
var lee : Student = Student(age:20,weight:65.2,name:"홍길동")
lee.displayS()
lee.display()

 

 self.name = name
        super.init(age:age, weight:weight) //이 줄을 안쓰면?

위 두줄의 순서를 바꾸면 안되는 이유: self.name = name을 super.init(...) 호출 이전에 수행하면, 초기화되지 않은 self를 사용하는 것이 되어 에러가 발생합니다. 따라서 반드시 부모 클래스의 초기화를 먼저 수행한 후, 자식 클래스의 속성을 초기화해야 함

 

class Man { // 'Man'이라는 클래스 정의
    var age: Int // 'age'라는 저장 속성 정의 (정수형)
    var weight: Double // 'weight'라는 저장 속성 정의 (실수형)
    
    // 'display' 메서드 정의 - Man 객체의 나이와 몸무게를 출력
    func display() {
        print("나이=\(age), 몸무게=\(weight)") // 나이와 몸무게를 출력
    }
    
    // Designated initializer - Man 객체를 초기화하는 메서드
    init(age: Int, weight: Double) {
        self.age = age // 매개변수 'age'를 저장 속성 'age'에 할당
        self.weight = weight // 매개변수 'weight'를 저장 속성 'weight'에 할당
    }
}

class Student: Man { // 'Student'라는 클래스 정의, 'Man' 클래스를 상속받음
    var name: String // 'name'이라는 저장 속성 정의 (문자열형)
    
    // display 메서드를 오버라이드 - Student 객체의 이름, 나이, 몸무게를 출력
    override func display() {
        // 오버라이드의 목적: 부모 클래스의 'display' 메서드를 재정의하여
        // Student 클래스에 맞는 출력 형식으로 변경
        print("이름=\(name), 나이=\(age), 몸무게=\(weight)") // 이름, 나이, 몸무게를 출력
    }
    
    // Designated initializer - Student 객체를 초기화하는 메서드
    init(age: Int, weight: Double, name: String) {
        self.name = name // 매개변수 'name'을 저장 속성 'name'에 할당
        super.init(age: age, weight: weight) // 부모 클래스의 designated initializer 호출
        // 위 줄이 없으면 에러 발생: 'super.init'이 모든 경로에서 호출되지 않음
    }
}

// 'Student' 클래스의 인스턴스를 생성하고 'lee'라는 변수에 할당
var lee: Student = Student(age: 20, weight: 65.2, name: "홍길동")

// 'lee' 인스턴스의 'display' 메서드를 호출하여 이름, 나이, 몸무게를 출력
lee.display()

override func display() { ... } 
// 오버라이드의 목적: 부모 클래스의 'display' 메서드를 재정의하여
// Student 클래스에 맞는 출력 형식으로 변경

 


델리게이트(Delegate) 디자인 패턴은 한 객체가 다른 객체에게 특정 작업을 맡기는 방법

 

프로토콜(protocol) :특정 클래스와 관련없는 함수(메서드)들의 선언 집합

 

Swift에서 프로토콜의 속성(property)은 접근 제어를 명시해야됨

즉, 속성이 읽기 전용인지(get), 쓰기 가능인지(get set) 명시해야됨
따라서, Runnable 프로토콜의 x 속성에 대해 { get } 또는 { get set }을 추가해야 함

 

메시지 "Type 'Man' does not conform to protocol 'Runnable'"는 Man 클래스가 Runnable 프로토콜의 요구사항을 충족하지 않음을 나타냄

Runnable 프로토콜은 x라는 읽기/쓰기 속성과 run()이라는 메서드를 요구하고 있음

 

protocol Runnable { // 'Runnable'이라는 프로토콜 정의
    var x: Int { get set } // 'x'라는 읽기/쓰기 가능한 속성 요구
    func run() // 'run()'이라는 메서드 요구
}

class Man: Runnable { // 'Man' 클래스가 'Runnable' 프로토콜을 준수 ,adopt
    var x: Int = 1 // 'x' 속성을 구현, 기본값 1로 초기화,준수, conform
    
    func run() {print("Runnnn~~~~")}// 'run()' 메서드를 구현, 메서드가 호출되면 출력, 준수,conform
   
}

var kim: Man = Man() // 'Man' 클래스의 인스턴스 생성
kim.run() // 'kim'의 'run()' 메서드 호출, "Runnnn~~~~" 출력

프로토콜은 여러개가 올 수 있음

 

 

상속과 프로토콜을 사용한 간단한 예제

// 'Workable'이라는 프로토콜 정의
protocol Workable {
    func work() // 일하기 메서드 요구
}

// 기본 클래스 'Employee' 정의
class Employee: Workable {
    var name: String // 직원의 이름
    var salary: Double // 직원의 급여
    
    // 초기화 메서드
    init(name: String, salary: Double) {
        self.name = name // 이름 초기화
        self.salary = salary // 급여 초기화
    }
    
    // 프로토콜의 'work()' 메서드 구현
    func work() {
        print("\(name) is working.") // 직원이 일하고 있음을 출력
    }
}

// 'Manager' 클래스가 'Employee' 클래스를 상속
class Manager: Employee {
    // 사장만의 고유 메서드
    func manage() {
        print("\(name) is managing the team.") // 사장이 팀을 관리하고 있음을 출력
    }
}

// 'PartTimeWorker' 클래스가 'Employee' 클래스를 상속
class PartTimeWorker: Employee {
    // 아르바이트생만의 고유 메서드
    func serve() {
        print("\(name) is serving customers.") // 아르바이트생이 고객을 서비스하고 있음을 출력
    }
}

// 사용 예: 'Manager' 인스턴스 생성
let boss = Manager(name: "사장님", salary: 5000)
boss.work() // "사장님 is working." 출력
boss.manage() // "사장님 is managing the team." 출력

// 사용 예: 'PartTimeWorker' 인스턴스 생성
let worker = PartTimeWorker(name: "아르바이트생", salary: 2000)
worker.work() // "아르바이트생 is working." 출력
worker.serve() // "아르바이트생 is serving customers." 출력

 

'Swift' 카테고리의 다른 글

iOS프로그래밍 실무 6주차  (0) 2025.04.09
iOS프로그래밍 실무 5주차  (0) 2025.04.02
iOS프로그래밍 실무 3주차  (0) 2025.03.19
iOS 프로그래밍 실무 2주차  (0) 2025.03.17
iOS 프로그래밍 실무 1주차  (0) 2025.03.05

사전 계획서


1. 프로젝트 개요
프로젝트명: 무드등 iOS 앱
목표: 사용자가 다양한 색상과 밝기를 조절하여 무드등을 설정할 수 있는 앱 개발
주요 기능:
색상 선택 기능
밝기 조절 기능
타이머 설정 기능
사용자 맞춤형 테마 저장 기능
Bluetooth 또는 Wi-Fi를 통한 무드등 제어 기능


2. 기술 스택
프로그래밍 언어: Swift
개발 환경: Xcode
데이터베이스: Core Data 또는 Firebase
UI/UX 디자인: Sketch 또는 Figma


3. 일정 계획
2025년 3월 20일 - 3월 31일: 요구사항 분석 및 기획
2025년 4월 1일 - 4월 15일: UI/UX 디자인
2025년 4월 16일 - 5월 15일: 개발 단계
색상 선택 및 밝기 조절 기능 구현
타이머 및 테마 저장 기능 구현
Bluetooth/Wi-Fi 연결 기능 구현
2025년 5월 16일 - 5월 25일: 테스트 및 버그 수정
2025년 5월 26일 - 5월 30일: 최종 검토 및 배포 준비


4. 작업 분담
팀원 A:

요구사항 분석 및 기획
UI/UX 디자인
테스트 및 버그 수정
팀원 B:

색상 선택 및 밝기 조절 기능 구현
타이머 및 테마 저장 기능 구현
최종 검토 및 배포 준비
팀원 C:

Bluetooth/Wi-Fi 연결 기능 구현
데이터베이스 설계 및 구현
테스트 및 버그 수정

 

 

bundle identifier은 식별자라고 생각하면 됨, 이게 달라야 앱이 올라감

 

실행키: commend(윈도우키)+R

 

import UIKit // UIKit 프레임워크를 임포트하여 iOS 앱의 UI 요소를 사용할 수 있게 함

class ViewController: UIViewController { // ViewController 클래스를 정의하며, UIViewController를 상속받음

    override func viewDidLoad() { // 뷰가 메모리에 로드된 후 호출되는 메서드
        super.viewDidLoad() // 부모 클래스의 viewDidLoad() 메서드를 호출하여 기본 동작을 수행
        print("viewDidLoad()") // viewDidLoad가 호출되었음을 콘솔에 출력
    }

    override func viewWillAppear(_ animated: Bool) { // 뷰가 화면에 나타나기 직전에 호출되는 메서드
        print("viewWillAppear") // viewWillAppear가 호출되었음을 콘솔에 출력
    }

    override func viewDidAppear(_ animated: Bool) { // 뷰가 화면에 나타난 후 호출되는 메서드
        print("viewDidAppear") // viewDidAppear가 호출되었음을 콘솔에 출력
    }
}

뷰에는 5가지로 구성되어 있다

 

 

AppDelegate.swift :iOS 애플리케이션의 시작, 씬 관리 및 리소스 정리를 담당하는 파일

import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {



    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        return true
    }

    // MARK: UISceneSession Lifecycle

    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        // Called when a new scene session is being created.
        // Use this method to select a configuration to create the new scene with.
        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
    }

    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
        // Called when the user discards a scene session.
        // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
        // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
    }


}

 

 

SceneDelegate.swift :  iOS 애플리케이션에서 씬의 생명 주기를 관리하고, 씬의 상태 변화에 따라 필요한 작업을 수행하는 파일

import UIKit // UIKit 프레임워크를 임포트합니다.

class SceneDelegate: UIResponder, UIWindowSceneDelegate { // SceneDelegate 클래스를 정의하고, UIResponder와 UIWindowSceneDelegate를 상속받습니다.

    var window: UIWindow? // 현재 씬에 연결된 UIWindow 객체

    // 씬이 세션에 연결될 때 호출되는 메서드
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // 주어진 UIWindowScene `scene`에 UIWindow `window`를 구성하고 연결하는 데 사용할 수 있는 메서드입니다.
        // 스토리보드를 사용하는 경우, `window` 속성은 자동으로 초기화되고 씬에 연결됩니다.
        // 이 델리게이트는 연결되는 씬이나 세션이 새롭다는 것을 의미하지 않습니다 (새로운 세션에 대한 `application:configurationForConnectingSceneSession`를 참조하세요).
        guard let _ = (scene as? UIWindowScene) else { return } // 씬이 UIWindowScene인지 확인합니다. 아니라면 메서드를 종료합니다.
    }

    // 씬이 시스템에 의해 해제될 때 호출되는 메서드
    func sceneDidDisconnect(_ scene: UIScene) {
        // 씬이 백그라운드로 들어가거나 세션이 버려진 직후에 호출됩니다.
        // 다음 번에 씬이 연결될 때 재생성할 수 있는 씬과 관련된 리소스를 해제합니다.
        // 씬은 나중에 다시 연결될 수 있습니다. 세션이 반드시 버려진 것은 아닙니다 (세션이 버려진 경우는 `application:didDiscardSceneSessions`를 참조하세요).
    }

    // 씬이 비활성 상태에서 활성 상태로 이동할 때 호출되는 메서드
    func sceneDidBecomeActive(_ scene: UIScene) {
        // 씬이 비활성 상태에서 활성 상태로 이동할 때 호출됩니다.
        // 이 메서드를 사용하여 씬이 비활성 상태일 때 일시 중지된 작업을 재시작합니다.
    }

    // 씬이 활성 상태에서 비활성 상태로 이동할 때 호출되는 메서드
    func sceneWillResignActive(_ scene: UIScene) {
        // 씬이 활성 상태에서 비활성 상태로 이동할 때 호출됩니다.
        // 이는 임시 중단(예: 전화 수신)으로 인해 발생할 수 있습니다.
    }

    // 씬이 백그라운드에서 포그라운드로 전환될 때 호출되는 메서드
    func sceneWillEnterForeground(_ scene: UIScene) {
        // 씬이 백그라운드에서 포그라운드로 전환될 때 호출됩니다.
        // 이 메서드를 사용하여 백그라운드에 들어갈 때 변경한 내용을 되돌립니다.
    }

    // 씬이 포그라운드에서 백그라운드로 전환될 때 호출되는 메서드
    func sceneDidEnterBackground(_ scene: UIScene) {
        // 씬이 포그라운드에서 백그라운드로 전환될 때 호출됩니다.
        // 이 메서드를 사용하여 데이터를 저장하고, 공유 리소스를 해제하며,
        // 씬을 현재 상태로 복원하는 데 필요한 씬 특정 상태 정보를 저장합니다.
    }
}

 

App Life Cycle

포그라운드 모드(Foreground Mode)
활성 (Active): 앱이 화면에 보이고 사용자와 상호작용 중.
비활성 (Inactive): 앱이 화면에 보이지만 사용자 입력을 받지 않음.


백그라운드 모드(Background Mode)
실행 중 (Running): 앱이 백그라운드에서 코드 실행 중, 사용자가 다른 앱으로 전환할 때 잠시 이 상태에 있음.
정지 (Suspend): 앱이 백그라운드에 있지만 코드 실행하지 않음. 필요 시 시스템이 종료할 수 있음.

 

 

뷰(View)

모든 뷰는 UIKit의 UIView클래스의 자식클래스이다

 

uicontrol은 클릭하거나 했을 때 반응함

나머지 툴바, 이미지바 등은 순수하게 화면을 보여줌

일반적으로 보여주는 거는 uiview클래스에서 관리함 

부모를 수퍼뷰, 자식을 서브뷰라고 함 

 

control: 컨트롤들은 정보를 표시하고 사용자에게 반응하는 뷰들을 포함

 

 

viewcontroller.swift ( 뷰의 배경색 설정)

import UIKit // UIKit 프레임워크를 임포트합니다.

class ViewController: UIViewController { // ViewController 클래스를 정의하고 UIViewController를 상속받습니다.

    override func viewDidLoad() { // 뷰가 메모리에 로드된 후 호출되는 메서드
        super.viewDidLoad() // 부모 클래스의 viewDidLoad 메서드를 호출하여 기본 설정을 수행합니다.
        view.backgroundColor = UIColor.green // 뷰의 배경색을 초록색으로 설정합니다.
    }

    // view: UIViewController의 기본 속성으로, 현재 뷰 컨트롤러가 관리하는 화면을 나타냅니다.
    // 이 속성을 통해 화면의 UI 요소에 접근하고, 레이아웃을 설정하며, 이벤트를 처리할 수 있습니다.
}

 

 

 

무드등 만들기

import UIKit // UIKit 프레임워크를 임포트하여 사용자 인터페이스 관련 기능을 사용합니다.

class ViewController: UIViewController { // ViewController 클래스를 정의하고 UIViewController를 상속받습니다.
    
    var colorChangeTimer: Timer? // 배경색을 변경하기 위한 타이머 변수

    override func viewDidLoad() { // 뷰가 메모리에 로드된 후 호출되는 메서드
        super.viewDidLoad() // 부모 클래스의 viewDidLoad 메서드를 호출하여 기본 설정을 수행합니다.
        
        // 1초마다 배경색을 변경하는 타이머를 설정합니다.
        colorChangeTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
            // 랜덤한 색상을 생성하기 위해 각각의 RGB 값을 생성합니다.
            let red = CGFloat(arc4random_uniform(256)) / 255.0 // 0부터 1까지의 랜덤한 빨간색 값
            let green = CGFloat(arc4random_uniform(256)) / 255.0 // 0부터 1까지의 랜덤한 초록색 값
            let blue = CGFloat(arc4random_uniform(256)) / 255.0 // 0부터 1까지의 랜덤한 파란색 값
            
            // 생성된 RGB 값을 사용하여 뷰의 배경색을 설정합니다.
            self.view.backgroundColor = UIColor(red: red, green: green, blue: blue, alpha: 1.0)
        }
    }
    
    override func viewDidDisappear(_ animated: Bool) { // 뷰가 화면에서 사라질 때 호출되는 메서드
        super.viewDidDisappear(animated) // 부모 클래스의 viewDidDisappear 메서드를 호출합니다.
        
        // 뷰가 사라질 때 타이머를 무효화하고 nil로 설정하여 메모리 해제를 도와줍니다.
        colorChangeTimer?.invalidate() // 타이머를 중지합니다.
        colorChangeTimer = nil // 타이머 변수를 nil로 설정합니다.
    }
}

 

 

오디오 재생

import UIKit

import AVFoundation  // 오디오를 다루기 위한 프레임워크 추가

class ViewController: UIViewController {
  
  var colorChangeTimer: Timer?
  var audioPlayer: AVAudioPlayer!

  override func viewDidLoad() {
    super.viewDidLoad()
    
    // 배경 음악 재생 설정
    if let soundURL = Bundle.main.url(forResource: "bgm", withExtension: "mp3") {
      do {
        audioPlayer = try AVAudioPlayer(contentsOf: soundURL)
        audioPlayer.play()
      } catch {
        print("음악 파일 로드 또는 재생 중 에러 발생: \(error)")
      }
    }
    
    // 1초마다 반복되는 타이머 생성
    colorChangeTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
      // 랜덤한 빨간색, 초록색, 파란색 값을 생성
      let red = CGFloat(arc4random_uniform(256)) / 255.0
      let green = CGFloat(arc4random_uniform(256)) / 255.0
      let blue = CGFloat(arc4random_uniform(256)) / 255.0
      self.view.backgroundColor = UIColor(red: red, green: green, blue: blue, alpha: 1.0)
    }
  }
  
  override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)
    
    // ViewController가 사라질 때 타이머를 중지하고 nil로 설정하여 메모리 누수를 방지
    colorChangeTimer?.invalidate()
    colorChangeTimer = nil
    
    // 음악 재생 중지
    audioPlayer.stop()
  }
}

 

정가운데 위치

오토레이아웃 : 모든 기기에 자동으로 디자인 적용

 

 

-오토레이아웃 사용 방법의 장단점

 

 

 

import UIKit

class ViewController: UIViewController {
    @IBOutlet weak var textFeld: UITextField!
    
    @IBOutlet weak var label: UILabel!
    
    @IBAction func displayText(_ sender: Any) {
        label.text = textFeld.text
        startScrolling()
    }
    func startScrolling() {
    UIView.animate(withDuration: 10, delay: 0, options: [.curveLinear, .repeat], animations: {
    self.label.center.x -= self.view.bounds.width
    }, completion: nil)
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }


}

 

 

출처: 한성현 교수님 수업자료

'Swift' 카테고리의 다른 글

iOS프로그래밍 실무 5주차  (0) 2025.04.02
iOS실무 프로그래밍 4주차  (0) 2025.03.26
iOS 프로그래밍 실무 2주차  (0) 2025.03.17
iOS 프로그래밍 실무 1주차  (0) 2025.03.05
iOS 기초 프로그래밍15주차  (0) 2024.12.11

숫자 저장하기 위한 변수 선언

var myNumber = 10 // lowerCamelCase, UpperCamelCase

*lowerCamelCase: 소문자로 시작해, 단어가 바뀔때 대문자로 , 변수명

*UpperCamelCase: 첫단어가 대문자, 클래스 이름

 

 

var x = 10 // 정수형 변수 x를 10으로 초기화
print(type(of: x)) // x의 타입을 출력 (결과: Int)

let s = MemoryLayout.size(ofValue: x) // x의 메모리 크기를 바이트 단위로 가져옴
let t = MemoryLayout<Int>.size // Int 타입의 메모리 크기를 바이트 단위로 가져옴

print(s, t) // x의 메모리 크기와 Int 타입의 메모리 크기를 출력

int형

// 정수형 변수 x를 10으로 초기화
var x = 10

// x의 타입 출력
print(type(of: x)) // Int

// x의 값 출력
print(x) // 10

// 변수 이름 x를 문자열로 출력
print("x") // x

// x의 값을 문자열 보간법으로 출력
print("\(x)") // 10

// x의 값을 포함한 문장 출력
print("값은 \(x)입니다.") // 값은 10입니다.

// Int형의 최소값과 최대값 출력
print("Int Min = \(Int.min) Int Max = \(Int.max)")
// Int Min = -9223372036854775808 Int Max = 9223372036854775807

 

 

부동 소수점 데이터 타입: Double vs Float

*double형이 기본

// 실수형 변수 myWeight를 58.5로 초기화
var myWeight = 58.5 

// myWeight의 타입 출력
print(type(of: myWeight)) // Double

 

 

부울 데이터 타입 : Bool

* 참 또는 거짓(1 또는 0) 조건을 처리

 

 

문자 데이터 타입 : Character

 

문자열 데이터 타입 : String

 

 

상수선언: let

 let maximumNumber = 10

변수 선언 var

var myVariable = 10 // :Int

 

튜플(Tuple)

:여러 값을 하나의 개체에 일시적으로 묶는 방법

 

// 이름이 없는 튜플
let myTuple1 = (10, 12.1, "Hi")
// 인덱스를 사용하여 접근
var myString = myTuple1.2 // myString에 "Hi" 저장
print(myString) // 출력: Hi
print(type(of:myTuple))//(Int,Double,String)


// 이름이 있는 튜플
let myTuple2 = (count: 10, length: 12.1, message: "Hi")
// 이름을 사용하여 접근
print(myTuple.message, myTuple.2)//에러 발생
print(myTuple2.message, myTuple2.count) // 출력: Hi 10

 

func logMessage(_ s: String) { // {앞에 ->Void나 ->() 생략
print("Message: \(s)")
}
let logger: (String)->Void = logMessage //여기서는 함수 자료형이라 ->Void 생략 불가
logger("Hello")

 

 

typealias Void = ()

// 문자열을 받아서 반환값이 없는 함수 logMessage 선언
func logMessage(_ s: String) {
    print("Message: \(s)") // 전달받은 문자열을 출력
}

// logMessage 함수를 호출하는 클로저를 logger라는 상수로 선언
let logger: (String) -> Void = logMessage // 함수 자료형이므로 ->Void 생략 불가

// logger 클로저를 사용하여 "Hello" 메시지 출력
logger("Hello") // Message: Hello

 

 

 

옵셔널(optional)

 Int("100") // 100이 아닌 Optional(100)을 리턴함,print(Int("100")), Int형 initializer
 Int("Hi") // 정수 값을 반환할 수 없음, 아무런 값도 반환할 수 없다는 의미로 nil을 반환
var x : Int? //옵셔널 정수형 변수 x 선언
var y : Int = 0
x = 10 // 주석처리하면?
print(x) // Optional(10)
print(x!) // forced unwrapping해서 10이 나옴
print(y)//0
x = x!+2 //!필요
print(x)//12
y = x! //!필요
print(y)//12

 

 

forced unwrapping

var x : Int?//=nil
//x = 10
//print(x!)

if x != nil {
print(x!)
}
else {
print("nil")
}

주의 : if x!=nil 이라고 쓰면 안됨

 

 

optional binding

var x : Int?
x = 10
//print(x)//x=10을 주석처리할 경우 nil출력
if let x{ //옵셔널 변수 x가 값(10)이 있으므로 언래핑해서 일반 상수 xx에 대입하고 if문 실행
print(x)
}
else {
print("nil")
}

 

 

여러 옵셔널을 언래핑

var pet1: String?
var pet2: String?
pet1 = "cat"
pet2 = "dog"
if let firstPet = pet1, let secondPet = pet2 {
print(firstPet, secondPet)
} else {
print("nil")
}


// 위 소스를 short form of if-let to the Optional Binding으로 변경
var pet1: String?
var pet2: String?
pet1 = "cat"
pet2 = "dog"

// Optional Binding의 short form 사용
if let firstPet = pet1, secondPet = pet2 { // pet2의 let 생략 가능
    print(firstPet, secondPet) // cat dog
} else {
    print("nil")
}

 

 

여러 옵셔널 값 동시에 언래핑

var x: Int?
var y: Int?
x = 10
y = 20

if let xx = x {
    print(xx) // 10
} else {
    print("nil")
}

if let yy = y {
    print(yy) // 20
} else {
    print("nil")
}

 

Nil-Coalescing Operator(Nil합병연산자) ??

var age: Int?
age = 20
print(age) // Optional(20) - age가 옵셔널이므로 값이 Optional로 감싸져 출력됨

var myAge = age ?? 1
print(myAge) // 20 - age가 nil이 아닐 경우 그 값을 사용하고, nil일 경우 1을 사용

 

 

옵셔널을 언래핑하는 여러가지 방법

var x: String? = "Hi" // x는 옵셔널 문자열로 "Hi"로 초기화됨
// = "Hi" 지우고도 실습: x는 nil이 될 수 있음

print(x, x!) // Optional("Hi") "Hi" (x가 nil이 아닐 경우)
if let a = x {
    print(a) // "Hi" (옵셔널 바인딩을 통해 a에 "Hi"가 할당됨)
}

let c = x ?? "" // x가 nil일 경우 빈 문자열("")을 할당
print(c) // "Hi" (x가 nil이 아니므로 "Hi"가 출력됨)

 

 

암묵적인 언래핑(implicitly unwrapped)

 var x : Int? //옵셔널 변수 선언방법 1
 var y : Int! //옵셔널 변수 선언방법 2, 암묵적인 언래핑(implicitly unwrapped) 옵셔널, 자동으로 풀리기도 함
let x: Int? = 1 // x는 옵셔널 정수형으로 1로 초기화됨
let y: Int = x! // 강제 언래핑하여 y에 1을 할당
let z = x // z는 옵셔널 정수형 (Optional<Int>)으로 x를 그대로 할당
print(x, y, z) // 출력: Optional(1) 1 Optional(1)
print(type(of: x), type(of: y), type(of: z)) 
// 출력: Optional<Int> Int Optional<Int>

let a: Int! = 1 // a는 암시적 언래핑 옵셔널로 1로 초기화됨
let b: Int = a // a가 자동으로 언래핑되어 b에 1을 할당
let c: Int = a! // 강제 언래핑하여 c에 1을 할당
let d = a // d는 암시적 언래핑 옵셔널 (Optional<Int>)로 a를 그대로 할당
let e = a + 1 // a가 자동으로 언래핑되어 1 + 1 = 2가 됨
print(a, b, c, d, e) // 출력: Optional(1) 1 1 Optional(1) 2
print(type(of: a), type(of: b), type(of: c), type(of: d), type(of: e)) 
// 출력: Optional<Int> Int Int Optional<Int> Int

 

 

 

nil-Coalescing Operator (nil합병연산자)

let defaultAge = 1 // 기본값으로 사용할 정수형 변수
var age: Int? // 옵셔널 정수형 변수 선언
age = 20 // age에 20 할당
print(age) // Optional(20) - age가 옵셔널이므로 값이 Optional로 출력됨

var myAge = age ?? defaultAge // age가 nil이 아니므로 20이 myAge에 할당됨
print(myAge) // 20 - age가 nil이 아니므로 언래핑된 값인 20이 출력됨

var x: Int? = 1 // 옵셔널 정수형 변수 x 선언 및 초기화
var y = x ?? 0 // x가 nil이 아니므로 1이 y에 할당됨
print(y) // 1 - x가 nil이 아니므로 언래핑된 값인 1이 출력됨

 

 

Int!형을 property로 갖는 클래스

// MyAge 클래스를 정의
class MyAge {
    // Int형의 강제 언래핑된 Optional 변수 age 선언
    var age: Int!
    
    // 초기화 메서드, age를 매개변수로 받음
    init(age: Int) {
        self.age = age // 초기화된 age 값을 설정
    }
    
    // 나이를 출력하는 메서드
    func printAge() {
        print(age) // age의 값을 출력 (optional(1) 형태로 출력)
        
        // age에 1을 더하여 출력 (강제 언래핑 없이 사용 가능)
        print(age + 1) // 2 (age가 nil이 아님을 보장)
        
        // age를 Int형으로 바인딩
        let age1: Int = age
        print(age1) // 1 (age의 값을 출력)
        
        // age에 2를 더한 값을 age2에 저장하고 출력
        let age2 = age + 2
        print(age2) // 3
    }
}

// MyAge 클래스의 인스턴스를 생성하고 나이를 1로 설정
var han = MyAge(age: 1)

// printAge 메서드를 호출하여 나이를 출력
han.printAge()

 

for-in문

*for 문 다음의 실행코드가 한 줄이라도 괄호({})를 필수적으로 사용

for i in 1...5 {
print("\(i) 안녕")
}
for _ in 1...5 {
print("안녕")
}

 

while 반복문

// 변수 myCount를 0으로 초기화
var myCount = 0

// myCount가 1000보다 작은 동안 반복
while myCount < 1000 {
    myCount += 1 // myCount의 값을 1씩 증가
}

// myCount의 최종 값을 출력
print(myCount) // 결과는 1000

 

repeat~while 반복문

// 변수 i를 10으로 초기화
var i = 10

// repeat-while 루프 시작
repeat {
    i = i - 1 // i를 1 감소시킴
    print(i) // 현재 i의 값을 출력
} while (i > 0) // i가 0보다 큰 동안 반복

// 출력 결과:
// 9
// 8
// 7
// 6
// 5
// 4
// 3
// 2
// 1
// 0

반복문에서 빠져나오기 (break)

for i in 1..<10 { // 1부터 9까지 반복
    if i > 5 { // i가 5보다 큰 경우
        break // 반복문을 종료
    }
    print(i) // i가 5 이하일 때만 출력
}

 

 

옵셔널은 연관 값(associated value)을 갖는 enum

// Optional 열거형 정의
public enum Optional<Wrapped> {
    case none          // 값이 없음을 나타내는 경우
    case some(Wrapped) // 값이 있는 경우 (Wrapped 타입의 값을 포함)
}

// Optional 타입의 변수 선언 및 초기화
var x: Int? = 20 // .some(20)으로 초기화됨
var y: Int? = Optional.some(10) // Optional.some을 사용하여 10으로 초기화
var z: Int? = Optional.none // 값이 없는 경우로 초기화

// Optional<Int> 타입의 변수 x1을 직접 초기화 
var x1: Optional<Int> = Optional.some(30) // .some(30)으로 초기화

// 변수 x, y, z, x1의 값을 출력
print(x, y, z, x1) // 출력: Optional(20) Optional(10) Optional.none Optional(Optional(30))

if 문 조건에서 콤마: 조건나열(condition-list)

var x = 1
var y = 2

// 첫 번째 if 문: x가 1이고 y가 2일 때
if x == 1 && y == 2 { // 논리식이 둘 다 참일 때
    print(x, y) // 출력: 1 2
}

// 두 번째 if 문: x가 1이고 y가 2일 때
if x == 1, y == 2 { // 조건이 둘 다 참일 때, 두 조건을 콤마로 연결한 condition-list
    print(x, y) // 출력: 1 2
}

var a: Int? = 1 // 옵셔널 정수형 변수 a 선언 및 초기화
var b: Int? = 2 // 옵셔널 정수형 변수 b 선언 및 초기화
print(a, b) // 출력: Optional(1) Optional(2)
// 강제 언래핑을 통해 값을 출력
print(a!, b!) // 출력: 1 2


if let a1 = a, let b1 = b { // a와 b가 nil이 아니면, 언래핑하여 a1과 b1에 대입
    print(a1, b1) // 출력: 1 2
}

// 오류 발생 코드 (주석 처리된 부분)
// if let a1 = a && let b1 = b { // error: expected ',' joining parts of a multi-clause condition
//     print(a1, b1)
// }

 

범위 연산자( One-Sided Ranges)

// 문자열 배열 names를 정의
let names = ["A", "B", "C", "D"]

// 배열의 인덱스 2부터 끝까지 반복
for name in names[2...] { // 2번째 인덱스부터 끝까지의 요소를 가져옴
    print(name) // 각 이름을 출력
} 
// 실행 결과:
// C
// D

 

switch-case문 

let anotherCharacter: Character = "a" // anotherCharacter를 "a"로 초기화

switch anotherCharacter {
case "a": // "a"인 경우
    print("a글자") // 실행문 추가: "a"일 때 출력
case "A": // "A"인 경우
    print("A글자") // 출력: "A글자"
default: // 위의 경우가 아닌 경우
    print("A글자 아님") // 출력: "A글자 아님"
}
//bmi if문 switch-case문으로 변경
//if 문 

let weight = 60.0
let height = 170.0
let bmi = weight / (height*height*0.0001) // kg/m*m
var body = ""
if bmi >= 40 {
body = "3단계 비만"
} else if bmi >= 30 && bmi < 40 {
body = "2단계 비만"
} else if bmi >= 25 && bmi < 30 {
body = "1단계 비만"
} else if bmi >= 18.5 && bmi < 25 {
body = "정상"
} else {
body = "저체중"
}
print("BMI:\(bmi), 판정:\(body)")


//switch-case문
let weight = 60.0
let height = 170.0
let bmi = weight / (height * height * 0.0001) // kg/m*m
var body = ""

switch bmi {
case _ where bmi >= 40:
    body = "3단계 비만"
case _ where bmi >= 30:
    body = "2단계 비만"
case _ where bmi >= 25:
    body = "1단계 비만"
case _ where bmi >= 18.5:
    body = "정상"
default:
    body = "저체중"
}

print("BMI:\(bmi), 판정:\(body)")

 

where: 조건을 추가

var numbers: [Int] = [1, 2, 3, 4, 5] // 정수 배열 numbers 선언 및 초기화

// numbers 배열의 각 요소에 대해 반복
for num in numbers where num > 3 { // num이 3보다 큰 경우에만 실행
    print(num) // 조건을 만족하는 num을 출력
}

switch-case에서 where절 사용하기

var temperature = 60
switch (temperature)
{
case 0...49 where temperature % 2 == 0:
print("Cold and even")
case 50...79 where temperature % 2 == 0:
print("Warm and even")
case 80...110 where temperature % 2 == 0:
print("Hot and even")
default:
print("Temperature out of range or odd")
}
//과제 : where절 예제 하나 만들기



// 숫자 변수를 정의
var number = 15

// switch 문을 사용하여 number의 값을 평가
switch number {
case 1...10 where number % 2 == 0:
    print("Number is between 1 and 10 and is even.")
case 1...10 where number % 2 != 0:
    print("Number is between 1 and 10 and is odd.")
case 11...20 where number % 2 == 0:
    print("Number is between 11 and 20 and is even.")
case 11...20 where number % 2 != 0:
    print("Number is between 11 and 20 and is odd.")
default:
    print("Number is out of range.")
}

// 출력 결과:
// Number is between 11 and 20 and is odd.

fallthrough

var value = 4
switch (value)
{
case 4:
print("4")
fallthrough
case 3:
print("3")
fallthrough
case 2:
print("2")
fallthrough
default:
print("1")
}

함수

// 함수 정의부의 값을 매개변수, 호출시의 값은 아규먼트라고 부름
#include <stdio.h>
void Fun( int param ) // parameter(매개변수, 인자), 형식 매개변수(formal parameter)
{
printf("%d",param);
}
int main()
{
Fun( 10 ); // 10은 argument(전달인자), 실 매개변수(actual parameter)
return 0;
}

 

 

함수 선언 방법

//매개변수를 받지 않으며 결과를 반환하지도 않고 오직 메시지만 출력
func sayHello() { //리턴값 없으면( -> Void ) 지정하지 않아도 됨
print("Hello")
}
void sayHello() { //C, C++
printf("Hello");
}
//하나의 문자열과 하나의 정수를 매개변수로 받아서 문자열을 반환
func message(name: String, age: Int) -> String {
return("\(name) \(age)")
}

 

 

c->swift

//c
int add(int x, int y) { //C, C++
return(x+y);
}
add(10,20);

//swift
func add(x: Int, y: Int) -> Int {
return(x+y)
}
print(add(x:10, y:20))//30
print(type(of:add))//(Int,Int)->Int

 

'Swift' 카테고리의 다른 글

iOS실무 프로그래밍 4주차  (0) 2025.03.26
iOS프로그래밍 실무 3주차  (0) 2025.03.19
iOS 프로그래밍 실무 1주차  (0) 2025.03.05
iOS 기초 프로그래밍15주차  (0) 2024.12.11
iOS 기초 프로그래밍 14주차  (0) 2024.12.04

-프론트엔드 신입개발자 질문&답변

 

뤼튼

 

HTML이란 무엇인가요?

HTML은 웹 페이지의 구조를 정의하는 마크업 언어입니다.
CSS의 역할은 무엇인가요?

CSS는 웹 페이지의 스타일을 지정하는 데 사용됩니다.
JavaScript란 무엇인가요?

JavaScript는 웹 페이지에 동적인 기능을 추가하는 프로그래밍 언어입니다.
반응형 웹 디자인이란 무엇인가요?

다양한 기기에서 웹 페이지가 잘 보이도록 설계하는 방법입니다.
DOM이란 무엇인가요?

DOM은 문서 객체 모델로, 웹 페이지의 구조를 나타내는 객체입니다.
AJAX란 무엇인가요?

비동기적으로 웹 페이지를 업데이트할 수 있게 해주는 기술입니다.
RESTful API란 무엇인가요?

REST 원칙에 따라 설계된 웹 서비스 API입니다.
프레임워크와 라이브러리의 차이점은 무엇인가요?

프레임워크는 전체 구조를 제공하고, 라이브러리는 특정 기능을 제공합니다.
CSS Flexbox란 무엇인가요?

요소들을 효율적으로 배치할 수 있는 CSS 레이아웃 모듈입니다.
CSS Grid란 무엇인가요?

2차원 레이아웃을 구성할 수 있는 CSS 모듈입니다.
브라우저 호환성이란 무엇인가요?

다양한 브라우저에서 웹 페이지가 동일하게 작동하는 것을 의미합니다.
SEO란 무엇인가요?

검색 엔진 최적화를 통해 웹 사이트의 가시성을 높이는 과정입니다.
버전 관리 시스템이란 무엇인가요?

코드 변경 사항을 추적하고 관리하는 시스템입니다. (예: Git)
모듈화란 무엇인가요?

코드를 독립적인 모듈로 나누어 관리하는 방법입니다.
CORS란 무엇인가요?

Cross-Origin Resource Sharing의 약자로, 다른 출처의 리소스에 접근할 수 있게 해주는 메커니즘입니다.
Webpack이란 무엇인가요?

JavaScript 애플리케이션의 모듈 번들러입니다.
프론트엔드 성능 최적화 방법은 무엇인가요?

이미지 최적화, 코드 분할, 캐싱 등을 사용할 수 있습니다.
프로미스란 무엇인가요?

비동기 작업의 완료 또는 실패를 나타내는 객체입니다.
ES6의 주요 특징은 무엇인가요?

화살표 함수, 클래스, 템플릿 리터럴, 모듈 등이 포함됩니다.
웹 접근성이란 무엇인가요?

장애인 포함 모든 사용자가 웹을 이용할 수 있도록 하는 설계 원칙입니다.

 

 


perplexity

 

HTML/CSS 관련 질문

  1. Q: HTML5의 새로운 기능은 무엇인가요?
    A: 시맨틱 태그, 멀티미디어 지원, 캔버스, 로컬 스토리지 등
  2. Q: 시맨틱 태그의 장점은?
    A: 검색엔진 최적화, 코드 가독성 향상, 접근성 개선
  3. Q: CSS Box Model이란?
    A: 콘텐츠, 패딩, 보더, 마진으로 구성된 요소의 레이아웃 모델
  4. Q: Flexbox와 Grid의 차이점은?
    A: Flexbox는 1차원, Grid는 2차원 레이아웃 시스템
  5. Q: CSS 선택자 우선순위는?
    A: !important > 인라인 스타일 > ID > 클래스 > 태그

JavaScript 관련 질문

  1. Q: var, let, const의 차이점은?
    A: 스코프와 재선언/재할당 가능 여부의 차이
  2. Q: 호이스팅이란?
    A: 변수와 함수 선언이 스코프 최상단으로 끌어올려지는 현상
  3. Q: 클로저란?
    A: 외부 함수의 변수에 접근할 수 있는 내부 함수
  4. Q: 이벤트 버블링과 캡처링의 차이는?
    A: 이벤트 전파 방향의 차이 (상향 vs 하향)
  5. Q: Promise란?
    A: 비동기 작업의 최종 완료 또는 실패를 나타내는 객체

프레임워크/라이브러리 관련 질문

  1. Q: React의 특징은?
    A: 가상 DOM, 컴포넌트 기반 구조, 단방향 데이터 흐름
  2. Q: Vue.js의 장점은?
    A: 학습 곡선이 낮고, 가볍고 유연함
  3. Q: Angular의 특징은?
    A: TypeScript 사용, 양방향 데이터 바인딩, 의존성 주입
  4. Q: Redux의 핵심 개념은?
    A: 단일 스토어, 액션, 리듀서, 불변성
  5. Q: jQuery와 모던 JavaScript의 차이점은?
    A: DOM 조작 방식, 브라우저 호환성, 성능 등의 차이

성능 최적화 관련 질문

  1. Q: 웹 성능 최적화 방법은?
    A: 이미지 최적화, 코드 분할, 캐싱, CDN 사용 등
  2. Q: 브라우저 렌더링 과정은?
    A: DOM 생성 > CSSOM 생성 > 렌더 트리 구축 > 레이아웃 > 페인트
  3. Q: 크리티컬 렌더링 패스란?
    A: 브라우저가 HTML을 화면에 렌더링하는 데 필요한 단계들
  4. Q: 레이지 로딩이란?
    A: 필요한 시점에 리소스를 로드하는 기술
  5. Q: 디바운싱과 쓰로틀링의 차이는?
    A: 이벤트 호출 제어 방식의 차이 (마지막 호출 vs 일정 간격)

GROK

HTML/CSS 관련 질문 (20개)

  1. HTML5의 새로운 기능은 무엇인가요?
    • 시맨틱 태그(<header>, <footer> 등), <canvas>, <video>, 로컬 스토리지 등입니다.
  2. 시맨틱 HTML이 왜 중요한가요?
    • SEO와 접근성을 개선하고, 코드 가독성을 높여줍니다.
  3. CSS에서 box-sizing 속성은 무엇인가요?
    • 요소의 크기 계산 방식을 정의하며, border-box는 패딩과 테두리를 포함합니다.
  4. Flexbox와 Grid의 차이점은 무엇인가요?
    • Flexbox는 1차원 레이아웃(행 또는 열), Grid는 2차원 레이아웃(행과 열)을 다룹니다.
  5. 반응형 디자인을 어떻게 구현하나요?
    • 미디어 쿼리, 상대 단위(%, vw, rem), 유연한 레이아웃을 사용합니다.
  6. CSS에서 position: absoluterelative의 차이는?
    • relative는 원래 위치 기준, absolute는 부모 요소 기준으로 배치됩니다.
  7. CSS 선택자의 우선순위는 어떻게 결정되나요?
    • Specificity(특이도)와 순서에 따라 결정되며, !important가 가장 높습니다.
  8. BEM 방법론에 대해 설명해주세요.
    • Block, Element, Modifier로 클래스를 구조화해 가독성과 유지보수를 개선합니다.
  9. CSS에서 z-index는 무엇인가요?
    • 요소의 쌓임 순서를 정의하며, 값이 클수록 위에 표시됩니다.
  10. 브라우저 호환성을 어떻게 해결하나요?
    • Vendor 접두사(-webkit-, -moz-)와 폴리필을 사용합니다.
  11. CSS 전처리기(Preprocessor)란 무엇인가요?
    • Sass, Less처럼 변수와 믹스인을 사용해 CSS를 효율적으로 작성하게 해줍니다.
  12. CSS에서 float의 역할은?
    • 요소를 좌우로 띄워 텍스트가 주위를 감싸게 합니다.
  13. clearfix란 무엇인가요?
    • float로 발생한 부모 요소 붕괴를 해결하기 위한 기법입니다.
  14. CSS에서 display: nonevisibility: hidden의 차이는?
    • display: none은 공간까지 제거, visibility: hidden은 공간은 남깁니다.
  15. HTML에서 alt 속성은 왜 중요한가요?
    • 이미지 로드 실패 시 대체 텍스트를 제공하고, 접근성을 높입니다.
  16. CSS에서 remem 단위의 차이는?
    • rem은 루트 폰트 크기 기준, em은 부모 요소 폰트 크기 기준입니다.
  17. CSS 애니메이션은 어떻게 만드나요?
    • @keyframesanimation 속성을 사용합니다.
  18. 미디어 쿼리란 무엇인가요?
    • 화면 크기나 디바이스 조건에 따라 스타일을 적용하는 방법입니다.
  19. CSS에서 overflow 속성은 무엇인가요?
    • 콘텐츠가 요소를 넘칠 때 처리 방법을 정의합니다(예: scroll, hidden).
  20. HTML에서 DOCTYPE의 역할은?
    • 브라우저에 문서 유형을 알려 렌더링 모드를 설정합니다.

JavaScript 관련 질문 (30개)

  1. var, let, const의 차이점은 무엇인가요?
    • var는 함수 스코프, letconst는 블록 스코프이며, const는 재할당 불가입니다.
  2. 클로저(Closure)란 무엇인가요?
    • 함수가 외부 스코프 변수에 접근할 수 있는 현상입니다.
  3. 이벤트 버블링과 캡처링의 차이는?
    • 버블링은 자식에서 부모로, 캡처링은 부모에서 자식으로 이벤트가 전파됩니다.
  4. 호이스팅(Hoisting)이란 무엇인가요?
    • 선언이 스코프 최상단으로 끌어올려지는 JavaScript 동작입니다.
  5. 프로미스(Promise)란 무엇인가요?
    • 비동기 작업의 성공/실패를 처리하는 객체입니다.
  6. async/await의 역할은?
    • 프로미스를 더 간결하게 작성할 수 있게 해줍니다.
  7. this 키워드는 어떻게 동작하나요?
    • 호출 방식에 따라 참조 대상이 달라집니다(예: 객체 메서드면 해당 객체).
  8. 이벤트 루프(Event Loop)란 무엇인가요?
    • 비동기 작업을 관리하며 콜 스택과 큐를 조율합니다.
  9. 화살표 함수와 일반 함수의 차이는?
    • 화살표 함수는 this를 바인딩하지 않습니다.
  10. Array.map과 Array.forEach의 차이는?
    • map은 새 배열을 반환하고, forEach는 반환값이 없습니다.

ios 개발 스택 중요도 순서>

 

Swift - 30%

iOS 앱 개발의 주요 프로그래밍 언어입니다.
Xcode - 20%

iOS 앱 개발을 위한 통합 개발 환경(IDE)입니다.
UIKit - 15%

iOS의 기본 사용자 인터페이스 프레임워크입니다.
SwiftUI - 10%

최신 UI 프레임워크로, 선언적 방식으로 UI를 구축할 수 있습니다.
CocoaPods / Swift Package Manager - 5%

외부 라이브러리 관리 도구입니다.
RESTful API - 5%

서버와 통신하기 위한 API 이해가 필요합니다.
Core Data - 5%

데이터 관리를 위한 프레임워크입니다.
Git - 5%

버전 관리 시스템으로 팀 협업에 필수적입니다.
Testing (XCTest) - 3%

애플리케이션의 품질 보장을 위한 테스트 프레임워크입니다.
App Store 배포 - 2%

 


hello, world 앱을 만드는 간단한 ios 예제>

 

<스토리보드 사용하기>

 

  1. 프로젝트 생성:

    Xcode를 열고 "Create a new Xcode project"를 선택합니다.
    "App"을 선택하고 "Storyboard"를 선택합니다.
  2. UI 구성:

    Main.storyboard 파일을 열고, View Controller를 선택합니다.
    왼쪽 패널에서 "Label"을 드래그하여 View Controller에 추가합니다.
    Label의 텍스트를 "Hello, World!"로 변경합니다.
  3. 앱 실행:

    Command + R을 눌러 앱을 실행합니다.

 

 코드로 만들기

 

  1. 프로젝트 생성:

    Xcode를 열고 "Create a new Xcode project"를 선택합니다.
    "App"을 선택하고 "Swift"와 "UIKit"을 선택합니다.
  2. 코드 작성:

    ViewController.swift 파일을 열고, viewDidLoad 메서드에 아래 코드를 추가합니다.
    swift


import UIKit

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let label = UILabel()
        label.text = "Hello, World!"
        label.textAlignment = .center
        label.frame = CGRect(x: 0, y: 0, width: 300, height: 50)
        label.center = view.center
        view.addSubview(label)
    }
}

3.앱 실행:

Command + R을 눌러 앱을 실행합니다.

 

<SwiftUI 사용하기>

 

  1. 프로젝트 생성:

    Xcode를 열고 "Create a new Xcode project"를 선택합니다.
    "App"을 선택하고 "SwiftUI"를 선택합니다.
  2. 코드 작성:

    ContentView.swift 파일을 열고 아래 코드를 작성합니다.
import SwiftUI

struct ContentView: View {
    var body: some View {
        Text("Hello, World!")
            .font(.largeTitle)
            .padding()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

3. 앱 실행:

Command + R을 눌러 앱을 실행합니다.

 


스토리보드, 코드, SwiftUI의 장단점을 비교>

 

 

 

물음표가 두개가 있는 연산자(셤)

예시)

let optionalValue: String? = nil // 옵셔널 문자열 변수, 현재 nil로 초기화
let defaultValue = "기본 값" // 기본 값 문자열 변수

// nil-coalescing 연산자 사용
let result = optionalValue ?? defaultValue // optionalValue가 nil이면 defaultValue를 사용

print(result) // 결과 출력: 기본 값

https://bbiguduk.gitbook.io/swift

 

The Swift Programming Language (한국어) | Swift

Last updated 5 months ago

bbiguduk.gitbook.io

 

이름 10번 출력

let name = "홍길동" // 출력할 이름

// 0부터 9까지 반복
for _ in 0..<10 {
    print(name) // 이름 출력
}

'Swift' 카테고리의 다른 글

iOS프로그래밍 실무 3주차  (0) 2025.03.19
iOS 프로그래밍 실무 2주차  (0) 2025.03.17
iOS 기초 프로그래밍15주차  (0) 2024.12.11
iOS 기초 프로그래밍 14주차  (0) 2024.12.04
iOS 프로그래밍 기초 13주차  (0) 2024.11.27

add1의 자료형
extraneous필요x

후행 클로저는 뒤쪽에 중괄호 열고 닫기

후행클로저 까지 시험

func add(x:Int, y:Int)->Int{
    return x+y
}
print(add(x: 3, y: 5))
print(type(of: add))
let add1 = { (x:Int, y:Int)->Int in
    return x+y
}
print(add1(2,3))
func math(x: Int, y: Int, cal: (Int, Int) -> Int) -> Int {
return cal(x, y)//add1(1,2)
}
print(math(x:1,y:2,cal:add1))
var a = math(x: 10, y: 20, cal: { (x:Int, y:Int)->Int in
    return x+y
})//a라는 상수에 넣음/let은 처음 값을 아래서 못 바꿈 그래서 var
print(a)
a = math(x: 100, y: 200) {(x:Int, y:Int)->Int in
return x+y
}//후행클로저
print(a)
math(x: 10, y: 20, cal: { (x:Int, y:Int)->Int in
    return x+y
})//후행클로저 전
math(x: 10, y: 20) { (x:Int, y:Int)->Int in
    return x+y
}//후행클로저 후/ 중괄호 열고 닫기를 뒤쪽에 쓸 수 있음

 

 

 

 

 

 

 

출처: 한성현교수님 수업자료

'Swift' 카테고리의 다른 글

iOS 프로그래밍 실무 2주차  (0) 2025.03.17
iOS 프로그래밍 실무 1주차  (0) 2025.03.05
iOS 기초 프로그래밍 14주차  (0) 2024.12.04
iOS 프로그래밍 기초 13주차  (0) 2024.11.27
iOS 기초 프로그래밍 12주차  (0) 2024.11.20

Auto Layout:

Auto Layout의 핵심은 제약조건(Constraints) 입니다. 제약조건은 UI 요소 간의 관계를 정의하는 규칙입니다. 예를 들어, 버튼이 화면의 상단에서 50pt 떨어져야 한다거나, 두 뷰가 가로로 일정 비율로 정렬되어야 한다는 규칙을 설정할 수 있습니다.

 

1방법 :

alignment constraints 설정하기

정가운데로 옮기는법

selected view
stack view를 가장 많이 씀
viewcontroller가져올때 이름바꿔서 가져오기
새로 가져온거 class를 sketchviewcontroller바꾸기

tab bar controller 잡고 ctrl로 sketch로 끌어다가 view controllers

 

 

 

 

출처: 한성현 교수님 수업자료

'Swift' 카테고리의 다른 글

iOS 프로그래밍 실무 1주차  (0) 2025.03.05
iOS 기초 프로그래밍15주차  (0) 2024.12.11
iOS 프로그래밍 기초 13주차  (0) 2024.11.27
iOS 기초 프로그래밍 12주차  (0) 2024.11.20
iOS 프로그래밍 기초 11주차  (0) 2024.11.13

-xcode에서 피일 delete하려면 move to trash해야됨

 

(Identity inspecter)class 연결 해줘야됨 Video ViewController, 반드시enter(enter

Identity inspector: video Scene 스토리 보드와 VideoViewController클래스 연결

 

시험

present 함수는 iOS의 UIKit 프레임워크에서 제공하는 메서드로, 현재의 뷰 컨트롤러에서 다른 뷰 컨트롤러를 모달 방식으로 표시하는 데 사용됩니다. 이 메서드는 사용자 인터페이스의 흐름을 관리하는 데 중요한 역할을 하며, 새로운 화면을 사용자에게 보여줄 때 주로 사용됩니다.

 

//
//  VideoViewController.swift
//  BMI_kdh
//
//  Created by 소프트웨어컴퓨터 on 2024/11/27.
//

import UIKit // UIKit 프레임워크를 임포트하여 UI 요소를 사용할 수 있게 합니다.
import AVKit // AVKit 프레임워크를 임포트하여 비디오 재생 기능을 사용할 수 있게 합니다.

class VideoViewController: UIViewController { // VideoViewController 클래스를 정의하며 UIViewController를 상속받습니다.

    @IBAction func playVideo(_ sender: UIButton) { // 버튼 클릭 시 호출되는 액션 메서드입니다.
        // 비디오 파일의 경로를 가져옵니다. APT.mp4 파일이 번들에 존재하는지 확인합니다.
        let videoPath: String? = Bundle.main.path(forResource: "APT", ofType: "mp4")
        
        // 비디오 파일 경로가 nil이 아닐 경우에만 진행합니다.
        guard let path = videoPath else {
            print("비디오 파일을 찾을 수 없습니다.") // 비디오 파일이 없을 경우 에러 메시지를 출력합니다.
            return // 비디오 파일이 없으면 함수 실행을 종료합니다.
        }
        
        // 비디오 파일의 URL을 생성합니다. URL(filePath:)는 파일 경로를 URL로 변환합니다.
        let videoURL = URL(fileURLWithPath: path)
        
        // AVPlayer 인스턴스를 생성하여 비디오 URL을 전달합니다.
        let player = AVPlayer(url: videoURL)
        
        // AVPlayerViewController 인스턴스를 생성하여 비디오 플레이어 UI를 표시합니다.
        let playerController = AVPlayerViewController()
        playerController.player = player // 생성한 AVPlayer를 playerController에 할당합니다.
        
        // 비디오 플레이어 화면을 모달로 표시합니다.
        present(playerController, animated: true) { 
            player.play() // 비디오 재생을 시작합니다.
        }
    }
    
    override func viewDidLoad() { // 뷰가 메모리에 로드된 후 호출되는 메서드입니다.
        super.viewDidLoad() // 부모 클래스의 viewDidLoad 메서드를 호출합니다.
        // 추가적인 설정을 여기에 작성할 수 있습니다.
    }
}

 

 

 

//
//  VideoViewController.swift
//  BMI_kdh
//
//  Created by 소프트웨어컴퓨터 on 2024/11/27.
//

import UIKit
import AVKit
class VideoViewController: UIViewController {

    @IBAction func playVideo(_ sender: UIButton) {
        guard let videoPath = Bundle.main.path(forResource: "APT", ofType: "mp4")else{return} //옵셔널 형을 풀기 위해서 guard let사용
        let videoURL = URL(filePath: videoPath)
        let player = AVPlayer(url: videoURL)
        let playerController = AVPlayerViewController()
        playerController.player = player
        present(playerController, animated: true)//시험
        player.play()
        //            // 비디오 파일의 URL을 가져옵니다.
//            guard let videoURL = Bundle.main.url(forResource: "APT", withExtension: "mp4") else {
//                print("비디오 파일을 찾을 수 없습니다.")
//                return
//            }
//
//            // AVPlayer와 AVPlayerViewController를 생성합니다.
//            let player = AVPlayer(url: videoURL)
//            let playerViewController = AVPlayerViewController()
//            playerViewController.player = player
//
//            // 비디오 플레이어 화면을 표시합니다.
//            present(playerViewController, animated: true) {
//                player.play() // 비디오 재생 시작
//            }
//        }
//
//        override func viewDidLoad() {
//            super.viewDidLoad()
            // Do any additional setup after loading the view.
        }
    }

옵셔널 형을 풀기 위해서 guard let사용

 

enter키 누르면 ↓

 

 

디폴트 인자(default arguments)는 함수나 메서드를 호출할 때 인자를 생략할 수 있도록 해주는 기능입니다. 각 프로그래밍 언어에서 디폴트 인자를 사용하는 방법을 예)

 

1. Python
Python에서는 함수 정의 시 인자에 기본값을 설정할 수 있습니다.

def greet(name="Guest"):
    print(f"Hello, {name}!")

greet()          # 출력: Hello, Guest!
greet("Alice")  # 출력: Hello, Alice!

 

 

2. JavaScript
JavaScript에서도 ES6부터 함수 매개변수에 기본값을 설정할 수 있습니다.

function greet(name = "Guest") {
    console.log(`Hello, ${name}!`);
}

greet();          // 출력: Hello, Guest!
greet("Alice");  // 출력: Hello, Alice!

 

3. Swift
Swift에서는 함수의 매개변수에 기본값을 설정할 수 있습니다.

func greet(name: String = "Guest") {
    print("Hello, \(name)!")
}

greet()          // 출력: Hello, Guest!
greet(name: "Alice")  // 출력: Hello, Alice!

 

 

-내장 웹브라우저 

 

 

 

 

 

//
//  AppDelegate.swift
//  BMI_kdh
//
//  Created by 소프트웨어컴퓨터 on 2024/11/13.
//

import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {



    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        return true
    }

    // MARK: UISceneSession Lifecycle

    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        // Called when a new scene session is being created.
        // Use this method to select a configuration to create the new scene with.
        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
    }

    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
        // Called when the user discards a scene session.
        // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
        // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
    }


}

refactoring하기

 

 

//
//  WebViewController.swift
//  BMI_kdh
//
//  Created by 소프트웨어컴퓨터 on 2024/11/27.
//

import UIKit
import WebKit

/// `WebViewController`는 웹 페이지를 표시하는 뷰 컨트롤러입니다.
class WebViewController: UIViewController {

    /// WKWebView 인스턴스. 웹 콘텐츠를 표시하는 뷰입니다.
    @IBOutlet weak var webView: WKWebView!

    /// 뷰가 로드될 때 호출되는 메서드.
    /// 초기 웹 페이지를 로드합니다.
    override func viewDidLoad() {
        super.viewDidLoad()
        loadURL("https://hhh08.tistory.com/") // 초기 로드할 URL
    }

    /// Naver 버튼이 클릭될 때 호출되는 액션 메서드.
    /// Naver 모바일 사이트를 로드합니다.
    /// - Parameter sender: 버튼 클릭 이벤트의 발신자
    @IBAction func goNaver(_ sender: UIButton) {
        loadURL("https://m.naver.com") // Naver 모바일 사이트 로드
    }

    /// 주어진 URL 문자열을 사용하여 웹 페이지를 로드하는 메서드.
    /// - Parameter urlString: 로드할 웹 페이지의 URL 문자열
    private func loadURL(_ urlString: String) {
        // URL 문자열을 URL 객체로 변환
        guard let url = URL(string: urlString) else { return }
        // URLRequest 객체 생성
        let request = URLRequest(url: url)
        // 웹 뷰에 요청 로드
        webView.load(request)
    }

    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destination.
        // Pass the selected object to the new view controller.
    }
    */
}

webviewcontroller문서화하기

 

//
//  VideoViewController.swift
//  BMI_kdh
//
//  Created by 소프트웨어컴퓨터 on 2024/11/27.
//

import UIKit
import AVKit

/// `VideoViewController`는 비디오를 재생하는 뷰 컨트롤러입니다.
class VideoViewController: UIViewController {

    /// 비디오 재생 버튼이 클릭될 때 호출되는 액션 메서드.
    /// - Parameter sender: 버튼 클릭 이벤트의 발신자
    @IBAction func playVideo(_ sender: UIButton) {
        // 비디오 파일의 경로를 가져옵니다. 파일이 존재하지 않으면 메서드를 종료합니다.
        guard let videoPath = Bundle.main.path(forResource: "APT", ofType: "mp4") else { return }
        
        // 비디오 파일의 URL을 생성합니다.
        let videoURL = URL(fileURLWithPath: videoPath)
        
        // AVPlayer 인스턴스를 생성하여 비디오 URL을 설정합니다.
        let player = AVPlayer(url: videoURL)
        
        // AVPlayerViewController 인스턴스를 생성합니다.
        let playerController = AVPlayerViewController()
        playerController.player = player
        
        // 비디오 플레이어 화면을 모달로 표시하고, 표시가 완료된 후 비디오 재생을 시작합니다.
        self.present(playerController, animated: true) {
            player.play() // 비디오 재생 시작
        }
    }

    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destination.
        // Pass the selected object to the new view controller.
    }
    */
}

 

videoviewcontroller문서화하기

//
//  ViewController.swift
//  BMI_kdh
//
//  Created by 소프트웨어컴퓨터 on 2024/11/13.
//

import UIKit

/// `ViewController`는 BMI(체질량지수)를 계산하고 결과를 표시하는 뷰 컨트롤러입니다.
class ViewController: UIViewController {
    
    // 사용자로부터 키와 체중을 입력받기 위한 UI 요소
    @IBOutlet weak var txtHeight: UITextField! // 키 입력 필드
    @IBOutlet weak var txtWeight: UITextField! // 체중 입력 필드
    @IBOutlet weak var lblResult: UILabel! // BMI 결과를 표시할 레이블

    /// BMI 계산 버튼이 클릭될 때 호출되는 액션 메서드.
    /// - Parameter sender: 버튼 클릭 이벤트의 발신자
    @IBAction func calcBmi(_ sender: UIButton) {
        // 키와 체중 입력 필드가 비어 있는지 확인합니다.
        if txtHeight.text == "" || txtWeight.text == "" {
            lblResult.textColor = .red // 텍스트 색상을 빨간색으로 설정
            lblResult.text = "키와 체중을 입력하세요!" // 안내 메시지 표시
            return
        } else {
            // 입력된 체중과 키를 Double로 변환합니다.
            let weight = Double(txtWeight.text!)!
            let height = Double(txtHeight.text!)!
            // BMI 계산 (kg/m²)
            let bmi = weight / (height * height * 0.0001) // height는 cm 단위이므로 0.0001로 나눔
            let shortenedBmi = String(format: "%.1f", bmi) // 소수점 첫째 자리까지 포맷팅
            
            var body = "" // BMI 판정 결과를 저장할 변수
            var color = UIColor.white // 초기값으로 흰색 설정
            
            // BMI 값에 따라 판정 및 색상 설정
            if bmi >= 40 {
                color = UIColor(displayP3Red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0) // 3단계 비만: 빨간색
                body = "3단계 비만"
            } else if bmi >= 30 && bmi < 40 {
                color = UIColor(displayP3Red: 0.7, green: 0.0, blue: 0.0, alpha: 1.0) // 2단계 비만: 어두운 빨간색
                body = "2단계 비만"
            } else if bmi >= 25 && bmi < 30 {
                color = UIColor(displayP3Red: 0.4, green: 0.0, blue: 0.0, alpha: 1.0) // 1단계 비만: 중간 빨간색
                body = "1단계 비만"
            } else if bmi >= 18.5 && bmi < 25 {
                color = UIColor(displayP3Red: 0.0, green: 0.0, blue: 1.0, alpha: 1.0) // 정상: 파란색
                body = "정상"
            } else {
                color = UIColor(displayP3Red: 0.0, green: 1.0, blue: 0.0, alpha: 1.0) // 저체중: 초록색
                body = "저체중"
            }
            
            // 결과 레이블의 배경색과 텍스트 설정
            lblResult.backgroundColor = color
            lblResult.clipsToBounds = true // 레이블의 경계가 둥글게 설정
            lblResult.layer.cornerRadius = 10 // 레이블의 모서리를 둥글게 설정
            lblResult.text = "BMI:\(shortenedBmi), 판정: \(body)" // 최종 결과 표시
        }
    }

    /// 뷰가 로드될 때 호출되는 메서드.
    override func viewDidLoad() {
        super.viewDidLoad()
        // 추가적인 설정을 여기에 작성할 수 있습니다.
    }
}

 

viewcontroller문서화하기

 

출처: 한성현 교수님 수업자료

'Swift' 카테고리의 다른 글

iOS 기초 프로그래밍15주차  (0) 2024.12.11
iOS 기초 프로그래밍 14주차  (0) 2024.12.04
iOS 기초 프로그래밍 12주차  (0) 2024.11.20
iOS 프로그래밍 기초 11주차  (0) 2024.11.13
iOS 기초 프로그래밍 10주차  (0) 2024.11.06

issue navigator이 떴을때 iOS에서  UI 요소의 위치와 크기를 동적으로 조정하기 위한 시스템 인  오토 레이아웃(Autolayout)이 필요

//
//  ViewController.swift
//  BMI_kdh
//
//  Created by 소프트웨어컴퓨터 on 2024/11/13.
//

import UIKit

class ViewController: UIViewController {
    
    @IBOutlet weak var txtHeight: UITextField!
    @IBOutlet weak var txtWeight: UITextField!
    @IBOutlet weak var lblResult: UILabel!
    @IBAction func calcBmi(_ sender: UIButton) {
        let weight = 60.0
        let height = 170.0
        let bmi = weight / (height*height*0.0001) // kg/m*m
        let shortenedBmi = String(format: "%.1f", bmi)
        var body = ""
        if bmi >= 40 {
            body = "3단계 비만"
        } else if bmi >= 30 && bmi < 40 {
            body = "2단계 비만"
        } else if bmi >= 25 && bmi < 30 {
            body = "1단계 비만"
        } else if bmi >= 18.5 && bmi < 25 {
            body = "정상"
        } else {
            body = "저체중"
        }
        print("BMI:\(shortenedBmi), 판정:\(body)")
        
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }
    
    
}

버튼을 누를때 앱에서는 안보이고 debug area에  보임

//
//  ViewController.swift
//  BMI_kdh
//
//  Created by 소프트웨어컴퓨터 on 2024/11/13.
//

import UIKit

class ViewController: UIViewController {
    
    @IBOutlet weak var txtHeight: UITextField!
    @IBOutlet weak var txtWeight: UITextField!
    @IBOutlet weak var lblResult: UILabel!
    @IBAction func calcBmi(_ sender: UIButton) {
        let weight = Double(txtWeight.text!)!//txtWeight.text은 옵셔널 string임 강제 언래핑!해야됨, double도 강제 언래핑! /text필드에 둘 다 값을 넣지 않으면 crash가 남
        let height = Double(txtHeight.text!)!
        let bmi = weight / (height*height*0.0001) // kg/m*m
        let shortenedBmi = String(format: "%.1f", bmi)
        var body = ""
        if bmi >= 40 {
            body = "3단계 비만"
        } else if bmi >= 30 && bmi < 40 {
            body = "2단계 비만"
        } else if bmi >= 25 && bmi < 30 {
            body = "1단계 비만"
        } else if bmi >= 18.5 && bmi < 25 {
            body = "정상"
        } else {
            body = "저체중"
        }
        print("BMI:\(shortenedBmi), 판정:\(body)")
        lblResult.text = "BMI:\(shortenedBmi), 판정: \(body)"
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }
    
    
}
let height = Double(txtHeight.text!)!
let weight = Double(txtWeight.text!)!

첫 번째 !: txtHeight.text와 txtWeight.text는 옵셔널(Optional) 타입입니다. 즉, 이 값이 nil일 수도 있음을 나타냅니다. !를 사용하여 이 옵셔널 값을 강제로 언래핑하여 실제 문자열 값을 가져옵니다. 만약 이 값이 nil이라면 런타임 오류가 발생합니다.

두 번째 !: Double(txtHeight.text!)와 Double(txtWeight.text!)는 문자열을 Double 타입으로 변환하는 시도입니다. 문자열이 숫자로 변환될 수 없는 경우 nil이 반환됩니다. 따라서 이 값을 다시 강제로 언래핑하여 Double 값을 가져옵니다. 이 경우에도 nil이라면 런타임 오류가 발생합니다.

 

<guard let을 사용하여 코드 수정>

guard let heightText = txtHeight.text, 
      let height = Double(heightText) else {
    print("Height 입력값이 올바르지 않습니다.")
    return
}

print("Height: \(height)")

guard let weightText = txtWeight.text, 
      let weight = Double(weightText) else {
    print("Weight 입력값이 올바르지 않습니다.")
    return
}

print("Weight: \(weight)")
//
//  ViewController.swift
//  BMI_kdh
//
//  Created by 소프트웨어컴퓨터 on 2024/11/13.
//

import UIKit

class ViewController: UIViewController {
    
    @IBOutlet weak var txtHeight: UITextField!
    @IBOutlet weak var txtWeight: UITextField!
    @IBOutlet weak var lblResult: UILabel!
    @IBAction func calcBmi(_ sender: UIButton) {
        if txtHeight.text == "" || txtWeight.text == "" {//값이 없으면 안내문이 뜨고 , 색을 red 로 지정함
            lblResult.textColor = .red
            lblResult.text = "키와 체중을 입력하세요!"
            return
        }else{
            let weight = Double(txtWeight.text!)!
            let height = Double(txtHeight.text!)!
            let bmi = weight / (height*height*0.0001) // kg/m*m
            let shortenedBmi = String(format: "%.1f", bmi)
            var body = ""
            if bmi >= 40 {
                body = "3단계 비만"
            } else if bmi >= 30 && bmi < 40 {
                body = "2단계 비만"
            } else if bmi >= 25 && bmi < 30 {
                body = "1단계 비만"
            } else if bmi >= 18.5 && bmi < 25 {
                body = "정상"
            } else {
                body = "저체중"
            }
            print("BMI:\(shortenedBmi), 판정:\(body)")
            lblResult.text = "BMI:\(shortenedBmi), 판정: \(body)"
        }
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }
    
    
}

전체 선택후 ctrl +i : 소스 정렬

 

//
//  ViewController.swift
//  BMI_kdh
//
//  Created by 소프트웨어컴퓨터 on 2024/11/13.
//

import UIKit

class ViewController: UIViewController {
    
    @IBOutlet weak var txtHeight: UITextField! // 키 입력 필드
    @IBOutlet weak var txtWeight: UITextField! // 체중 입력 필드
    @IBOutlet weak var lblResult: UILabel! // 결과를 출력할 레이블
    
    @IBAction func calcBmi(_ sender: UIButton) { // BMI 계산 버튼 클릭 시 호출되는 함수
        // 입력값이 비어 있는지 확인
        if txtHeight.text == "" || txtWeight.text == "" {
            lblResult.textColor = .red // 경고 메시지 색상 설정
            lblResult.text = "키와 체중을 입력하세요!" // 안내 메시지 출력
            return // 함수 종료
        } else {
            // 입력된 키와 체중을 Double로 변환
            let weight = Double(txtWeight.text!)!
            let height = Double(txtHeight.text!)!
            // BMI 계산 (kg/m²)
            let bmi = weight / (height * height * 0.0001) 
            let shortenedBmi = String(format: "%.1f", bmi) // 소수점 1자리로 포맷팅
            
            var body = "" // BMI 판정을 저장할 변수
            var color = UIColor.white // 초기 배경색을 하얀색으로 설정
            
            // BMI 값에 따른 판정 및 색상 설정
            if bmi >= 40 {
                color = UIColor(displayP3Red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0) // 3단계 비만 (빨간색)
                body = "3단계 비만"
            } else if bmi >= 30 && bmi < 40 {
                color = UIColor(displayP3Red: 0.7, green: 0.0, blue: 0.0, alpha: 1.0) // 2단계 비만 (어두운 빨간색)
                body = "2단계 비만"
            } else if bmi >= 25 && bmi < 30 {
                color = UIColor(displayP3Red: 0.4, green: 0.0, blue: 0.0, alpha: 1.0) // 1단계 비만 (좀 더 어두운 빨간색)
                body = "1단계 비만"
            } else if bmi >= 18.5 && bmi < 25 {
                color = UIColor(displayP3Red: 0.0, green: 0.0, blue: 1.0, alpha: 1.0) // 정상 (파란색)
                body = "정상"
            } else {
                color = UIColor(displayP3Red: 0.0, green: 1.0, blue: 0.0, alpha: 1.0) // 저체중 (초록색)
                body = "저체중"
            }
            
            // 결과 레이블의 배경색 설정
            lblResult.backgroundColor = color
            lblResult.clipsToBounds = true // 레이블의 경계선 처리
            lblResult.layer.cornerRadius = 10 // 레이블의 모서리를 둥글게 설정
            lblResult.text = "BMI:\(shortenedBmi), 판정: \(body)" // 결과 출력
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 뷰가 로드된 후 추가 설정이 필요할 경우 여기에 작성
    }
}

결과 나올때 결과에 따라 배경색이 바뀌는 코드 + 결과 레이블 둥글게하는 코드 추가

 

 

universal: 고해상도 ( 아이패드, 아이폰 사진 전부 가능하게하는 )

tab bar controller 선택하면 화면이 하나 더 생김

 

(apple hig: apple 디자인 가이드라인)

 

tab bar controller 화면을 ctrl누르고 드래그 후 view controllers 누르기

 

**메뉴얼 세그웨이(Manual Segue)**와 **릴레이션 세그웨이(Relationship Segue)**의 차이점

 

 

출처: 한성현 교수님 수업자료

'Swift' 카테고리의 다른 글

iOS 기초 프로그래밍 14주차  (0) 2024.12.04
iOS 프로그래밍 기초 13주차  (0) 2024.11.27
iOS 프로그래밍 기초 11주차  (0) 2024.11.13
iOS 기초 프로그래밍 10주차  (0) 2024.11.06
iOS 기초 프로그래밍 9주차  (0) 2024.10.30

+ Recent posts