서론
raywenderlich의 Swift Interview Questions에 답변을 달아보려고 합니다.
Beginner, Intermediate, Advanced로 나뉘어져 있는데
이번 포스팅에서는 Beginner 질문에 대한 답변입니다.
Swift 공부를 하면서 제대로 이해를 했는지, 무엇을 모르는지 알 수 있는
좋은 기회가 될 것 같아요 ㅎ
Question #1
tutorial1의 difficulty는 1, tutorial2의 difficulty는 2입니다.
구조체는 값 타입이기 때문에 인스턴스의 변화가 다른 인스턴스에 영향을 주지 않기 때문입니다.
만약 Tutorial이 클래스였다면 tutorial1과 tutorial2는 같은 참조 인스턴스를 가지므로
tutorial1의 difficulty도 2로 변경됩니다.
Question #2
컴파일이 됩니다.
UIView는 클래스이고 let으로 선언된 참조 인스턴스는 다른 주소값으로 변경할 수 없습니다.
하지만 클래스의 프로퍼티를 변경하는 것은 가능하므로 컴파일이 정상적으로 됩니다.
(구조체는 프로퍼티 변경도 불가능)
Question #3
String은 Comparable을 준수하므로 가장 짧게 줄이는 방법은
aniamls.sort(by: <)
입니다.
만약 Comparable을 채택하지 않는 아이템이라면
animals.sort { $0.xxx < $1.xxx }
로 줄일 수 있습니다.
(xxx는 Comparable을 준수하는 프로퍼티)
Question #4
ray와 brian이 같은 참조 인스턴스를 가지고 있기 때문에
brian의 address가 변경되면 ray의 address도 함께 변경됩니다.
ray와 brian을 생성할 때 다른 Address 인스턴스를 넣거나,
Address를 구조체로 정의하면 문제를 해결할 수 있습니다.
Question #5
옵셔널은 변수에 값이 존재하지 않을 가능성이 있다는 것을 의미합니다.
옵셔널을 통해 데이터가 없는 경우를 표현할 수 있습니다.
옵셔널을 이용해 nil에 대한 예외처리를 강제할 수 있기 때문에 런타임 에러를 방지할 수 있습니다.
(개발자는 사람이므로 예외처리에 대해 언제든지 실수할 수 있음)
Question #5
구조체는 값 타입으로 복사가 일어날 때 COW로 최적화가 발생합니다.
Stack 영역에 저장되고 상속이 불가능하여 메서드가 Static Dispatch로 동작합니다.
클래스는 참조 타입으로 ARC에 의해 메모리 관리가 됩니다.
Heap 영역에 저장되고 상속이 가능해서 Dynamic Dispatch로 동작합니다.
구조체가 클래스보다 효율적인 상황이 많기 때문에 Swift는 공식적으로 구조체를 권장하고 있습니다.
구조체는 값 타입입니다.
- Stack 영역에 저장된다는 것은 Heap에 저장된 것보다 성능이 좋다는 것을 의미합니다.
스택의 특성상 push, pop으로 짧은 명령어만으로 메모리 할당, 해제를 할 수 있고
컴파일 단계에서 메모리 할당, 해제 타이밍을 알 수 있기 때문에 런타임에 성능 저하가 발생하지 않습니다.
- Stack 영역은 Thread도 각자 가지고 있기 때문에 Thread-Safe 합니다.
- let으로 구조체 인스턴스를 생성하면 내부 프로퍼티도 수정을 하지 못합니다.
- 메서드 안에서 프로퍼티를 수정할 수 없으며 mutating 키워드를 이용해야 합니다.
많은 경우에 Stack 영역에 저장되지만 Heap에 저장되는 경우도 있습니다.
참조 타입 안에 선언된 구조체를 Heap 영역에 저장됩니다.
Collection 타입은 구조체로 선언되어 있지만 Heap 영역에 저장됩니다.
Collection 타입의 복사가 일어날 때 COW의 이점을 활용합니다.
String은 구조체이지만 Stack과 Heap을 동시에 사용합니다.
16글자 미만은 Stack에 저장하고 16글자 이상은 Heap에 저장됩니다.
상속이 불가능하기 때문에 대부분의 경우에 메서드가 Static Dispatch로 동작하지만
프로토콜을 준수하기 위한 메서드는 Dynamic Dispatch로 동작합니다.
클래스는 참조 타입입니다.
- 메모리가 ARC에 의해 관리됩니다.
- Heap 영역에 할당/해제되는 메모리는 런타임에만 알 수 있기 때문에 성능 저하가 발생합니다.
- 모든 Thread가 같은 Heap을 공유하므로 Thread-Safe 하지 않습니다.
- let으로 클래스 인스턴스를 생성하면 주소값만 수정이 불가능하고 프로퍼티는 수정할 수 있습니다.
상속이 가능한 Class는 메서드가 Dynamic Dispatch 동작합니다.
final, private, extension을 이용하는 경우 Static Dispatch로 바뀌어 최적화 할 수 있습니다.
클래스는 Objective-C와 상호 이용해야 할 때, === 연산자로 객체 비교를 해야할 때, 상속이 필요할 때 사용하는 것이 적절합니다.
Question #6
제네릭은 모든 타입이 사용 가능한 공통의 타입을 의미합니다.
제네릭을 이용하면 코드 중복을 피할 수 있습니다.
매개 변수의 타입만 다르고 기능이 같은 경우 제네릭이 유용합니다.
Question #7
(이 문제는 몰랐네요 ㅠㅠ)
초기화 시점에 nil이 아닌 프로퍼티로 초기화할 수 없을 때 implicitly unwrapped optionals을 사용해야 합니다.
대표적인 예로 IBOutlet이 있습니다.
IBOutlet은 항상 owner보다 늦게 초기화되기 때문에 outlet이 사용하기 전에 non-nil이라는 것을 보장할 수 있습니다.
Question #8
(7가지나 있었나?)
1. 강제 언래핑 - 위험함
let a: String = x!
2. implicitly unwrapped 옵셔널 선언 - 위험한 경우가 많음
var a = x!
3. 옵셔널 바인딩 - 안전함
if let a = x {
...
}
4. 옵셔널 체이닝 - 안전함
let a = x?.count
5. nil coalescing 연산 - 안전함
let a = x ?? ""
6. guard 문 - 안전함
guard let a = x else { return }
7. 옵셔널 패턴 - 안전함
if case let a? = x {
...
}
마무리
여기까지가 Beginner를 위한 질문입니다.
두 가지 빼고는 머리로는 알고 있었으나
한 두 문장으로 잘 정리가 안 되는 질문들도 있었네요.
다음 포스팅에서 Intermediate를 위한 질문에 답변을 해보겠습니다.
2편 보러가기
[Swift] Swift Interview Questions - Intermediate(중급)
현재 포스팅은 2편 Intermediate 질문입니다. 1편 Beginner 보러가기 Question 1 차이가 없습니다. nil과 Optional.none은 같습니다. 동작은 같아도 nil로 작성하는 것이 일반적인 코드 컨벤션에 더 맞습니다. Qu.
jeong9216.tistory.com
감사합니다!
참고
https://www.raywenderlich.com/762435-swift-interview-questions-and-answers#toc-anchor-001
아직은 초보 개발자입니다.
더 효율적인 코드 훈수 환영합니다!
공감과 댓글 부탁드립니다.