[Swift] Day9 - Structs, part two

한철희·2023년 2월 28일
0

100 DaysOfSwift

목록 보기
5/11

그래도 클로저보다는 이해가 잘 되는듯 합니다?
이제 곧 개강인데 학교다니면서도 꾸준히 하도록 해보겠습니다 허허
그럼 가보실까요


Initializers

Initializers는 보통 '초기화'라고 합니다
음.. 이것도 예시를 바로 보는게 더 도움이 될 거같네요

한 개의 프로퍼티가 있는 User구조체가 있다고 해볼게요

struct User {
    var username: String
}

여기서 인스턴스를 생성하려면 username값을 줘야합니다

var users = User(username: "twostraws)

이렇게 말이죠
빼먹으면 에러가 나게됩니다

여기서 밑에 init(username:) 부분 보이시죠?
저게 바로 초기화와 관련된 부분인데요
실제로 작성을 하면 아래와 같이 됩니다.

struct User {
    var username: String

    init() {
        username = "Anonymous"
        print("Creating a new user!")
    }
}

작성하면서 주의할 점은 init구문이 끝나기전에 모든 프로퍼티에 값을 지정해줘야한다는 것입니다

이제 인자를 안 받아도 되면 아래와 같이 작성하면 됩니다

var user = User()
user.username = "twostraws"

username은 초기화에서 할당해준 기본값을 반환하고
두 번째 username은 이후 할당해준 twostraws를 반환하는걸 확인했습니다.


Referring to the current instance

메소드 내부에는 self라고 하는 특별한 상수가 존재합니다.
이게 특히 프로퍼티와 이름이 같은 초기화를 해야할 때 유용하게 사용됩니다
코드를 한번 보실까요

struct Person {
    var name: String

    init(name: String) {
        print("\(name) was born!")
        self.name = name
    }
}

name프로퍼티를 가지는 Person구조체입니다
그리고 name 매개변수를 받는 name initializer를 작성하는데
self이때 프토퍼티와 파라미터의 구분을 해줍니다
self.name은 프로퍼티고 name은 파라미터(매개변수)입니다


Lazy properties

성능 최적화를 위해서 Swift는 몇몇 프로퍼티들을 필요할 때만 생성할 수 있도록 합니다.
예시로 FamilyTree구조체를 보죠 단순한 구조체지만 가계도를 만드는데는 생각보다 시간이 들어갑니다

struct FamilyTree {
    init() {
        print("Creating family tree!")
    }
}

그리고 FamilyTree 구조체는 Person 구조체에서 프로퍼티처럼 사용될 수도 있습니다

struct Person {
    var name: String
    var familyTree = FamilyTree()

    init(name: String) {
        self.name = name
    }
}

var ed = Person(name: "Ed")

그런데 만약 가계도가 모든 사람에게 필요하지 않는다면 어떨까요?
familyTree앞에 lazy라는 키워드를 붙이면 됩니다

lazy var familyTree = FamilyTree()

그러면 접근을 할 때만 가계도를 생성하게 합니다

ed.familyTree

따라서 “Creating family tree!”을 보고싶다면 최소한번은 프로퍼티를 호출해야하는거죠

전체 코드입니다


Static properties and methods

우리가 여태 만든 모든 프로퍼티와 메소드는 구조체의 개별 인스턴스에 속하죠
그 말은 우리가 Student라는 구조체를 만든다면 각각의 프로퍼티와 메소드를 가지는 개별 인스턴스를 만들 수 있다는 소립니다

struct Student {
    var name: String

    init(name: String) {
        self.name = name
    }
}

let ed = Student(name: "Ed")
let taylor = Student(name: "Taylor")

그리고 static 키워드를 통해 특정 프로퍼티와 메소드를 구조체의 모든 인스턴스가 공유할 수 있도록 할 수 있습니다

확인해보기 위해서 Student구조체에 static property를 추가해보죠
학생이 반에 학생이 몇명인지 나타낼 건데요.
새로 인스턴스를 생성할때 마다 1을 더해줄겁니다

struct Student {
    static var classSize = 0
    var name: String

    init(name: String) {
        self.name = name
        Student.classSize += 1
    }
}

그리고 classSize 인스턴스가 아니라 구조체에 속하기 때문에 호출할 때는 아래와 같이 해야합니다

print(Student.classSize)


값이 증가함을 확인할 수 있네요


Access control

Access control은 어떤 코드가 프로퍼티와 메소드를 사용할 수 있는지 제한하는 문법입니다
이게 중요한 이유는 어떤 프로퍼티들은 다른 코드가 읽게하고 싶지 않기 때문이죠

아래의 Person 구조체는 사회보장넘버를 저장하는 id라는 프로퍼티를 가집니다

struct Person {
    var id: String

    init(id: String) {
        self.id = id
    }
}

let ed = Person(id: "12345")

당연하지만 이런 개인정보를 타인이 보게하면 안되겠죠?
그래서 private키워드를 사용해 아래와 같이 코드를 수정했습니다

struct Person {
    private var id: String

    init(id: String) {
        self.id = id
    }
}

이렇게 하면 ed.id를 해도 값을 읽을수가 없습니다

그렇죠?
그럼 이제 이걸 어떻게 해서 접근할 수 있느냐
Person구조체 내부의 함수를 통해서만 접근할 수 있어요

struct Person {
    private var id: String

    init(id: String) {
        self.id = id
    }

    func identify() -> String {
        return "My social security number is \(id)"
    }
}


이렇게 말이죠
public이라는 옵션도 있는데요, 이건 다른 코드들이 프로퍼티와 메소드에 접근하게 해줍니다.


Summary

  1. 구조체를 통해 프로퍼티와 메소드를 가지는 나만의 타입을 만들 수 있다
  2. 저장 프로퍼티나 연산 프로퍼티를 사용해서 값을 계산하게 할 수 있다
  3. 메소드 내부의 프로퍼티 값을 변경하고 싶으면 mutating을 붙여줘야한다
  4. 초기화는 구조체를 만드는 특별한 방법이다.기본적으로 memberwise initializer가 제공되지만 직접 생성할 경우엔 모든 프로퍼티에 값을 지정해줘야한다.
  5. self를 통해 메소드 내부의 최근 인스턴스를 참조할 수 있다
  6. lazy 키워드는 스위프트가 처음 사용할 때 프로퍼티를 만들도록 한다
  7. static키워드로 모든 인스턴스에 프로퍼티나 메소드를 공유할 수 있다.
  8. Access control는 어떤 코드가 프로퍼티와 메소드를 사용할 수 있는지 정할 수 있다.
profile
초보 개발자 살아남기

0개의 댓글