본문 바로가기
Swift

Swift_ 변수의 종류

by JunsC 2025. 2. 11.
728x90

Java 에서처럼 변수의 종류들이 여러가지 있어 

우선 잘 모르겠으면 이 포스트를 참고하도록 해봐 

https://juns-jc.tistory.com/160

 

Java_ 지역변수 , 인스턴스 변수 차이

자꾸 안드로이드 스튜디오에서 heap size 에 대해서 초과되었다고 경고 메시지를 주고 있다...뭐지 ?? 근데 언뜻 찾아보니 인스턴스 변수들의 사용량이 매우 커서 힙사이즈가 초과되었다는 얘기를

juns-jc.tistory.com

 

우선 Swift 에서의 변수부분을 설명할꺼야 

 

✅ Swift 변수의 종류

변수 종류선언 위치메모리 영역초기화 필요 여부특징

저장 프로퍼티 (Stored Property) 클래스/구조체 내부 Heap (클래스) / Stack (구조체) 필요 (옵셔널 제외) 인스턴스마다 개별 값 유지
타입 프로퍼티 (Type Property, static/ class) static 또는 class 사용 Data 영역 자동 초기화 모든 인스턴스가 공유
지역 변수 (Local Variable) 함수/메서드 내부 Stack 필요 선언된 블록 내에서만 사용 가능
매개변수 (Parameter) 함수/메서드의 인자 Stack 자동 초기화 함수 호출 시 전달받은 값 저장
계산 프로퍼티 (Computed Property) 클래스/구조체 내부 Heap (클래스) / Stack (구조체) X 값 저장 없이 연산을 통해 결과 반환

1️⃣ 저장 프로퍼티 (Stored Property)

클래스 또는 구조체 내부에서 값을 저장하는 변수
Java의 인스턴스 변수와 비슷하지만, 구조체에서는 값 타입이므로 Stack에 저장됨

📌 특징

  • let(상수) 또는 var(변수)로 선언 가능
  • 클래스에서는 Heap 메모리에 저장 (참조 타입)
  • 구조체에서는 Stack 메모리에 저장 (값 타입)
  • 옵셔널이 아니라면 반드시 초기화 필요! (init()에서 초기화 가능)

📌 예제

class Person {
    var name: String  // 저장 프로퍼티 (초기화 필요)
    var age: Int

    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

let p1 = Person(name: "Alice", age: 25)
print(p1.name) // "Alice"

 

  • name과 age는 저장 프로퍼티로, init()에서 초기화해줘야 함.
  • Person은 클래스이므로 Heap 메모리에 저장됨.

2️⃣ 타입 프로퍼티 (Type Property)

클래스나 구조체 자체에 속하며, 모든 인스턴스가 공유하는 변수
Java의 static 변수와 동일한 개념

📌 특징

  • static 키워드를 사용해 선언
  • class 키워드를 사용하면 서브클래스에서 재정의 가능
  • 프로그램 실행 시 초기화되고, 인스턴스 없이 접근 가능

📌 예제

class Counter {
    static var count = 0  // 타입 프로퍼티 (모든 객체가 공유)

    init() {
        Counter.count += 1
    }
}

let c1 = Counter()
let c2 = Counter()

print(Counter.count) // 2 (모든 객체가 공유)
 
  • count는 static 변수이므로 모든 인스턴스가 같은 값을 공유함.

3️⃣ 지역 변수 (Local Variable)

함수나 메서드 내부에서 선언된 변수로, 해당 블록 내에서만 사용 가능

📌 특징

  • Stack 메모리에 저장됨
  • 자동 초기화되지 않음 → 직접 초기화 필요
  • 함수 실행이 끝나면 사라짐

📌 예제

func printNumber() {
    let num = 10  // 지역 변수 (자동 초기화 X → 직접 초기화 필요)
    print("Number: \(num)")
}

printNumber()
// print(num)  // 오류! (num은 지역 변수라 접근 불가)
 
  • num은 함수 내부에서만 사용 가능.
  • 함수 실행이 끝나면 num은 메모리에서 제거됨.

4️⃣ 매개변수 (Parameter)

함수 호출 시 전달받아 사용되는 변수

📌 특징

  • Stack 메모리에 저장됨
  • 함수 호출 시 값이 전달되고, 함수 종료 후 사라짐
  • 기본적으로 상수(let)로 취급되므로 값 변경 불가 (inout으로 변경 가능)

📌 예제

func greet(name: String) { // 매개변수 name
    print("Hello, \(name)")
}

greet(name: "Alice") // "Hello, Alice"
 
  • name은 함수가 호출될 때 값이 전달됨.
  • 함수 실행 중에만 존재하고 끝나면 사라짐.

5️⃣ 계산 프로퍼티 (Computed Property)

저장된 값 없이, 특정 연산을 통해 값을 반환하는 변수

📌 특징

  • get과 set을 사용하여 값 계산 가능
  • Heap(클래스) / Stack(구조체)에 저장됨
  • 내부적으로 값을 저장하지 않고, 매번 연산하여 값을 반환

📌 예제

struct Rectangle {
    var width: Double
    var height: Double

    var area: Double { // 계산 프로퍼티
        return width * height
    }
}

let rect = Rectangle(width: 5, height: 10)
print(rect.area) // 50.0
  • area는 실제 값을 저장하지 않고, width * height의 결과를 반환.

✅ 변수 종류별 차이점 정리

변수 종류선언 위치저장 공간초기화 필요 여부특징

저장 프로퍼티 클래스/구조체 내부 Heap (클래스) / Stack (구조체) 필요 (옵셔널 제외) 인스턴스마다 개별 값 유지
타입 프로퍼티 static 또는 class 사용 Data 영역 자동 초기화 모든 인스턴스가 공유
지역 변수 함수/메서드 내부 Stack 필요 선언된 블록 내에서만 사용 가능
매개변수 함수/메서드의 인자 Stack 자동 초기화 함수 호출 시 전달받은 값 저장
계산 프로퍼티 클래스/구조체 내부 Heap (클래스) / Stack (구조체) X 값 저장 없이 연산을 통해 결과 반환

✅ 마무리

  • 저장 프로퍼티 → 일반적인 멤버 변수 (var name: String)
  • 타입 프로퍼티 → 모든 객체가 공유하는 변수 (static var count)
  • 지역 변수 → 함수 내부에서만 사용 (let num = 10)
  • 매개변수 → 함수 호출 시 전달된 값 (func greet(name: String))
  • 계산 프로퍼티 → 저장 없이 연산을 통해 값 반환 (var area: Double { width * height })

Swift에서 변수를 사용할 때 값 타입(구조체)과 참조 타입(클래스)의 차이도 고려해야 해.

 

 

별책부록

 

 

✅ 1. Property Observers (프로퍼티 옵저버)

willSet과 didSet을 이용하여 변수 값이 변경될 때 실행할 코드 지정

📌 특징

  • willSet → 값이 변경되기 직전에 실행
  • didSet → 값이 변경된 직후 실행
  • 초기화할 때는 호출되지 않고, 기존 값에서 변경될 때만 호출됨
  • 주로 UI 업데이트나 특정 이벤트 감지할 때 유용

📌 예제

class User {
    var name: String = "Unknown" {
        willSet(newName) { // 값이 변경되기 직전 실행
            print("이름이 \(name)에서 \(newName)로 변경될 예정!")
        }
        didSet { // 값이 변경된 직후 실행
            print("이름이 \(oldValue)에서 \(name)로 변경됨!")
        }
    }
}

let user = User()
user.name = "Alice"
/*
 출력:
 이름이 Unknown에서 Alice로 변경될 예정!
 이름이 Unknown에서 Alice로 변경됨!
 */

 

 

✅ willSet에서 newValue, didSet에서 oldValue를 사용할 수 있음!

🔹 언제 유용할까?

  • UI 업데이트 필요할 때
var score: Int = 0 {
    didSet {
        scoreLabel.text = "점수: \(score)"  // UI 자동 업데이트
    }
}
  • 값 변경을 감지하고, 로직을 실행할 때
var batteryLevel: Int = 100 {
    didSet {
        if batteryLevel < 20 {
            print("배터리가 부족합니다!")
        }
    }
}

✅ 2. Computed Property (계산 프로퍼티)

실제 값을 저장하지 않고, 연산을 통해 값을 반환하는 프로퍼티

📌 특징

  • 저장되지 않고 항상 연산을 통해 값을 반환
  • get만 사용하면 읽기 전용, get-set을 사용하면 읽기/쓰기 가능

📌 예제

struct Rectangle {
    var width: Double
    var height: Double

    var area: Double { // 계산 프로퍼티 (읽기 전용)
        return width * height
    }

    var halfWidth: Double { // 읽기/쓰기 가능
        get {
            return width / 2
        }
        set(newHalfWidth) {
            width = newHalfWidth * 2
        }
    }
}

var rect = Rectangle(width: 10, height: 5)
print(rect.area) // 50.0

rect.halfWidth = 8
print(rect.width) // 16.0

✅ get만 사용하면 읽기 전용, set을 추가하면 값 변경 가능!

🔹 언제 유용할까?

  • 실시간으로 값이 계산되어야 할 때
var temperatureInFahrenheit: Double {
    return temperatureInCelsius * 9/5 + 32
}

 

  • 특정 로직을 실행하고 값을 반환할 때
var isAdult: Bool {
    return age >= 18
}

✅ 3. Lazy Property (지연 저장 프로퍼티)

값이 실제로 사용될 때까지 초기화되지 않는 프로퍼티

📌 특징

  • lazy var 키워드를 사용
  • 초기값을 나중에 설정할 수 있음
  • 클로저({})를 이용해 초기화 가능
  • 구조체에서는 mutating 없이는 변경 불가능

📌 예제

class DataLoader {
    lazy var data: String = { // 실제로 접근할 때 실행됨
        print("데이터 로드 중...")
        return "로딩된 데이터"
    }()
}

let loader = DataLoader()
print("초기화 완료") // 여기서는 data 값이 아직 로딩되지 않음

print(loader.data) // 이 순간에 data가 로드됨!
/*
 출력:
 초기화 완료
 데이터 로드 중...
 로딩된 데이터
 */
 


🔹 언제 유용할까?

  • 메모리를 절약하고 싶을 때 (큰 데이터를 미리 로드하지 않음)
  • 네트워크 요청이 필요할 때
  • 초기화 비용이 큰 객체를 지연 생성할 때

✅ 4. Property Wrapper (속성 래퍼)

변수의 동작을 커스텀할 수 있는 기능

📌 특징

  • @propertyWrapper 키워드를 사용
  • 프로퍼티의 저장 방식과 동작을 커스텀 가능

📌 예제

@propertyWrapper
struct UpperCase {
    private var text: String = ""

    var wrappedValue: String {
        get { text }
        set { text = newValue.uppercased() } // 값을 대문자로 변환
    }
}

struct User {
    @UpperCase var name: String
}

var user = User()
user.name = "alice"
print(user.name) // "ALICE"
 

✅ wrappedValue를 통해 값을 자동으로 변환하거나, 특정 로직을 추가할 수 있음!

🔹 언제 유용할까?

  • 입력 값을 자동 변환하고 싶을 때 (@UpperCase, @Trimmed)
  • UserDefaults, Keychain 같은 저장 기능을 래핑할 때

✅ 5. Key-Value Observing (KVO)

객체의 속성 변화를 감지하는 기능 (@objc dynamic)

📌 특징

  • Objective-C의 KVO(Key-Value Observing) 기능 활용
  • @objc dynamic을 사용하여 감지 가능
  • addObserver(_:forKeyPath:options:context:)를 사용

📌 예제

import Foundation

class Person: NSObject {
    @objc dynamic var name: String = "Unknown"
}

class Observer: NSObject {
    var person: Person

    init(person: Person) {
        self.person = person
        super.init()

        person.addObserver(self, forKeyPath: "name", options: [.new, .old], context: nil)
    }

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {
        if keyPath == "name" {
            print("이름 변경됨: \(change?[.oldKey] as? String ?? "") → \(change?[.newKey] as? String ?? "")")
        }
    }
}

let person = Person()
let observer = Observer(person: person)
person.name = "Alice" // "이름 변경됨: Unknown → Alice"

 

 

✅ KVO는 SwiftUI와 Combine 사용 시 대체되는 경우가 많음!


✅ 마무리

기능설명언제 유용할까?

willSet / didSet 값 변경 전/후 실행 UI 업데이트, 이벤트 감지
계산 프로퍼티 저장 없이 연산하여 값 반환 실시간 값 계산
lazy var 필요할 때만 초기화 메모리 절약, 네트워크 요청
Property Wrapper 변수를 커스텀 자동 변환, UserDefaults
KVO (@objc dynamic) 속성 변경 감지 SwiftUI, Combine

각 기능을 적절히 사용하면 더 깔끔하고 성능 좋은 코드를 만들 수 있어! 🚀

'Swift' 카테고리의 다른 글

Swift_ intrinsicContentSize / Frame / bounds  (0) 2025.02.08
Swift_ CoreData Model , extension , Struct  (0) 2024.08.02
Swift_ CoreData 적용기...  (0) 2024.07.24
"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."