Coding Bottle Mobile 01

YEOMI·2023년 9월 12일
0

Swfit - Coding Bottle

목록 보기
1/13

질문 리스트

hanni님의 질문

  • struct와 class와 enum의 차이를 설명하시오.
  • class의 성능을 향상 시킬수 있는 방법들을 나열해보시오.
  • Struct 가 무엇이고 어떻게 사용하는지 설명하시오.

PSY님의 질문

  • class 메서드와 static 메서드의 차이점을 설명하시오.
  • defer란 무엇인지 설명하시오.
  • defer가 호출되는 순서는 어떻게 되고, defer가 호출되지 않는 경우를 설명하시오.

struct와 class와 enum의 차이를 설명하시오.

Swift의 기본 자료구조 블럭으로 키워드 + 이름 + {} 의 방식으로 사용.

class oneClass{
}
struct oneStruct{
}
eunm One{
}

Struct

  • 구조체, 값타입으로 값을 복사.
  • 인스턴스 간 값이 복사되기에 하나의 인스턴스를 변경해도 다른 인스턴스에 영향을 주지 않음.
  • 스택에 값을 저장.
  • 구조체에 멤버 변수를 선언할 때 let 키워드를 사용하면 인스턴스가 불변하게 됨.
  • 상속 불가.

Class

  • 클래스, 참조타입으로 인스턴스가 참조로 전달.
  • 여러 변수가 동일한 인스턴스를 참조할 수 있음.
  • 힙에 값을 저장하고, 스택에 값의 주소를 저장.
  • ARC(Automatic Reference Counting)를 사용하여 메모리를 관리.
  • 단일 상속 가능.

Enum

  • 열거형, 값타입으로 값을 복사.
  • 유사한 종류의 여러 값을 유의미한 이름으로 한 곳에 모아 정의한 것.
  • 값 자체를 스택에 저장.
  • 상속 불가.

나의 질문

  • swfit에서 클래스는 왜 단일상속만 가능한가요?

class의 성능을 향상 시킬수 있는 방법들을 나열해보시오.

Swift에서 클래스는 상속을 지원하기 때문에 오버라이딩의 가능성이 있기에 Dynamic Dispatch로 동작.
-> Dynamic Dispatch(Indirect Call, 동적 디스패치)란 런타임에 호출될 함수를 결정.

상속 가능성이 없거나 오버라이딩이 되지 않는 프로퍼티와 메서드인 경우 효율적이지 않기 때문에 Static Dispatch로 바꿔 주면 성능이 향상.
-> Static Dispatch(Direct Call, 정적 디스패치)란 컴파일 타임에 호출될 함수를 결정하여 런타임 때 그대로 실행. (미리 정해둠.)

Static Dispatch를 이용한 성능 최적화 방법

  • 상속이나 오버라이딩 될 필요 없는 클래스나 메서드, 프로퍼티에 final 사용.

final을 클래스에 사용하면 상속이 불가하고, 메서드나 프로퍼티에 사용하면 하위 클래스에서 오버라이딩을 할 수 없음.

  • WMO((Whole Module Optimization) : 모듈 전체를 하나의 덩어리로 컴파일해서 internal level에 대해 오버라이딩의 여부를 추론할 수 있게 되고, 오버라이딩이 되지 않을 경우 내부적으로 final을 붙임.

Swift는 기본적으로 컴파일을 할 때 모듈 내의 파일을 하나씩 컴파일 함.
-> 컴파일 시점에서는 상속 여부를 확인 불가.

그래서 WMO는 하나의 모듈을 컴파일할 때 모듈 전체를 확인하며 컴파일 함.
-> 하지만 기본 접근 제어자가 internal일 때에만 해당되고, public이나 open인 경우에는 외부 모듈에서도 접근할 수 있기에 WMO를 적용해도 Dynamic Dispatch로 동작.

  • 파일 내에서만 접근해도 된다면 private으로 선언
  • Lazy Initialization을 사용하여 필요한 시점까지 속성의 초기화를 지연시켜 초기화 시간과 리소스를 절약.

Lazy Initialization으로 성능을 향상시킬 수 있는 경우
: 비용이 큰 초기화 또는 연산이 필요한 속성, 데이터베이스 연결 또는 네트워크 호출, 복잡한 계산이나 초기화 로직.

질문

가장 큰 성능 향상의 방법이 어떤 것이라고 생각하나요?

Struct 가 무엇이고 어떻게 사용하는지 설명하시오.

Struct - 구조체

인스턴스의 값(프로퍼티)을 저장하거나 기능(메소드)을 제공하고 이를 캡슐화할 수 있는 스위프트가 제공하는 타입.
간단히 말해서 데이터를 저장하고 전달하는 데 사용됨.

struct MyStruct {
    var property1: DataType
    var property2: DataType

    // 초기화자 및 메소드도 추가 가능
    init(initialValue: DataType) {
        self.property1 = initialValue
        self.property2 = initialValue
    }

    // 다른 메소드 정의
}
  • 구조체, 값타입으로 값을 복사.
  • 인스턴스 간 값이 복사되기에 하나의 인스턴스를 변경해도 다른 인스턴스에 영향을 주지 않음.
  • 스택에 값을 저장.
  • 구조체에 멤버 변수를 선언할 때 let 키워드를 사용하면 인스턴스가 불변하게 됨.
  • 상속 불가.
  • 함수의 매개변수로 전달하거나 반환할 수 있으며, 배열, 딕셔너리 등 컬렉션에 저장할 수 있음.

Initialization - 구조체 초기화

구조체는 구조체 멤버를 파라미터 네임으로하여 스위프트가 자동으로 초기화 코드를 만들어 줌.
초기화 코드를 직접 작성할 수도 있지만, 자동 초기화 코드는 제공받지 못함.

// 간단한 활용 예제

// Point 구조체 정의
struct Point {
    var x: Int
    var y: Int
}

// Point 구조체 인스턴스 생성
var point1 = Point(x: 10, y: 20)
var point2 = Point(x: 5, y: 15)

// 속성 접근
print("point1의 x 좌표: \(point1.x)") // 출력: "point1의 x 좌표: 10"
print("point2의 y 좌표: \(point2.y)") // 출력: "point2의 y 좌표: 15"

이 예제에서 Point 구조체는 x와 y라는 두 개의 정수 속성을 가지고 있음.
구조체 인스턴스 point1과 point2를 생성하고, 속성에 접근하여 해당 값을 출력함.
구조체는 간단한 데이터 유형을 나타내기 위해 사용될 수 있음.

구조체 안의 변수: 프로퍼티(속성)
구조체 안의 함수: 메소드

일반적인 순서

구조체 정의(속성, 메소드)
-> 구조체 인스턴스 생성
-> 속성에 접근(Initializer 호출하여 속성 초기화)
-> 속성에 접근 or 메소드 호출

class 메서드와 static 메서드의 차이점을 설명하시오.

Swift에서 class 메소드와 static 메소드는 둘 다 타입 메소드(Type Method)로 인스턴스가 아닌 타입 자체에 속하는 메소드.
그러나 class 메소드와 static 메소드 사이에 중요한 차이점이 존재.

상속 가능성

class 메소드: 클래스 메소드는 상속 가능하며, 서브클래스에서 오버라이딩(재정의)이 가능.
서브클래스에서 class 메소드를 재정의하려면 class 키워드를 사용.

static 메소드: static 메소드는 상속 불가능하며, 서브클래스에서 재정의할 수 없음.
타입 자체에 속하며 오버라이딩할 수 없음.

다형성

class 메소드: 클래스 메소드는 다형성을 지원하며, 메소드를 호출할 때 실제 객체의 타입에 따라 실행.
클래스의 인스턴스에서 호출할 때 그 클래스의 메소드가 실행되지만, 서브클래스의 인스턴스에서 호출할 때는 서브클래스의 재정의된 메소드가 실행.

static 메소드: static 메소드는 다형성을 지원하지 않으며, 항상 타입 자체에 정의된 메소드가 호출.
타입에 따라 실행되며 객체의 타입에 영향을 받지 않음.

정리하자면 class 메소드는 상속 가능하고 다형성을 지원하며, 서브클래스에서 재정의 가능한 반면, static 메소드는 상속 불가능하고 다형성을 지원하지 않으며 오버라이딩할 수 없음.

defer란 무엇인지 설명하시오.

코드 블록 안에서 어떤 작업을 나중에 실행하도록 지연시키는 데 사용되는 키워드.
defer는 코드 블록 내에서 여러 작업을 수행하는 동안, 특히 현재 범위(scope)를 빠져나가기 직전에 어떤 작업을 실행하고 싶을 때 유용함.
주로 파일이나 리소스를 정리하거나 코드 실행 후 필요한 정리 작업을 수행할 때 사용.

func someFunction() {
    // 코드 블록 시작
    defer {
        // 이 부분에 작성한 코드는 현재 범위를 빠져나가기 직전에 실행됨
        print("작업이 완료되었습니다.")
    }

    // 다른 작업들...
    print("작업 진행 중...")

    // 코드 블록 종료
}

someFunction()
// 출력 순서: "작업 진행 중...", "작업이 완료되었습니다."

함수나 블록 내에서 여러 번 사용할 수 있으며, 작성한 순서대로 실행.
코드 블록이 중첩되어 있을 때는 defer 블록도 중첩되어 있으며, 범위를 빠져나갈 때 가장 가까운 defer 블록부터 실행.

유용한 경우

  • 파일 핸들을 열었을 때, 파일을 닫는 작업을 놓치지 않기 위해 사용.
  • 자원을 할당한 경우, 자원을 해제하는 작업을 수행하기 위해 사용.
  • 함수나 메서드가 정상적으로 종료될 때 항상 필요한 정리 작업을 수행하기 위해 사용.

defer가 호출되는 순서는 어떻게 되고, defer가 호출되지 않는 경우를 설명하시오.

//여러 번 사용된 defer 예제
func exampleFunction() {
    defer {
        print("첫 번째 defer 블록")
    }

    print("1")

    defer {
        print("두 번째 defer 블록")
    }

    print("2")

    defer {
        print("세 번째 defer 블록")
    }

    print("3")
}

exampleFunction()

실행결과

1
2
3
세 번째 defer 블록
두 번째 defer 블록
첫 번째 defer 블록

실행 순서는 가장 마지막에 실행된 defer부터 역순.
여러 번 호출한 경우, 가장 먼저 작성한 defer 블록이 가장 마지막에 실행.

//중첩 defer 예제
func testDefer() {
    defer {
        defer {
            defer {
                print("defer #3")
            }
            print("defer #2")
        }
        print("defer #1")
    }
}

실행 결과

defer #1
defer #2
defer #3

중첩해서 사용한 경우 가장 바깥쪽 defer부터 실행.

호출되지 않는 경우

  • 코드 블록이 실행 중에 에러가 발생하고, 해당 블록이 정상적으로 종료되지 않은 경우. defer 블록은 범위를 빠져나가는 동안 호출되지 않음.
  • 코드가 실행되는 도중에 프로그램이 강제 종료되거나 비정상적으로 중단된 경우.
  • 함수가 반환되지 않는 경우.
    ex) 무한 루프 내에서 함수가 종료되지 않음.

질문

실제 작업에서 defer가 필요한 경우가 언제 있을까요?

profile
뭐라도 좀 해라

0개의 댓글