🔥 전역 변수와 지역 변수

553자
6분

Swift에서 변수는 전역 변수(Global Variables)와 지역 변수(Local Variables)로 나눌 수 있어요. 전역 변수부터 같이 알아볼게요.

전역 변수(Global Variables)

전역 변수는 함수, 메서드, 클로저, 타입 컨텍스트 외부에 정의된 변수를 말해요. 이전 장에서 다뤘던 전역 변수들은 모두 저장 변수(Stored Variables)였죠.

저장 변수는 저장 속성과 마찬가지로 특정 타입의 값을 저장하고, 해당 값을 설정하고 검색할 수 있게 해준답니다.

swift
var globalVar = 10 // 전역 변수 선언 및 초기화
 
func someFunction() {
    print(globalVar) // 10
}
 
someFunction()
print(globalVar) // 10
swift
var globalVar = 10 // 전역 변수 선언 및 초기화
 
func someFunction() {
    print(globalVar) // 10
}
 
someFunction()
print(globalVar) // 10

위 코드에서 globalVar는 전역 변수로 선언되었어요. someFunction() 내부와 외부 모두에서 globalVar에 접근할 수 있죠.

지역 변수(Local Variables)

반면에 지역 변수는 함수, 메서드, 클로저 컨텍스트 내에 정의된 변수예요.

swift
func someFunction() {
    var localVar = 20 // 지역 변수 선언 및 초기화
    print(localVar) // 20
}
 
someFunction()
// print(localVar) // 오류: localVar는 someFunction() 내부에서만 접근 가능
swift
func someFunction() {
    var localVar = 20 // 지역 변수 선언 및 초기화
    print(localVar) // 20
}
 
someFunction()
// print(localVar) // 오류: localVar는 someFunction() 내부에서만 접근 가능

localVarsomeFunction() 내부에서 선언된 지역 변수라서 함수 외부에서는 접근할 수 없어요.

계산 변수(Computed Variables)

그런데 재미있는 사실은, 전역 변수와 지역 변수 모두 계산 변수(Computed Variables)로 정의할 수 있다는 거예요. 계산 변수는 계산 속성처럼 값을 저장하지 않고 계산하죠.

swift
var storedGlobalVar = 10 // 저장 전역 변수
 
var computedGlobalVar: Int { // 연산 전역 변수
    return storedGlobalVar * 2
}
 
func someFunction() {
    var storedLocalVar = 20 // 저장 지역 변수
 
    var computedLocalVar: Int { // 연산 지역 변수
        return storedLocalVar + 5
    }
 
    print(computedLocalVar) // 25
}
 
print(computedGlobalVar) // 20
someFunction()
swift
var storedGlobalVar = 10 // 저장 전역 변수
 
var computedGlobalVar: Int { // 연산 전역 변수
    return storedGlobalVar * 2
}
 
func someFunction() {
    var storedLocalVar = 20 // 저장 지역 변수
 
    var computedLocalVar: Int { // 연산 지역 변수
        return storedLocalVar + 5
    }
 
    print(computedLocalVar) // 25
}
 
print(computedGlobalVar) // 20
someFunction()

computedGlobalVar는 전역 범위에서 정의된 계산 변수고, computedLocalVarsomeFunction() 내에서 정의된 연산 지역 변수예요.

속성 래퍼

그리고 지역 저장 변수에는 속성 래퍼(Property Wrapper)를 적용할 수 있어요. 하지만 전역 변수나 계산 변수에는 적용할 수 없답니다.

swift
@propertyWrapper
struct SmallNumber {
    private var value: Int
    var wrappedValue: Int {
        get { return value }
        set { value = min(newValue, 12) }
    }
 
    init() { self.value = 0 }
}
 
func someFunction() {
    @SmallNumber var myNumber: Int = 0 // 지역 변수에 속성 래퍼 적용
 
    myNumber = 10
    print(myNumber) // 10
 
    myNumber = 24
    print(myNumber) // 12
}
 
someFunction()
swift
@propertyWrapper
struct SmallNumber {
    private var value: Int
    var wrappedValue: Int {
        get { return value }
        set { value = min(newValue, 12) }
    }
 
    init() { self.value = 0 }
}
 
func someFunction() {
    @SmallNumber var myNumber: Int = 0 // 지역 변수에 속성 래퍼 적용
 
    myNumber = 10
    print(myNumber) // 10
 
    myNumber = 24
    print(myNumber) // 12
}
 
someFunction()

SmallNumber라는 속성 래퍼를 정의하고, someFunction() 내부의 지역 변수 myNumber에 적용했어요.

속성 래퍼는 wrappedValuesetter에서 새로운 값이 12보다 크면 12로 제한하도록 구현되어 있죠.

따라서 myNumber에 24를 할당하면 12로 저장된답니다. 신기하죠?

함수 매개변수에 속성 래퍼 적용

더 나아가서, 함수의 매개변수에도 속성 래퍼를 적용할 수 있어요. 함수 매개변수는 함수 내부에서 사용되는 일종의 지역 변수로 볼 수 있기 때문이죠.

swift
func printSmallNumber(@SmallNumber num: Int) {
    print(num)
}
 
printSmallNumber(num: 10) // 10
printSmallNumber(num: 24) // 12
swift
func printSmallNumber(@SmallNumber num: Int) {
    print(num)
}
 
printSmallNumber(num: 10) // 10
printSmallNumber(num: 24) // 12

printSmallNumber 함수의 매개변수 num@SmallNumber 속성 래퍼를 적용했어요.

함수를 호출할 때 num에 10을 전달하면 그대로 10이 출력되고, 24를 전달하면 속성 래퍼에 의해 12로 제한되어 12가 출력되는 걸 확인할 수 있죠.

이렇게 함수 매개변수에 속성 래퍼를 사용하면 전달받은 값을 원하는 방식으로 가공하거나 제한할 수 있어요.

또한 속성 래퍼를 사용하면 코드의 재사용성도 높일 수 있답니다. 여러 함수에서 동일한 제약사항이 필요한 경우 속성 래퍼를 정의해두고 필요한 매개변수에 적용하면 되니까요.

swift
func calculateSmallNumber(@SmallNumber num1: Int, @SmallNumber num2: Int) {
    let result = num1 + num2
    print(result)
}
 
calculateSmallNumber(num1: 10, num2: 5) // 15
calculateSmallNumber(num1: 20, num2: 8) // 24
swift
func calculateSmallNumber(@SmallNumber num1: Int, @SmallNumber num2: Int) {
    let result = num1 + num2
    print(result)
}
 
calculateSmallNumber(num1: 10, num2: 5) // 15
calculateSmallNumber(num1: 20, num2: 8) // 24

calculateSmallNumber 함수의 매개변수 num1num2 모두에 @SmallNumber 속성 래퍼를 적용했어요.

두 번째 호출에서 num1에 20을 전달했지만 속성 래퍼에 의해 12로 제한되고, num2에 전달한 8과 합쳐져 24가 출력되는 걸 볼 수 있죠.

이렇게 Swift에서는 전역 변수와 지역 변수에 대해 다양한 기능을 제공해요. 상황에 맞게 적절한 변수를 선택하고, 속성 래퍼를 활용하면 더욱 효율적이고 가독성 높은 코드를 작성할 수 있습니다.

YouTube 영상

채널 보기
미들웨어 vs 가드, 왜 NestJS에서는 가드가 더 똑똑할까? | NestJS 가이드
Const 펑터 - 아무것도 안 하는 펑터가 필요한 이유 | 프로그래머를 위한 카테고리 이론
클로드 섀넌이 들려주는 정보 이론 이야기
입력을 전처리하는 Functor - Contravariant와 contramap 이해하기 | 프로그래머를 위한 카테고리 이론
Zod로 스키마 유효성 검사 구현하기 | NestJS 가이드
NestJS 파이프가 뭔가요? 컨트롤러를 보호하는 방법 | NestJS 가이드
존 매카시가 들려주는 인공지능의 탄생 이야기
함수형 데이터 타입 | 프로그래머를 위한 카테고리 이론