2014년 6월 16일 월요일

Swift - 서브스크립트(Subscripts)

서브스트립트라는 이름에서 뭘 말하는지 잘 이해가 안되는데, 클래스나 구조체를 배열(Array)처럼 인덱스를 이용해 엑세스 가능하게 만들어 주는 거라고 생각하면 편하다. 물론 완전히 같지는 않지만...

서브스크립트는 subscript 라는 키워드로 클래스나 구조체에 init 처럼 미리 정의되어 있는 특수한 메소드이다. 따라서 func 키워드를 붙이지 말고 그냥 구현하면 된다.
struct SubscriptTest {
    subscript(index: Int) -> Int {
        get {
            return index * 10
        }
        set {
            
        }
    }
}
구조체 내에서는 대충 요런 식으로 구현한다. 여기서는 하나의 매개변수를 선언했는데 index 라는 단일 인덱스를 기존으로 getter와 setter가 구현한다. 물론 보시는대로 setter는 그냥 아무일도 안한다.

실제 실행 결과는 이렇다.
var st = SubscriptTest()
st[10]      // 100
st[500]     // 5000
setter는 구현 안되어 있으니 생략한다. 어쨌거나 배열처럼 접근했는데 인덱스에 10을 곱한 값을 돌려주는 괴랄한 타입이 탄생했다.

이번에는 다른 예제를 한번 보자. 이번에는 서브스크립트를 2차원 배열처럼 접근할 것이다. 그리고 추가로 이 코드에서는 약간 이상한 트릭이 쓰이는데, 1차원 배열로 2차원 배열을 흉내내는 것이다. 심심해서 해 본 것이니 오해는 없었으면 좋겠다. -_-;;
struct BingoBoard {
    var board: Int[]

    // 상수 정의
    static let None = 0
    static let O = 1
    static let X = 2

    // 초기화: 5x5(25)크기의 board 배열을 None(0)으로 채운다.
    init () {
        self.board = Array(count: 25, repeatedValue: BingoBoard.None)
    }

    // 서브스크립트 구현
    subscript(x: Int, y: Int) -> Int {
        get {
            return self.board[y*5 + x]
        }
        set(value) {
            self.board[y*5 + x] = value
        }
    }

    // 콘솔에 현재 보드 상태를 출력
    func print() {
        for var y = 0; y < 5; y++ {
            var str = ""
            for var x = 0; x < 5; x++ {
                let v = self[x, y]
                if v == BingoBoard.O {
                    str += "O "
                }
                else if v == BingoBoard.X {
                    str += "X "
                }
                else {
                    str += ". "
                }
            }
            println(str)
        }
        println("")
    }
}
이름에서 알 수 있듯이 빙고 게임을 위한 5x5 크기의 보드를 구현하는 코드이다. 이번에는 서브스크립트 메소드가 매개변수를 2개(x, y) 받는다. 2차원 배열 형태로 접근하려니 당연한 것이다. 여기서 알 수 있는 사실은 서브스크립트의 매개변수 갯수는 마음대로 정할 수 있다는 점이다.

별로 중요하지는 않지만, 앞서 이야기 한 대로 여기서는 배열 하나(self.board)를 1차원 배열로 만들어 놓고 이를 (y * 5 + x) 라는 공식으로 접근하고 있다. 이렇게 하면 가로5 세로5 크기의 배열을 엑세스 하는 것과 동일한 결과가 나온다. 과거에 힙에 메모리 블럭을 만들어 놓고 2차원 배열처럼 엑세스 할 때 포인터 계산하는 것과 동일하다. 물론 중요하진 않으니 깊게 생각하지는 말자.

2차원 배열 이야기를 계속 하긴 했는데, 실제 코드 실행 시는 2차원 배열 형태로 접근하지는 않는다.
var board = BingoBoard()
board.print()
board[0, 0] = BingoBoard.O
board.print()
board[1, 1] = BingoBoard.X
board[3, 2] = BingoBoard.X
board[4, 4] = BingoBoard.O
board.print()
보다싶이 그냥 콤마를 이용해 2가지 인덱스를 넘기는 식으로 호출한다.

실행 결과를 글로 적으니 알아보기가 힘들어서 플레이그라운드에서 실행한 결과를 스크린샷으로 만들어 봤다.


print 메소드에서도 self[x, y] 와 같은 식으로 서브스크립트를 이용해 접근이 가능함을 알 수 있다. 스크린샷으로 올리니 약간 폼이 나서 기분이 좋....어쨌거나 이런 식으로 서브스크립트를 활용하는 것도 가능하다는 이야기였다.

[관련글] Swift - 구조체(Structure) 훑어보기
[관련글] Swift - 클래스(Class) 훑어보기
[관련글] Swift - 프로퍼티(Properties)

[돌아가기] 스위프트(Swift) 가이드

댓글 1개 :

강철 :

공식 문서보다 쉽게 설명해주셔서 도움이 많이되네요.
공식 문서는 쓸데없이 너무 어렵네요 ㅎㅎ