상세 컨텐츠

본문 제목

[Day6] Collective Types (1) : Array

Swift&SwiftUI

by (방울)도마토 2024. 4. 14. 00:43

본문

Collective Types (집단 자료형)

1. Array : 일련번호로 구분되는 순서에 따라 데이터가 정렬된 목록 형태의 자료형

2. Set : 중복되지 않은 유일 데이터들이 모인 집합 형태의 자료형 

3. Tuple : 종류에 상관없이 데이터들을 모은 자료형, 수정 및 삭제가 불가능함

4. Dictionary : key를 사용하여 key-value로 연관된 데이터들이 순서 없이 모인 자료형 

 

- 어떤 타입의 데이터라도 모두 저장할 수 있으나, 튜플을 제외한 나머지는 저장되는 모든 타입이 동일해야 함

    - 다른 타입의 데이터를 섞어 저장하는 것은 불가능 

 

Array

- 일련의 순서를 가지는 리스트 형식의 값을 저장하는 데 사용하는 자료형 

- Index 

    - index를 사용하여 배열 내 아이템을 읽어올 수 있음 

    - 정수, 0부터 시작하여 추가할 때마다 차례대로 증가 

    - item의 고유 코드 역할을 할 수 없으며 아이템이 있는 위치를 가리키는 역할만 함 

 

- 배열에 저장할 아이템의 타입에는 제약이 없으나, 하나의 배열에 저장하는 아이템 타입은 모두 같아야 함 

- 선언 시 배열에 저장할 아이템 타입을 명확히 정의해야 함 

- 배열의 크기는 동적으로 확장할 수 있음 

 

// 배열의 선언과 값 할당 
var cities = ["Seoul", "New York", "LA", "Santiago"]
    // 문자열 literal 이 사용되었으므로 cities는 문자열 아이템을 가지는 배열이 됨
    
cities[0] // Seoul
cities[1] // New York
cities[2] // LA
cities[3] // Santiago

 

 

순회 탐색

- 순서가 있는 데이터를 처음부터 마지막까지 차례대로 읽어 들이는 것 

1) 배열의 길이를 직접 다루는 방식 

2) 배열의 순회 특성을 이용하는 방식 

 

1) 배열의 길이를 직접 다루는 방식 

- 배열의 길이를 구해서 이 횟수만큼 루프가 반복되도록 직접 구현하는 방식 

let length = cities.count // 4
	// .count : properties(속성), 배열의 길이를 구함
    
for i in 0..<length { // 반 닫힌 연산자 : 마지막 인덱스 값은 항상 배열의 크기보다 1이 적음
    print("\(i) : \(cities[i])")
} // 0 : Seoul
// 1 : New York
// 2 : LA
// 3 : Santiago

 

 

 

2) 배열의 순회 특성(Iterator)을 이용하는 방식 

- for~in 구문에 배열 자체를 넣어서 실행시키는 것 

for row in cities {
    print(row)
} // Seoul
// New York
// LA
// Santiago

- cities 배열의 아이템들은 모두 문자열이므로 루프 상수(row) 역시 문자열 타입으로 선언 

    - 순회 특성을 이용하여 배열 탐색 시 루프 상수에 담긴 값은 배열 아이템 자체이므로 아이템의 인덱스를 바로 알기 어려움 

    - index(:of)를 사용하여 아이템을 통해 인덱스 값을 역으로 찾을 수 있음 

 

for row in cities {
    let index = cities.index(of: row)
    		// index(:of) : Method
    print("\(index!) : \(row)")
} // 0 : Seoul 
// 1 : New York
// 2 : LA
// 3 : Santiago

 

 

 

배열의 동적 선언과 초기화 

 

배열을 정의하는 첫 번째 방식

Array <아이템 선언> ()

 

- Swift에서 배열을 정의할 경우 반드시 저장할 아이템의 타입도 함께 명시해주어야 함 

- <> : generic

    - 배열 내부에서 사용할 아이템 타입을 지정하는 문법

    - 구조체나 클래스 외부에서 객체 내부에 사용될 타입을 지정할 수 있음 

    ex. <AnyObject> : 범용 클래스 객체 저장 

 

 

선언(Declare)

- Compiler 에게 어떠한 배열을 만들지 알려주는 역할 

초기화(Initailization)

- 선언한 대로 배열을 실제로 만들어 줄 것을 요청하는 과정 

 

    - 배열 구조체는 선언만 되었을 때는 메모리 공간을 차지하지 않다가 초기화가 진행되어야 메모리 공간을 할당 받음 

    - 배열의 선언은 "시스템 OS에 얼마 만큼의 공간을 사용하고 싶다"라고 예약하는 과정, 초기화는 실제로 사용하기 위해 체크인을 하는 과정과 유사 

 

// 문자열 배열을 선언 
var cities : Array <String>
// 배열의 초기화 
cities = Array()

// 문자열 배열의 선언 및 초기화 
var cities = Array<String>()

 

 

배열을 정의하는 두 번째 방식

[아이템 방식]()
// 배열 선언 
var cities : [String]
// 배열 초기화 
// 첫 번째 
cities = [String]()
// 두 번째 
cities = []

// 배열의 선언과 초기화 
var cities = [String]()

 

 

Cf. 다양한 스타일의 배열 선언과 초기화

// 1
var cities : [String]
cities = [String]()

// 2
var country : [String]
country = []

// 3
var list : [Int] = []

// 4
var rows : Array<Float> = [Float]()

// 5
var tables : [String] = Array()

 

 

isEmpty

- 선언된 배열이 실제로 비어있는지 체크 

- 배열에 아이템이 없는 상태이면 true, 아이템이 있다면 false를 반환 

- 해당 속성은 Read-Only이므로 isEmpty 속성에 true를 대입할 수 없음 

var list = [String]()

if list.isEmpty {
    print("배열이 비어 있는 상태입니다")
} else {
    print("배열에는 \(list.count) 개의 아이템이 저장되어 있습니다")
} // 배열이 비어 있는 상태입니다

 

 

배열의 아이템 동적 추가 method

1. append(_:)

- 입력된 값을 배열의 맨 뒤에 추가 

- 아이템 추가 전에 먼저 배열의 크기를 +1 만큼 확장하여 인덱스 공간을 확보한 후, 인자 값을 마지막 인덱스 위치에 추가 

 

2. insert(_:at:)

- 아이템을 원하는 위치에 직접 추가하고 싶을 때 사용 

- at: 뒤에 입력되는 정수값은 아이템이 추가될 인덱스의 위치를 의미 

- 새로운 인덱스 값이 추가되면 이를 기준으로 나머지 인덱스들은 하나씩 다음으로 밀려남 

 

3. append(contentsOf:)

- append(_:)와 같이 배열의 맨 마지막에 아이템을 추가하지만, 여러 개의 아이템을 배열에 한꺼번에 추가할 때 사용

- 메소드의 인자값은 항상 배열이어야 함 

 

var cities = [String]()

cities.append("Seoul") // ["Seoul"]
cities.append("New York") // ["Seoul", "New York"]
cities.insert("Tokyo", at: 1) // ["Seoul", "Tokyo", "New York"]
cities.append(contentsOf: ["Dubai", "Sydney"])
	// ["Seoul", "Tokyo", "New York", "Dubai", "Sydney"]
    
// 수정 시 
cities[2] = "Madrid"
	// ["Seoul", "Tokyo", "Madrid", "Dubai", "Sydney"]

 

 

- 배열의 인덱스를 이용하여 직접 아이템에 접근하는 방식은 기존에 있는 값을 수정할 수는 있지만, 값을 추가할 수는 없음 

- 배열의 인덱스를 직접 이용하여 아이템의 값을 할당하거나 수정하고, 읽어오는 것은 해당 배열에 그 인덱스가 이미 만들어져 있거나 그만큼의 인덱스가 확보된 경우로 제한 

    ex. cities[3] = "Dubai"

        - cities 배열에 인덱스 3이 이미 만들어져 있어야 가능 

        - 그렇지 않은 경우 "잘못된 인덱스 참조로 인한 오류" 발생 

        - insert(_:at:) 메소드의 at 매개변수에 현재 존재하지 않는 인덱스 값을 넣으면 오류 발생 

- 단, 현재 배열에서 마지막 인덱스에 이어지는 다음 인덱스를 참조하는 것은 허용 

    - 내부적으로 배열의 크기를 +1 확장하여 새로운 인덱스를 만들기 때문 

 

var cities = [String]()

cities.insert("Seoul", at: 0)
    // 마지막 인덱스에서 이어지는 다음 인덱스 참조 
    // 배열의 길이가 늘어나면 인덱스도 자동으로 늘어남
    
print(cities) // Seoul

 

- 배열의 크기는 언제나 입력된 값의 개수만큼만 생성 

- 새로운 아이템을 직접 할당하기 위해 참조해야 할 인덱스는 생성되어 있지 않으므로 새로운 아이템을 추가할 목적으로 인덱스에 직접 접근할 수 없음 

    - Cocoa Touch Framework 에서 초기화할 때 배열의 크기를 지정할 수 있는 구문이 정의되어 있음 

extension Array : RangeReplaceableCollection {
    public init(repeating repeatedValue: Element, count: Int)
    
    // repeatedValue : 배열의 크기만큼 생성된 인덱스 각각에 기본값으로 넣어줌 
    // count : 배열의 길이 지정 
}


var cities = Array(repeating: "None", count: 3)
// var cities = [String](repeating: "None", count: 3)

print(cities) // ["None", "None", "None"]

- 배열의 인덱스가 개수만큼 미리 정의되고, 기본값이 각각 추가된 상태로 배열이 만들어짐 

    - 배열의 크기가 기본값으로 지정된 것이므로 메소드를 사용하여 새로운 인덱스와 값을 추가하고 배열의 크기를 늘릴 수 있음 

 

 

범위 연산자를 이용한 인덱스 참조

- 일정 범위의 배열 아이템을 한꺼번에 읽어 들일 때 사용 

- 결과값은 배열로 전달 

var alphabet = ["a", "b", "c", "d", "e"]

alphabet[0...2] // ["a", "b", "c"]
alphabet[2...3] // ["c", "d"]

 

- 범위 연산자로 읽어 들인 배열에 새로운 값을 할당하면 할당할 배열 아이템과 범위 연산자로 읽어 들인 배열의 크기가 일치하지 않을 때도 값을 변경할 수 있음 

alphabet[1...2] = ["1", "2", "3"]
// alphabet = ["a", "1", "2", "3", "d", "e"]

- 2개의 아이템("b", "e")이 제거되었지만 새로이 3개의 아이템이 추가되었으므로 전체 배열 길이로 보면 1만큼 커짐

alphabet[2..4] = ["A"]
// alphabet = ["a", "1", "A", "e"]

- 3개의 아이템("2", "3", "d")는 모두 제거되고 "A"가 추가되면서 배열의 크기가 4로 줄어들게 됨

 

 

* NSArray, NSMutableArray 

- Foundation Framework에서 제공하는 객체 

- NSArray는 수정이 필요없는 배열에, NSMutableArray는 수정이 필요한 배열에 사용 

- 타입이 명확하게 정해지지 않은 불특정 집합 데이터나 여러 종류의 값이 섞여 있는 집합 데이터를 처리할 때에 사용 

관련글 더보기

댓글 영역