Lazy / Private / Static

조재민·2023년 8월 8일
1
post-thumbnail

오늘 공부한 내용

  • lazy
  • private
  • static

lazy

  • 해당 속성이 처음으로 사용될 때까지 초기화를 지연시킴
  • 지연 초기화는 해당 속성이 필요한 시점에 초기화되므로, 불필요한 자원 장비를 방지하고 성능 최적화에 도움이 됨

단점

  • 처음 사용될 때에만 초기화가 발생 → 해당 속성이 처음 사용되는 시점에 초기화 작업이 실행되므로 초기 사용 시점에 약간의 성능 부하가 발생할 수 있음
  • 해당 변수가 처음 사용될 때 메모리에 할당됨 → 초기화가 지연되는 동안 변수가 필요없어도 메모리를 차지할 수도 있음 → 메모리 사용량이 중요할 때 조심
  • 다중 스레드 환경에서 사용할 경우 여러 스레드가 동시에 해당 변수를 접근하면서 초기화가 중복해서 발생할 수 있음 → 스레드 안정성 보장하려면 추가적인 동기화 매커니즘이 필요
  • 속성이 처음 사용될 때 한 번만 초기화됨 → 해당 값이 변경되지 않는 상황에서도 초기화가 발생함 → 불필요한 초기화를 초래

➢ 초기화가 많은 비용이 드는 경우에 유용하지만, 비용이 크지 않거나 다른 변수에 의존성이 있을 때 다른 초기화 방식을 고려해야 함

➢ 스레드 안정성 문제를 고려하여 다중 스레드 환경에서 사용할 경우 적절한 동기화를 해주어야 함

예제 코드

class ExampleClass {
    // lazy var를 사용하여 초기화가 지연되도록 설정
    lazy var expensiveProperty: String = {
        // 초기화가 많은 비용이 드는 작업 (여기서는 간단한 문자열 반환)
        print("Expensive property initialized.")
        return "Hello, Lazy World!"
    }()

    func doSomething() {
        print("Doing something...")
        // expensiveProperty를 사용할 때 초기화가 발생
        print(expensiveProperty)
    }
}

// ExampleClass 인스턴스 생성
let exampleObject = ExampleClass()

// doSomething() 메서드를 호출할 때 expensiveProperty가 초기화됨
exampleObject.doSomething()

// 이미 초기화되어 더 이상 초기화가 발생하지 않음
exampleObject.doSomething()

private

  • 변수(속성)에 접근 범위를 제한할 수 있음
  • 선언된 변수는 해당 클래스 또는 구조체 내에서만 접근 가능하도록 설정되며, 외부로부터 숨겨져 정보 은닉과 캡슐화를 구현하는 데 도움이 됨

특징

  1. 접근 제한: private var로 선언된 변수는 해당 클래스 또는 구조체 내에서만 접근 가능. 다른 클래스나 구조체에서는 직접 접근할 수 없으며, 해당 변수에 접근하는 메서드를 통해 간접적으로 접근해야 함.

  2. 정보 은닉: private var로 선언된 변수는 외부로부터의 접근을 차단하여 내부 구현의 세부 사항을 숨길 수 있음. 이로써 외부 코드에서 해당 변수의 값을 변경하는 것을 방지하고, 내부 구현의 안정성을 보장할 수 있음.

  3. 캡슐화: private var는 캡슐화를 구현하는데 사용됨.
    ( 캡슐화란? → 데이터와 해당 데이터를 조작하는 메서드를 하나의 단위로 묶는 것 )
    private var로 선언된 변수와 해당 변수를 조작하는 메서드는 동일한 범위 내에 존재하여 데이터와 메서드 간의 관계를 명확하게 표현할 수 있음.

  4. 유지보수: 해당 변수의 이름과 동작이 클래스나 구조체의 내부로 제한되기 때문에, 내부 구현을 변경해도 외부 코드에 영향을 덜 미침 → 코드 유지보수가 더 편리해짐

단점

  1. 접근 제한으로 인한 제한성: private var로 선언한 변수는 해당 클래스나 구조체 외부에서 접근할 수 없음.

  2. 코드 재사용의 어려움: private var로 선언한 변수는 해당 클래스나 구조체 내부에서만 사용 가능하므로, 다른 클래스에서 해당 변수를 활용할 수 없음.
    → 필요한 정보를 공유하거나 코드를 재사용해야 할 경우에는 다른 접근 제어 속성을 사용해야 함.

예제 코드

class ExampleClass {
    // private var로 선언된 변수는 클래스 내부에서만 접근 가능
    private var privateVariable: Int = 42

    // private var로 선언된 변수에 접근하는 private 메서드
    private func privateMethod() {
        print("Private method called. Private variable value:", privateVariable)
    }

    // public 메서드에서 private var와 private method를 사용
    func publicMethod() {
        print("Public method called.")
        privateVariable += 10
        privateMethod()
    }
}

let exampleObject = ExampleClass()

// publicMethod를 호출하면 privateVariable과 privateMethod에 접근
exampleObject.publicMethod()
// exampleObject.privateVariable // Error: Cannot access 'privateVariable' outside of its containing class
// exampleObject.privateMethod() // Error: Cannot access 'privateMethod' outside of its containing class
class Person {
    private var name: String
    private var age: Int

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

    func introduce() {
        print("안녕하세요, 저의 이름은 \(name)이고, \(age)살입니다.")
    }

    func updateName(newName: String) {
        name = newName
    }

    func updateAge(newAge: Int) {
        age = newAge
    }

    private func privateFunction() {
        print("이것은 private 함수입니다. 클래스 외부에서는 접근할 수 없습니다.")
    }
}

func main() {
    let person = Person(name: "Alice", age: 30)

    // private 변수에 접근할 수 없으므로 getter 메서드 이용
    person.introduce()

    // private 변수에 직접 접근하려면 컴파일 오류 발생
    // person.name = "Bob"

    // private 변수에 값을 변경하려면 public 메서드 이용
    person.updateName(newName: "Bob")
    person.updateAge(newAge: 32)

    // 변경된 값 확인
    person.introduce()

    // private 함수에 접근하려면 컴파일 오류 발생
    // person.privateFunction()
}

main()

static

특징

  • "타입" 프로퍼티/메서드
  • 변수, 메서드, 서브스크립트는 클래스나 구조체의 모든 인스턴스들이 공유함
    → 인스턴스를 생성하지 않아도 타입 이름을 통해 접근 가능
  • static 으로 선언되면 상속할 수 없음
    → 오버라이딩 불가, 타입 자체에만 속함
    ✷ 오버라이딩: 서브클래스가 슈퍼클래스로부터 상속받은 메서드를 재정의하는 것
  • 해당 클래스나 구조체의 인스턴스와 무관하게 정의됨.
    → 인스턴스와 독립적으로 동작하고 인스턴스의 상태와는 무관하게 동작

예제 코드

class A {
	func functionA(){
    	print("function A in class A"
    }
}

let a: A = .init()
a.function()

A.function() //error: instance member 'functionA' cannot be used on type 'A';

위 에러가 나는 예제 코드를 static을 사용해서 정상적으로 출력될 수 있도록 할 수 있다.


class A {
	static func isStatic() {
    	print("this is static function"
    }
    
    class func isClass() {
    	print("this is class function")
    }

}

A.isClass()
A.isStatic()

//this is class function
//this is static function 출력

클래스 인스턴스 만들지 않고 A.(함수명) 이렇게 썼는데도 오류없이 잘 출력된다.
→ static이 이걸 가능하게 해줌

<예시 1>

class Animal {
	static var nums = 0
    
    init() {
    	Animal.nums += 1
    }
}

let dog = Animal()
Animal.nums //1

let cat = Animal
Animal.nums //2

<예시 2>

class Student {
	static let section: String = "A" //static constant
    static var day: String = "Monday" //static vatriable
    var name: String = "Akash" //instance variable
    var rollNum: Int = 1 //instance variable
}
let student1 = Student() //Object 1
print(student1.name) //Akash
print(student1.rollNum) //1
student1.name = "Aman" //Settinf ob1 value to Aman
print(student1.name) //Aman
let student2 = Student() //Object 2
print(student2.name) //Akash
print(Student.section) //A
print(Student.day) //Monday
profile
“누군가는 너를 사랑하고 있다.”

1개의 댓글

comment-user-thumbnail
2023년 8월 13일

👍👍👍

답글 달기

관련 채용 정보