seong_hye, the developer

Swift) 문법 정리 - 속성(Property) & 함수(Method) 본문

IOS

Swift) 문법 정리 - 속성(Property) & 함수(Method)

seong_hye 2022. 7. 12.

 

구조체와 클래스는 둘 다 속성과 메서드로 이루어져 있는데

둘의 차이는 상속과 연관이 있는 메서드에서 차이가 나게 된다.

이를 제대로 알아보기 위해

속성과 함수에 대해 자세히 알아보도록 하자


속성

저장 속성(Stored Properties)

값이 저장되는 일반적인 속성(변수)

클래스/구조체의 틀에서 찍어낸 각 인스턴스가 가지는 고유의 데이터 저장 공간

변수(var)나 상수(let)로 선언 가능

객체의 초기화 시, 각 저장 속성은 반드시 값을 가져야 함

(기본값 설정 or 생성자에서 설정 or 옵셔널 타입으로 선언)

struct Person {
	var name = "seonghye"
    var age: Int?
}

 

지연 저장 속성(Lazy Stored Properties)

해당 속성이 반드시 처음부터 초기화가 필요하지 않은 경우에 초기화를 지연시킴

값에 대한 접근이 있어야 초기화(메모리 공간 생성)

lazy var로만 선언 가능

생성자에서 초기화하지 않기 때문에 반드시 기본값이 필요

 

사용하는 이유?

- 메모리 공간의 낭비를 막을 수 있음

- 지연 저장 속성으로 선언되는 속성이 다른 저장 속성을 이용해야 할 때

struct Person {
	var num = 1
	lazy var name = "seonghye"
    lazy var age = {
    	return num * 24
    }
}

 

계산 속성(Computed Properties)

속성의 형태를 가진 실질적 메서드 ( getter / setter )

메서드이기 때문에 인스턴스에 메모리 공간이 할당되어 있지 않음

var로만 선언 가능, 자료형까지 선언해야함

- get블록만 선언하면 읽기 전용(read-only) 계산 속성이 됨(필수 구현)

- set 블록은 선택적으로 구현할 수 있음( set만 구현하는 것은 불가능)

- set 블록에서 기본 파라미터 newValue가 제공됨 -> 받아오는 값

struct Person {
	var birth: Int = 0
    var age: Int {
    	get {
    		return 2024 - birth
        }
        set(age) {
        	self.birth = 2024 - age
        }
    }
}

var seonghye = Person()
seonghye.birth = 2000
seonghye.age 				// 24 (get 블록 실행)
seonghye.age = 23			//(set 블록 실행)
seonghye.birth				// 2001

 

타입 속성(Type Properties)

인스턴스에 속한 속성이 아니고 ,타입 자체가 속한 속성이기에

내/외부에서 Type.property로 접근해야함

저장 타입 속성을 주로 사용

 

어떤 경우에 선언하는가?

- 모든 인스턴스가 동일하게 가져야 하는 보편적인 속성

- 모든 인스턴스가 공유해야 하는 성격

 

1. 저장 타입 속성

static 키워드 사용 -> 상속시 재정의 불가

let/ var 선언 둘 다 가능

항상 기본값(초기값) 필요

자체적으로 지연(lazy) 속성의 성격을 가지므로, 호출시 메모리 할당

struct Circle {
	static let pi: Double = 3.14
    	static var count: Int = 0
}

Circle.pi		//3.14
Circle.count		//0

 

2. 계산 타입 속성

static(고정적인) 또는 class 키워드 사용

(static: 상속시 재정의 불가 / class: 상속시 재정의 가능)

var 키워드만 사용 가능

메서드이기 때문에 메모리 공간이 할당되어 있지 않음

struct Circle {
	static let pi = 3.14
		...
 	static var multiPi: Double {
    	return Circle.pi * 2
    }
}

let result = Circle.multiPi

 

(저장) 속성 감시자(Property Observers)

저장 속성의 변화시점을 관찰하는 실질적 메서드(타입/인스턴스 둘 다 가능은 함)

willSet - (값이 변할 때) 새 값이 저장되기 직전에 호출됨

didSet - (값이 변할 때) 새 값이 저장된 직후에 호출됨

 

저장속성 자체는 var로만 선언 가능

자료형을 선언하는 것은 일반 변수와 동일

둘 중 하나만 선언하면 됨(일반적으로 didSet으로 구현)

변수가 변하면 어떤 것을 업데이트 하려는 패턴 구현할 때 사용

ex) 프로필 사진, 상태 메시지

 

속성 감시자 추가 가능한 경우?

- 저장 속성( 상속한 저장속성은 재정의 불가, 감시자 추가는 가능)

- 상속한 계산 속성을 재정의해 속성 관찰자 추가 가능(단순 메서드 추가일 뿐)

class Profile {
    ...
    var statusMessage: String = "기본메시지" {
        willSet {
            print("\(statusMessage)에서 \(newValue)로 번경될 예정입니다")
        }
        didSet {
            print("\(oldValue)에서 \(statusMessage)로 변경되었습니다")
        }
    }
}

+ print문 앞이 같은 이전 내용 / 뒤가 새로운 내용을 나타냄


메서드(Method)

인스턴스 메시지

가장 기본적인 메서드

메서드 접근 시 인스턴스 이름으로 접근해야 함 

메서드이기 때문에 인스턴스에 메모리 공간이 할당되어 있지 않음

값 타입의 인스턴스 메서드에서 인스턴스 고유의 (저장) 속성을 수정할 수 없음

(수정하려면 명시정으로 mutating 키워드 필요)

+ 오버로딩 지원

struct Person {
	var name = "seonghye"
    
    func breathe() {
   		print("\(name)이 숨을 쉽니다")
    }
}

 

타입 메서드

인스턴스에 속한 속성이 아니고, 타입 자체에 속한 속성이기 때문에

내/외부에서 Type.method()로 접근해야함

static 또는 class 키워드 사용

(static: 상속시 재정의 불가 / class: 상속시 재정의 가능)

메서드이기 때문에 인스턴스에 메모리 공간이 할당되어 있지 않음

사용하는 경우?

타입에 해당하는 보편적인 동작의 경우

class Dog {
    static let species = "Dog"
    ...
    
    static func saySpecies() {
        print("종은 \(species)입니다")
    }
}

Dog.saySpecies()		// "종은 Dog입니다"

 

서브스크립트(Subscripts)

대괄호([ ])를 이용해서 접근가능하도록 만든 문법

 

(인스턴스) 서브스크립트

함수의 구현이 특별한 키워드인 subscript로 명명됨

메서드이기 때문에 인스턴스에 메모리 공간이 할당되어 있지 않음

메서드 접근 시, 인스턴스 이름으로 접근해야함 -> instance[파라미터] 

메서드 실행 시, 스택프레임을 만들고 필요한 데이터를 사용 -> 메서드 종료 시 스택프레임 사라짐

파라미터 2개 이상도 구현 가능함

계산속성과 형태는 유사 -> 리턴 타입이 있는 부분이 다름

struct TimeTable {
    var multiplier: Int = 3
    
    subscript(index: Int) -> Int {
        get {
            return multiplier * index
        }
    }
}

let threeMultiplier: TimeTable = TimeTable()

print("6 X 3 을 하면 \(threeMultiplier[6])이 나옵니다")		// "6 X 3 을 하면 18이 나옵니다"

struct Matrix {
    // 2차원 배열
    var data = [["1", "2", "3"], ["4", "5", "6"], ["7", "8", "9"]]
    
    // 2개의 파라미터를 받는 읽지 전용 서브스크립트 구현
    subscript(row: Int, column: Int) -> String? {
        get {
            if 2 < row || 2 < column {
                return nil
            }
            return data[row][column]
        }
    }
}

var mat = Matrix()

mat[0, 1]!   // "2"

 

타입 서브 스크립트

서브 스크립트 메서드 앞에 static 또는 class 키워드만 붙이면 됨

enum Planet: Int {
    case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
    
    static subscript(n: Int) -> Self {
        return Planet(rawValue: n)!
    }
}

let planet = Planet[3]

switch planet {
case .mercury:
    print("mercury 입니다")
case .venus:
    print("venus 입니다")
case .earth:
    print("earth 입니다")
case .mars:
    print("mars 입니다")
case .jupiter:
    print("jupiter 입니다")
case .saturn:
    print("saturn 입니다")
case .uranus:
    print("uranus 입니다")
case .neptune:
    print("neptune 입니다")
}				// "earth 입니다"

참고자료)

https://zrr.kr/qNHN

 

앨런 Swift문법 마스터 스쿨 (온라인 BootCamp - 2개월과정) 강의 - 인프런

Swift문법을 제대로 이해, 활용해보고자 하는 철학을 바탕으로 과정이 설계되었습니다. 코딩에 대해 1도 모르는 비전공자를 시작으로 네카라쿠배에 입사할 수 있는 초고급 수준까지 올리는 것을

www.inflearn.com

 

 

Comments