라벨이 150-interview인 게시물 표시

[인터뷰질문 018] Swift 함수에서 return 키워드가 필요없는 상황은 어느때 인가요?

이미지
return 키워드 return 키워드는 함수의 반환값을 표시할 때 쓰입니다. 이 함수에서 이 값이 반환됩니다 라는 의미지요. 함수가 무엇인지 반환값이 무엇인지 모른다면 먼저 공부하고 읽으시는 것을 추천 드립니다. return값이 없을 때 함수에 반환값이 필요 없는경우 당연히 return 키워드가 필요하지 않습니다. func sayHello () -> Void { print ( "Hello" ) } sayHello() // Hello Error 상황 함수가 실행되다가 정상적인 종료가 아닌 예외처리 하는 부분에서는 return 키워드가 필요 없습니다. func devidedValue (numerator : Double, denominator: Double) -> Double { if denominator == 0 { fatalError ( "can not devided by zero" ) //print("can not devided by zero") } else { return numerator / denominator } } print (devidedValue(numerator: 3 , denominator: 6 )) print (devidedValue(numerator: 3 , denominator: 0 )) 함수에서 반환타입이 있다면 반환값을 지정해주어야 합니다. 하지만 fatalError() 구문이 있으면, return 하지 않아도 됩니다. 왜냐하면 fatalError() 을 만나는 순간 함수가 종료되기 때문입니다. 한줄로 작성된 함수의 반 func devidedValue ( numerator : Double, denominator : Double) - > Double { numerator / denominator } print (devidedValue( n

[인터뷰질문 017] protocols을 주니어 개발자에게 어떻게 설명해 줄 것 인가요?

이미지
프로토콜이란? 프로토콜은 인터페이스 입니다. swift에서는 특정 기능을 정의합니다. 실제 구현은 하지 않고 정의만 합니다. 마치 설계도와 같죠. 간단한 예제 간단한 예제를 보도록 하겠습니다. 자동차의 기능을 구현하기에 앞서 일단 정의하려고 하는데요. 자동차가 주행에 필요한 것들을 나열해 봅시다. 간단하게 생각해서 출발과, 정지를 할 수 있으면 자동차가 주행할 수 있겠죠? 앞에 나오는 조건들이 주행에 필요한 요소들이라고 했으니 이 조건들을 모두 갖추면, 주행이 가능하다고 할 수 있습니다. 그럼 한번 설계 해 볼까요? protocol Driveable { func start () func stop () } 이렇게 설계 해 놓으면 이 프로토콜을 채택하면, 아 주행가능하구나 라고 생각하면됩니다. 아래와 같이 구현되겠죠? struct Sonata : Driveable { func start () { print ( "주행 시작합니다." ) } func stop () { print ( "주행 종료합니다." ) } } 사실 위에서 Driveable 프로토콜을 채택하지 않아도 돌아가는데는 문제가 없습니다. 하지만 다른 곳에서 사용할 때 프로토콜을 채택하고 있지 않으면 주행이 가능한건지에 대한 보장이 되지않겠죠? 그렇기 때문에 설계와 기능의 보장을 위해 프로토콜을 정의해서 채택해서 써야합니다. 여러 프로토콜 하나의 프토콜이 한 종료의 기능을 보장해준다면, 여러개의 기능은 아래와 같이 여러개의 프로토콜을 채택해서 구현할 수 있을 것 입니다. 거꾸로 이 객체가 어떤 기능을 하는지에 대한 것들은 프로토콜을 살펴보는 것 만으로도 가능 합니다. protocol Driveable { func start () func stop () } protocol Openable { func open () f

[인터뷰질문 016] operator overloading을 주니어 개발자에게 어떻게 설명해 줄 것 인가요?

이미지
오버라이딩 이 문제를 이해하기 위해서는 오버라이딩이라는 개념을 알고 있어야 합니다. 오버라이딩은 쉽게 말해 같은 이름의 다른 타입의 함수를 정의하는 것 입니다. 두개의 인자를 받아서 더하는 함수를 정의해 보겠습니다. func sum(_ a : Int, _ b : Int) -> Int { return a + b } func sum(_ a : Double, _ b : Double) -> Double { return a + b } print (sum( 3 , 2 ) ) // 5 print (sum( 4.1 , 4.2 ) ) // 8.3 두 숫자의 합을 구하고 싶을 때, 매개별수로 정수와 실수가 들어가야 한다면, 이렇게 한 함수를 오버라이딩해서 사용하는 사람이 편하게 쓸 수 있도록 구현할 수 있습니다. 연산자 오버라이딩 이름에서 알 수 있듯이, 연산자를 오버라이딩 하는 것 입니다. 우리가 알고있는 연산자는 다음과 같습니다. + , - , / , * 등등... 그렇다면, 언제 연산자를 오버라이딩 할까요? 아래 예제를 보면서 생각해 보겠습니다. struct Point { var x = 0.0 var y = 0.0 } let p1 = Point(x: 12.3 , y: 34.5 ) let p2 = Point(x: 67.2 , y: 89.6 ) 두개의 좌표가 있을 때, 좌표의 합을 구하고 싶다면, 어떻게 해야할까요? 쉽게드는 생각은 p1 + p2 하면 x는 x끼리 y는 y끼리 더해주었으면 좋겠는데, 실제 돌려보면 binary operator '+' cannot be applied to two 'Point' operands print(p1 + p2) 와 같은 에러가 발생합니다. 왜냐하면 + 연산자는 좌표를 더하는 것에 대한 처리가 되어있지 않기 때문입니다. 그렇다면? 위에서 봤던 예제처럼 연산자를 오버라이딩 하면 문제를 해결할 수 있을것 같습니다. struct Poi

[인터뷰질문 015] 두 개의 튜플의 값이 동일한지 어떻게 비교하시겠습니까?

이미지
튜플의 비교 튜플은 이름없는 구조체 라고도 하죠. 튜플이 같은지 비교하는 방법은 간단합니다 == 기호를 써줍니다. 여러 예제를 통해 비교해 보도록 하겠습니다. let temp1 = ( 2 , 4 ) let temp2 = ( 2 , 4 ) let temp3 = ( 3 , 4 ) let temp4 = ( top : 2 ,bottom: 4 ) print (temp1 == temp1) // true print (temp1 == temp2) // true print (temp1 == temp3) // false print (temp1 == temp4) // true 당연히 자기 자신과 비교 하면, 같다 라는 결과가 나옵니다. 값을 비교하는 연산자 이기 때문이죠. 그리고 다른 변수에 할당 하더라도 값이 같으면 true 의 결과값이 나옵니다. 그리고 (2,4)와 (3,4)는 같지 않기 때문에 false 가 출력되는 것을 볼 수 있습니다. 또한 tuple은 element의 이름을 지정할 수 있는데, 두 튜플이 같다고 해서 elemene의 이름까지 같음을 보장하지는 않습니다. 그러므로 temp4와 temp1이 다른 element 이름을 가지고 있어도, 같은 튜플로 인식합니다.

[인터뷰질문 013] Result 타입은 언제 사용할 수 있나요

이미지
Result 타입은 Swift5에 추가되었습니다. 그렇다면 왜 추가되어야 했는지 Result 타입이 없었을 때는 어떤 문제가 있는지 알아보면서 Result에 고마움에 대해 알아보도록 하겠습니다. Result가 없는 세상 Result 타입은 네트워크 요청 쪽에서 많이 사용되었습니다. 예를 들면 아래와 같은 상황에서 말이죠. import Foundation func getData <T: Decodable> (urlString: String, completion: @escaping (T?) -> Void ) { let url = URL (string: urlString)! URLSession .shared.dataTask(with: url) { data, response, error in if let error = error { return completion( nil ) } guard let data = data else { return completion( nil ) } guard let response = response as ? HTTPURLResponse , response.statusCode == 200 else { return completion( nil ) } guard let parsedData = try ? JSONDecoder ().decode( T . self , from: data) else { return completion( nil ) } completion(parsedData) }.resume() } URLSession.shared.dataTask 에서 요청한 응답 중 에러를 처리하려면, 정상적인 케이스와 정상적이지 않은 케이스들을 구

[인터뷰질문 012] value 타입과, reference 타입의 차이는 무엇인가요?

이미지
개념의 차이 가장 쉽게 예를 들 수 있는 개념의 차이는 엑셀파일과 구글 스프레드 시트 입니다. 두 파일 다 문서를 같게 작성할 수 있는 문서 편집이 가능한 도구입니다. 내가 작성한 엑셀파일을 저장해서 상대방에게 전달 하면, 같은 내용의 파일이 하나 더 생겨서 전달이 됩니다. 이 때, 상대방이 전달받은 파일을 수정해도 독립적으로 수정되어 수정본이 생기는 것일 뿐 내가 작성한 내용이 변경되지는 않습니다. 이렇게 값을 전달해서 주는 타입을 value type 이라고 합니다. 반면에 구글 스프레드시트를 작성하고, 링크를 전달해서 상대방에게 전달 한 뒤, 상대방이 수정하면 어떻게 될까요? 상대방화면에서 수정된 내용이 그대로 내 눈앞에 보이는 화면이 실시간으로 변경되고, 결국 이전에 작업했던 내용은 없어진 수정된 내용만 남게 됩니다. 이렇게 주소값을 전달 해주는 타입을 reference type 이라고 합니다. class와 struct class의 인스턴스는 reference type 입니다. 그렇기 때문에 인스턴스를 생성하고, 다른곳에서 수정하면 원래 사용되고 있었던 곳에서도 다 영향을 받게 되죠. 그리고 struct의 인스턴스는 value type 입니다. 인스턴스를 생성해서 사용하고, 다른곳에 전달해서 수정해도 원래 사용되고 있었던 곳에서는 영향을 받지 않습니다. 추가적으로 closures는 reference type 입니다. 그렇기 때문에 원하는 값을 사용하기 위해서 capture를 해야하죠. 그렇지 않으면 계속 값이 바뀔테니까요!

[인터뷰질문 011] UUID란 무엇이며, 언제 사용하는 것 입니까?

이미지
정의 UUID는 U niversally U nique ID entifier의 약자입니다. 직역 해보자면, 범용적인 고유 식별 아이디 입니다. 즉 유일한 값입니다. 그렇다면 이 유일한 값은 어떻게 만들어지고, 어느 범위까지 사용할 수 있는 것 일까요? 내용 내용은 위키 를 참고해서 정리 해 보있습니다. 8-4-4-4-12 의 포맷의 16진수로 만들어진 ID입니다. 생성 방법에 따라 버젼이 존재하며, 각 버젼은 아래와 같은 방법으로 생생된다고 합니다. 버전 1 (시간 + MAC 주소) 버전 2 (시간 + DCE 보안) 버전 3 (네임스페이스 + MD5 해시) 버전 4 (랜덤) 버전 5 (네임스페이스 + SHA-1 해시) 그렇다면, 우리가 사용하는 let uuid = UUID() 는 어떤 방법을 사용하는 것 일까요? 정확한 내용은 애플의 문서 에도 설명되어 있습니다. init() - Initializes a new UUID with RFC 4122 version 4 random bytes . 네 버젼4, 랜덤 방식을 사용한다고 합니다. 그렇다면 나올 수 있는 경우의 수는 16의 32승 가지가 되겠네요, 같은 숫자가 나올 확률은 16의 32승의 제곱 분의 1 . 물론 불가능 한 확률은 아니지만 거의 0에 가까운 확률로 같은 UUID를 생성할테니 랜덤 방식으로 만들어도 고유 식별 아이디가 생성된다고 봐도 무방할 듯 싶습니다.

[인터뷰질문 010] "문자열은 Swift에서 컬렉션입니다"라는 말은 무엇을 의미합니까?

이미지
String type 은 Collection 프로토콜을 채택했기 때문에, 문자열은 컬렉션입니다. 라고 말할 수 있습니다. 이것이 의미하는 바는, Collection 타입이 가지고 있는 프로퍼티와 메소드들을 사용할 수 있습니다. 예를들면 startIndex , isEmpty 와 같은 프로퍼티, index(_ i: Self.Index, offsetBy distance: Int, limitedBy limit: Self.Index) -> Self.Index? 와 같은 메소드 입니다. Collection 프로토콜은 원소들을 순회하는 연속성을 가지고 있습니다. 기본적으로 Sequence 프로토콜을 채택하고 있기 때문입니다. 하지만 Sequence 프로토콜과 다른점은, 순서대로만이 아닌 임의 key, index 값을 가지고 접근할수 있습니다. 또한 처음부터 끝까지 돌아가는게 아닌, 중간부분부터 얻을 수 있습니다.

[인터뷰질문 009] one-sided ranges가 무엇이며 언제 사용할 수 있나요?

이미지
범위 연산자 범위를 나타내는 여러가지 방법이 있습니다. closed range operator 0...5 // [0, 1, 2, 3, 4, 5] half-open range operator 0..<5 // [0, 1, 2, 3, 4] one-sided range operator ...5 // ?? 특정 조건에서는 one-sided ranges 를 사용할 수 있습니다. 에를 들면 아래의 코드 같은 경우 입니다. let friends = [ "Leeo" , "Jonh" , "Tim" , "Lisa" , "Mons" ] let member = friends[..< 3 ] // "Leeo" , "Jonh" , "Tim" 활용 배열을 잘라서 사용해야 할 떄, 일부분을 자르는게 아닌, 처음부터 어디까지 혹은 어디부터 끝까지 자를 떄 활용하면 편리합니다. 어디서 부터 시작인지, 어디까지가 끝인지 명시하지 않아도 잘리기 때문이죠.

[인터뷰질문 008] 왜 불변성(immutability)이 중요한가요?

이미지
불면성 변수의 종류에는 상수인 let 과 변수인 var 가 있습니다. 이 중에서 불변성을 가지는 변수는 let 키워드를 가지는 변수 입니다. 두 변수의 차이는 말 그대로 불변성 입니다. 변수 안에 들어있는 값을 수정할 수 있느냐 없느냐의 차이이죠. 그렇다면 수정할 수 없는 상수를 언제 써야할까요? 활용 변수의 값이 변하지 않음을 보장합니다. 이 말은 코드를 볼 때 상수를 보고 그 안에 어떤 값이 있을지 쉽게 예측 할 수 있다는 말 입니다. 그래서 Xcode에서도 var 로 변수를 선언하더라도, 그 안의 값이 변하지 않으면 let 으로 바꿔 상수로 변경할 것을 제안합니다. 멀티 쓰레드의 코드를 작성했을 때, 다른 곳에서 내가 짠 코드의 값을 변경하지 못하게 막을 수 있습니다. 상수를 사용하면, 변수보다 데이터를 효율적인 방법으로 저장할 수 있습니다.

[인터뷰질문 007] Array를 사용할 때, map()과 compactMap()를 쓰는 차이점은 무엇인가요?

이미지
map vs compactMap 기본적으로 정의를 알아야 하는 내용이기 때문에, map 와 compactMap 의 내용을 보고 기능을 아는 것이 중요할 것 같습니다. 짧게 요약하면, map은 내가 가진 데이터들을 다른 형태나 다른 값으로 변환 해주는 녀석 입니다. compactMap은 내가 가진 데이터들 중에 nil 값을 제거해 주는 녀석이죠. 용도에 맞게 쓰면 되겠습니다 아래 예제 코드를 간단히 비교해서 언제 써야 할 지 고민해보아요. map let numberList = [ 1 , 3 , 4 , 5 , 7 ] print(numberList) // [1, 3, 4, 5, 7] let doubleNumberList = numberList.map { $ 0 * 2 } print(doubleNumberList) // [2, 6, 8, 10, 14] 정말 간단한 예제입니다. 내가 가진 데이터가 있는데, 모두 2배를 해야한다면 반복문인 for 로 모두 순회 하면서 2배씩 곱하고 그 값을 새로운 배열에 저장하는 방법이 가장 먼저 떠오르지만 위의 예제를 사용하면 우아하게 데이터를 변형할 수 있습니다. compactMap let numberListWithNil: [ Int ?] = [ 1 , 2 , 4 , nil, 1 , 3 ] print (numberListWithNil) // [ Optional ( 1 ), Optional ( 2 ), Optional ( 4 ), nil, Optional ( 1 ), Optional ( 3 )] let doubleNumberListWithNil: [ Int ] = numberListWithNil.compactMap { $ 0 } print (doubleNumberListWithNil) // [ 1 , 2 , 4 , 1 , 3 ] 마찬 가지로 가지고 있는 Array에 값이 항상 있다는 보장이 되지 않는 Optional 이라면, compactMap을 사용해서 Optional값을 없앤 새로운 데이터를 만들 수 있습니

[인터뷰질문 006] Float과 Double 그리고 CGFloat의 데이터 타입 차이는 무엇인가요?

이미지
처음 숫자를 다룰 때는, Int 형을 썼습니다. 그러다가 이제 나눗셈이 들어가면서 부터 실수를 사용해야 하는데, 그 때 마다 대충 적당히 쓰다가 정확한 차이점과 그 쓰임새를 정리하려고 합니다. Float vs Double 변수의 크기가 다릅니다. Int와의 다른점은 생략하겠습니다. 자세 한 부분은 부동소수점 을 참고하면 좋습니다. Float은 32-bit, Double은 64-bit 입니다. 즉 Float은 2의 24승인 16777216.0, Double은 2의 53승인 9007199254740992까지 표현할 수 있습니다. 물론 정확한 범위는 소수점까지 포함되어야 하겠지만 Float과 Double의 크기 차이가 어느 정도 인지만 나타내겠습니다. 아래 코드는 궁금해서 출력해 본 코드 입니다. 궁금하신 분들은 한 번 복, 붙 해서 돌려보세요 :) import Foundation var float : Float = 16777216 var double : Double = 9007199254740992 print ( float ) float = float + 1 print ( float ) print ( double ) double = double + 1 print ( double ) var total: Double = 1 for i in 1. .< 55 { total = total * 2 print (i, total) } Float vs CGFloat CGFloat은 import UIKit 해야 쓸 수 있다는 점이 다릅니다. 돌아가는 기기에 따라 32-bit 이나 64-bit이 될 수 있으나, 현실적으로는 거의 64-bit입니다. 추가적으로 Swift 5.5 버젼 이상에서는 CGFloat 과 Double 이 교환 가능하다고 합니다.

[인터뷰질문 005] Array와 Set의 차이가 무엇인가요?

이미지
Array와 Set의 차이점 Array, 한국어로 하면 배열입니다. 의미 그대로 무엇인가를 나열할 수 있는 배열이기 때문에 다양한 타입이 오기도 하고 중복되는 같은 값이 와도 이상하지 않습니다. Set, 한국어로 하면 집합입니다. 이런 저런것들이 나열되어 있다기 보다는 중복되지 않은 값들을 그룹으로 모아놓은 느낌이 강합니다. 정리 해 보면, 여러개의 값들을 나열할 수 있는 것은 Array , 중복을 제거한 집합은 Set 입니다. 그리고 조회에 있어서 Set 가 Array 에 비해 훨씬 빠릅니다. 아래의 코드를 통해 두 차이점을 비교해 보고 눈으로 확인 해 보도록 하겠습니다 import Foundation let sampleArray: [Int] = [ 1 , 1 , 2 , 3 , 3 , 3 ] var sampleSet:Set<Int> = Set([ 1 , 1 , 2 , 3 , 3 , 3 ]) print (sampleArray) // [1, 1, 2, 3, 3, 3] print (sampleSet) // [2, 3, 1] var numbers:[Int] = [] while numbers .count < 10000 { var number = Int.random( in : 1 ... 100000 ) if !numbers.contains(number){ numbers.append(number) } } sampleSet = Set(numbers) let startTime = CFAbsoluteTimeGetCurrent() print (sampleSet.contains( 98891 ) ) let processTime = CFAbsoluteTimeGetCurrent() - startTime print ( "set process time : \(processTime)" ) // set process time : 0.00021398067474365234 let star

[인터뷰질문 004] Codable protocol이 하는 역할이 무엇인가요?

이미지
Cadable이란? encodable과 decodable 프로토콜을 모두 채택한 프로토콜 입니다. 데이터를 손쉽게 Json이나 다른 구조화된 데이터로 인코딩 하거나, 파싱할 때 사용합니다. 예제 import Foundation struct Student : Codable { var name: String var age: Int } let studentData = """ { "name": "leeo", "age": 17 } """ .data(using: .utf8)! let student1 = try ! JSONDecoder ().decode( Student .self, from: studentData) print(student1) // Student(name: "leeo", age: 17) print(student1.name) // leeo print(student1.age) // 17 모델을 만들고, Codable 프로토콜을 채택하면 Decodable 프로토콜이 포함되어 있기 때문에 JSONDecoder().decode() 를 사용할 수 있습니다. 그러면 from: studentData 이 부분에 입력된 데이터와 Student.self 이 같은 타입인지 비교하고 일치하면 Student 의 객체로 만들어 줍니다. 사용할 때의 문제점1 swift 에서 사용하고 있는 변수는 camelCase 를 사용하고 있습니다. 하지만 내려오는 데이터도 같은 키로 내려오리란 보장이 없죠 그 때 사용할 수 있는것이 CodingKey 입니다. 같은 키는 알아서 찾지만, 다른 이름으로 내려왔을 때 수동으로 매칭해준다고 생각하시면 쉬울 것 같습니다. 코드로 예를 들어보면 아래와 같습니다. struct StudentFullname: Codable { var firstName: St

[인터뷰질문 003] tuples이란 무엇이고 어느 상황에서 유용하게 사용할 수 있습니까?

이미지
튜플이란? 튜플은 아주 작은 익명의 'struct'라고 생각하면 편합니다. 이게 무슨의미냐 하면, struct 라는 것을 생각해보면 다양한 타입의 프로퍼티 들이 들어갈 수 있습니다. Array 는 같은 타입만 넣을 수 있지만, 튜플은 여러 타입이 들어갈 수 있는 자료형 입니다. 예제 간단하고 익숙한 예제부터 설명 해보도록 하겠습니다. let student = ( "Leeo" , 17 ) print(student .0 , student .1 ) // Leeo 17 본인은 이름이 없고, student라는 변수에 할당했습니다. 그리고 현재는 구성 요소들의 이름이 없기 때문에 index 로 접근해야합니다. 다음은 이름을 줘 보도록 하겠습니다. let student = ( name : "Leeo" ,age: 17 ) print( student .name, student.age) // Leeo 17 코드를 살펴보면 값을 이름으로 접근할 수 있습니다. 마치 struct 같지 않나요? 그리고 보이는 바와 같이 여러개의 다른 타입의 값들을 type-safe 하게 반환할 수 있습니다. 위와 같은 방법을 활용하여 1회용 이라면 struct 를 선언하지 않고 여러개의 값을 반환할 수 있습니다.

[인터뷰질문 002] Swfit에서 class와 struct의 차이점이 무엇인가요?

이미지
https://www.hackingwithswift.com/interview-questions/what-are-the-main-differences-between-classes-and-structs-in-swift 값 타입, 참조 타입 많은 분들이 머리로는 다 알고 있는 부분일것이라 생각합니다. 저도 class 는 reference type 이고, struct 는 value types이다. 라고 알고 있습니다. 그게 무슨 뜻일까요? 쉽게 비유하면, 엑셀과 스프레드 시트로 할 수 있습니다. 여러분이 하나의 엑셀을 만들고 다른 동료에게 보내고 난 다음에, 그 엑셀이 어떻게 되었는지는 관심도 없고 나에게 영향을 주지 않죠. 하지만 내가 스프레드 시트를 만들어서 전해주면, 다른사람이 내가 만든 결과물에 영향을 줄 수 있습니다. 너무 동떨어진 예제라면 아래 코드로 이해해 보도록 하겠습니다. struct Student { var na me: String var a ge: Int } 간단한 예제의 struct 가 있습니다. name 과 age 를 가지고 있습니다. let firstStudent = Student(name: "Leeo_student" , age: 17 ) print (firstStudent.name, firstStudent.age) // Leeo_student 17 var secondStudent = firstStudent secondStudent .name = "batgird_student" secondStudent .age = 18 print (firstStudent.name, firstStudent.age) // Leeo_student 17 print (secondStudent.name, secondStudent.age) // batgird_student 18 처음에 생성하고 바로 출력해보면, 생성한 결과가 나오니 이상하진 않습니다. 그리고 두번째 변수를 만

[인터뷰질문 001] Swfit에서 dictionary와 array의 차이점이 무엇인가요?

이미지
데이터 접근 방식의 차이 array는 정렬된 값들의 모임이고, dictionary는 정렬되지 않은 key-value 쌍의 값들의 모임입니다. 그러므로 데이터에 접근하는 방법이 다릅니다. array - 숫자로 된 index에 데이터에 접근합니다. // print (myArray[ 3 ]) dictionary - 사용자가 정의 한 key 값을 통해 value에 접근합니다. // print (myDictionary[ "apple" ]) 데이터 정렬의 차이 array는 index의 순서대로 정렬이 되어있습니다. 그래서 반복문으로 출력을 하게 되면 일정한 순서가 있고, 순서대로 출력되게 됩니다. let fruits = [ "banana" , "apple" , "avocado" ] for item in fruits { print (item) } // banana // apple // avocado 물론 정렬을 지원하기도 합니다. let sortedFruits = fruits.sorted {$0 < $1} for item in sortedFruits { print (item) } // apple // avocado // banana dictionary는 기본적으로 정렬되어있지 않습니다. 이게 무슨뜻 인지 아래 코드로 설명하겠습니다. let fruits = [ "banana" : " $3 " , "apple" : " $8 " , "avocado" : " $12 " ] for item in fruits { print (item.key, item.value) } // avocado $12 // banana $3 // apple $8 출력된 결과를 보면, 알파벳 순도 아니고, 그 어떤 기준도 없습니다. 정의 그대로 정렬되어 있지 않