Swift 면접질문들
Swift 면접 질문이라는데… 난이도는 그리 높지 않은 편이다.
http://www.toptal.com/swift/interview-questions
1
다음 코드를 보고 질문에 답하시오
var array1 = [1, 2, 3, 4, 5]
var array2 = array1
array2.append(6)
var len = array1.count
- 문:
len
값은 얼마이며, 왜 그런가요? - 답: 5. Swift의 Array는 값 시멘틱이며, 다른 변수에 대입하게 되면 복사가 일어난다. 따라서
array2
는array1
과는 다른 독립된 사본이며,array2.append(6)
가 실행되더라도array1
은 변하지 않는다.
2
다음 코드를 보고 질문에 답하시오
let op1: Int = 1
let op2: UInt = 2
let op3: Double = 3.34
var result = op1 + op2 + op3
- 문: 어디에 에러가 있으며, 왜 에러인가? 그리고 어떻게 고쳐야 하나?
- 답: 마지막 라인에 에러가 있다.
op1
,op2
의 타입은Int
인데op3
은Double
타입이다. 타입이 다른 두 수는 더할 수 없다. (더한 결과는Int
타입인가? 아니면Double
타입인가?) 이를 계산하려면 다음과 같이 수정한다.
var result = Double(op1 + op2) + op3
혹은 다음과 같이 +
연산자를 오버로딩하는 방법도 있다.
func + (lhs:Int, rhs: Double) -> Double { return Double(lhs) + rhs }
var result = op1 + op2 + op3 // Double
3
아래 코드를 보고 질문에 답하시오.
var defaults = NSUserDefaults.standardUserDefaults()
var userPref = defaults.stringForKey("userPref")!
printString(userPref)
func printString(string: String) {
println(string)
}
- 문: 버그는 어디에 있나? 그리고 버그의 원인은? 어떤식으로 고쳐야 할까?
- 답: 두 번째라인.
defaults.stringForKey("userPref")!
에서 해당 키가 없다면 nil을 리턴한다. 그런데 그 값을 강제로 unwrapping 하면 런타임 에러가 발생할 것이다. 옵셔널 값은 보다 안전하게if let
구문을 이용해서 언래핑한다.
if let userPref = defaults.stringForKey("userPref") {
printString(userPref)
}
4
- 문:
String
구조체는count
나length
프로퍼티를 제공하지 않고 대신 전역함수인countElement<T>
를 써야 한다. 이를 문자열에 적용했을 때 이 함수의 시간 복잡도는 어떻게 되는가? 그리고 그 이유는? - 답: O(n)이다. Swift의 문자열의 “길이”는 유니코드 문자 몇 개인가를 의미하는데, 유니코드 코드값은 2개 이상이 하나의 글자가 되는 경우가 있기 때문에 문자열 맵 전체를 확인해야 한다. Swift의 문자열은 각 글자(Character)들의 연결리스트에 가까운 구조이다.
Swift2.0에서부터 countElement()
함수는 제거되었다. CollectionType
의 원소의 개수는 count
프로퍼티로 이동하였다. 문자열은 그 성격이 배열과 같은 집합은 아니므로 count
프로퍼티가 존재하지 않는다. 문자열의 글자의 수를 세고 싶다면 str.characters.count
로 캐릭터맵의 원소의 개수를 이용한다.
5
- 문:
enum
타입에서raw value
와associated value
의 차이는? - 답:
raw value
는 개별 enum case가 대응되어 다른 case와 구분되는 값이다.associated value
는 특정한 enum case와 연결되는 타입이다. 이 때 enum case는 해당 associated value에 대한 constructor 역할을 한다고 볼 수 있다. 즉,raw value
의 경우 값이 다르면 다른 case에 해당하지만,associated value
는 동일한 enum case 내에서 다른 값을 가질 수 있다.
6
AnyObject
는 어떠한 클래스의 인스턴스라도 나타낼 수 있는 타입인데, 이는 내부적으로 프로토콜로 정의되어 있다. 이 때,
var array = [AnyObject]()
struct Test {}
array.append(Test())
이 코드는 컴파일 되지 않으며 다음과 같은 에러를 낸다.
Type 'Test' does not conform to protocol 'AnyObject'
그런데 다음 코드를 보면…
var array = [AnyObject]()
array.append(1)
array.append(2.0)
array.append("3")
- 문: 이 코드는 문제없이 컴파일 된다. 왜?
- 답: 이 문제는 틀렸다. Swift 2 부터는 Swift의 원시타입인 Int, Double 등은 자동으로 NSNumber로 브릿징되지 않으며 `as NSNumber`로 명시적으로 캐스팅해야 한다. 또한 이러한 캐스팅을 이용하려면 `Foundation`을 반입해야 한다. 그러한 전제없는 위 질문은 잘못되었다고 볼 수 있다.
7
struct Planet {
var name: String
var distanceFromSun: Double
}
let planets = [
Planet(name: "Mercury", distanceFromSun: 0.387),
Planet(name: "Venus", distanceFromSun: 0.722),
Planet(name: "Earth", distanceFromSun: 1.0),
Planet(name: "Mars", distanceFromSun: 1.52),
Planet(name: "Jupiter", distanceFromSun: 5.20),
Planet(name: "Saturn", distanceFromSun: 9.58),
Planet(name: "Uranus", distanceFromSun: 19.2),
Planet(name: "Neptune", distanceFromSun: 30.1)
]
let result1 = planets.map { $0.name }
let result2 = planets.reduce(0) { $0 + $1.distanceFromSun }
- 문:
result1
,result2
의 타입은 각각 무엇이며, 왜 그렇게 추론되는지 설명하세요. - 답: result1:
[String]
, result2:Double
.
먼저 result1은 맵핑에 사용된 클로저의 타입이 Planet -> String
이기 때문에 [String]으로 추론할 수 있으며, result2는 각 거리값의 합인데, Swift는 기본적으로 실수값을 Double로 추론하기 때문이다.
8
아래 코드를 보고 문제에 답하라.
class Master {
lazy var detail: Detail = Detail(master: self)
init() {
println("Master init")
}
deinit {
println("Master deinit")
}
}
class Detail {
var master: Master
init(master: Master) {
println("Detail init")
self.master = master
}
deinit {
println("Detail deinit")
}
}
func createMaster() {
var master: Master = Master()
var detail = master.detail
}
createMaster()
- 문: 위 코드에는 어떤 버그가 있으며, 메모리에 영향을 미치는지? 그리고 어떻게 고쳐야 하는지?
- 답:
Master
,Detail
두 클래스간에 순환참조가 있다. 이 관계에 있는 두 객체 인스턴스는 메모리 누수의 원인이 된다.
이는 한쪽에서는 다른쪽에 참조수를 늘리지 않도록 weak
, unowned
조절자를 써서 프로퍼티를 정의해야 한다.
class Detail {
unowned var master: Master
init(master: Master) {
print("Detail init")
self.master = master
}
...
}
unowned
는 옵셔널 타입에 쓸 수 없다. (값이 항상 있음을 가정함)
9
아래 코드를 보고 질문에 답하라.
struct IntStack {
var items = [Int]()
func add(x: Int) {
items.append(x) // Compile time error here.
}
}
- 문: 위 코드는 컴파일 에러가 난다. 왜 그런 것이며, 어떻게 고쳐야 하는가?
- 답: struct 는 값 시멘틱이기 때문에 인스턴스 자신이 변경되는 동작에는 명시적으로
mutating
변경자가 붙어야 한다.
struct IntStack {
var items = [Int]()
mutating func add(x: Int) {
items.append(x) // Compile time error here.
}
}