[Swift] 인스턴스

김태형·2023년 3월 22일
0

Swift

목록 보기
12/22
post-thumbnail

오늘은 인스턴스에 대해 정리해보려고 한다.
인스턴스란 클래스나 구조체 등에 소속된 개별적인 객체를 말한다.
객체 지향 언어에서 객체가 메모리에 할당되어 실제로 사용될 때 인스턴스라고 말한다.
객체와 인스턴스의 차이점은 객체는 '선언'하는 것이고, 인스턴스는 객체를 '실체화'하는 것이라고 생각하면 될 것 같다.


인스턴스 생성 (in Swift)

우리가 인스턴스를 사용하기 위해서는 초기화를 진행해야 한다. 초기화는 새로운 인스턴스를 사용할 준비를 하기 위해 저장 프로퍼티의 초깃값을 설정하는 등의 일을 진행하는 것으로, 초기화를 해줘야 인스턴스를 사용할 수 있다.

초기화를 해주는 방법 중 하나로 이니셜라이저를 정의하여 초기화를 직접 구현할 수 있는데, 이니셜라이저를 정의하면 새로운 인스턴스를 생성할 수 있는 메소드가 된다.
이니셜라이저는 반환 값이 없고, 그저 인스턴스의 사용을 위해 초기화하는 용도이다.


이니셜라이저 (init)

  • 새로운 인스턴스를 생성하기 위해 호출되는 키워드

초깃값(initial value)과 기본값(default value)

  • 구조체와 인스턴스는 처음 생성할 때 초깃값을 할당해야 함
  • 하지만 프로퍼티의 기본값을 할당하면 초깃값을 할당하지 않더라도 기본값으로 프로퍼티의 값이 초기화된다.
struct Area {
	var squareMeter: Double

	init() {    //init으로 인스턴스 초기화
		squareMeter = 0.0    //프로퍼티에 초기값 할당
	}
}

let room: Area = Area()
print(room.squareMeter)    //0.0



struct Area {
	var squareMeter: Double = 0.0    //프로퍼티 기본값 할당
}

let room: Area = Area()
print(room.squareMeter)    //0.0

사용자 정의 이니셜라이저 (이니셜라이저 매개변수)

  • 인스턴스를 초기화하는 과정에 필요한 값을 전달받을 수 있음
  • 사용자 정의 이니셜라이저를 만들면 기본 이니셜라이저(init())을 별도로 구현하지 않는 이상 기본 이니셜라이저를 사용할 수 없음
//사용자 정의 이니셜라이저
struct Area {
    var squareMeter:Double
    
    init(fromPy py: Double) {    //첫 번째 이니셜라이저
        squareMeter = py * 3.3058
    }
    
    init(fromSquareMeter squareMeter: Double) {     //두 번째 이니셜라이저
        self.squareMeter = squareMeter
    }
    
    init(value: Double) {   //세 번째 이니셜라이저
        squareMeter = value
    }
    
    init(_ value: Double) { //네 번째 이니셜라이저
        squareMeter = value
    }
}


let roomOne: Area = Area(fromPy: 15.0)
print(roomOne.squareMeter    //49.857

let roomTwo: Area = Area(froomSquareMeter: 33.06)
print(roomTwo.squareMeter)    //33.06

let roomThree: Area = Area(value: 30)    //30

let roomFour: Area = Area(10)    //10

Area()  //에러 : 사용자 정의 이니셜라이저를 사용했는데, 기본 이니셜라이저를 정의하지 않았기 때문

옵셔널 프로퍼티 타입

  • 인스턴스가 사용되는 동안에 값을 꼭 갖지 않아도 되는 저장 프로퍼티가 있다면 해당 프로퍼티를 옵셔널로 선언할 수 있음
  • 또한 초기화 과정에서 값을 지정해주기 어려운 경우 저장 프로퍼티를 옵셔널로 선언할 수 있음
  • 옵셔널 프로퍼티는 값이 할당되어 있지 않다면 nil로 할당됨
class Person {
    var name: String
    var age: Int?   //옵셔널로 프로퍼티 할당
    
    init(name: String) {
        self.name = name
    }
}

let ted: Person = Person(name: "Ted")   //Ted
print(ted.age)  //nil
ted.age = 99
print(ted.age)  //Optional(99)

상수 프로퍼티

  • 만약 할당된 값이 변하지 않는 상수로 만들고 싶다면 프로퍼티를 상수(let)로 선언하면 됨
  • 하지만 상수로 선언된 프로퍼티는 인스턴스를 초기화하는 과정에서만 값을 할당할 수 있으며, 처음 할당된 이후로는 값을 변경할 수 없음
class Person {
    let name: String    //상수 프로퍼티 (let)
    var age: Int?   //옵셔널로 프로퍼티 할당
    
    init(name: String) {
        self.name = name
    }
}

let ted: Person = Person(name: "Ted")   //Ted
ted.name = "rlaxogud"   //에러

기본 이니셜라이저와 멤버와이즈 이니셜라이저

  • 저장 프로퍼티를 선언할 때 기본값을 지정해주지 않으면 이니셜라이저에서 초깃값을 설정해야함
    --> 하지만 프로퍼티 때문에 매번 이니셜라이저를 추가하고 변경하는 것은 귀찮은 일임!

  • 구조체에서는 이니셜라이저를 구현하지 않으면 프로퍼티의 이름을 매개변수로 갖는 이니셜라이저인 '멤버와이즈 이니셜라이저'를 제공함 (클래스는 제공하지 않음)
    --> 이로 인해 구조체에서는 이니셜라이저를 굳이 선언해주지 않아도 됨!!

struct Point {
    var x: Double = 0.0
    var y: Double = 0.0
}

struct Size {
    var width: Double = 0.0
    var height: Double = 0.0
}

let point: Point = Point(x: 0,y: 0)  //Point를 class로 바꾸면 이렇게 사용하지 못함 (init이 없기 때문에 -> class는 멤버와이즈 이니셜라이저를 제공하지 않기 때문에)
let size: Size = Size(width: 50, height: 50)

let somePoint: Point = Point()
print(somePoint)

let someSize: Size = Size(width: 50)    //필요한 매개변수만 초기화 할 수도 있음

let anotherPoint: Point = Point(y: 40)

정리

사용자 정의 이니셜라이저 : 사용자가 이니셜라이저에 프로퍼티(변수, 상수 등)를 정의해놓은 것

사용자 정의 이니셜라이저를 정의해주지 않으면 모든 프로퍼티에 기본값이 지정되어 있다는 전제하에 기본 이니셜라이저를 사용함

기본 이니셜라이저 : 프로퍼티 기본값으로 프로퍼티를 초기화해서 인스턴스를 생성

  • 저장 프로퍼티의 기본값이 모두 지정되어 있고, 동시에 사용자 정의 이니셜라이저가 정의되어 있지 않은 상태에서 제공됨

초기화 위임

  • 값 타입인 구조체와 열거형은 초기화 위임을 간단하게 구현할 수 있지만,
    클래스는 ‘상속’을 지원하기 때문에 간단한 초기화 위임도 할 수 없음
  • 값 타입에서 다른 이니셜라이저를 호출하려면 self.init을 사용해야함
    —> self.init을 사용하는 것 자체가 사용자 정의 이니셜라이저를 정의하고 있는 것임!!
  • 사용자 정의 이니셜라이저를 정의하면 기본 이니셜라이저와 멤버와이즈 이니셜라이저를 사용할 수 없음
    따라서 초기화 위임을 하려면 최소 두 개 이상의 사용자 정의 이니셜라이저를 정의해야 함!!
    (기본 이니셜라이저 + 사용자 정의 이니셜라이저)
  • 코드를 중복으로 쓰지 않고도 효율적으로 여러 개의 이니셜라이저를 생성할 수 있음
enum Student {
    case elementary, middle, high
    case none
    
    init() {    //사용자 정의 이니셜라이저가 있어서, init()을 구현해줘야 기본 이니셜라이저를 사용할 수 있음
        self = .none
    }
    
    init(koreanAge: Int) {  //사용자 정의 이니셜라이저
        switch koreanAge {
        case 8...13:
            self = .elementary
        case 14...16:
            self = .middle
        case 17...19:
            self = .high
        default:
            self = .none
        }
    }
    
    init(bornAt: Int, currentYear: Int) {   //사용자 정의 이니셜라이저
        self.init(koreanAge: currentYear - bornAt + 1)
    }
}


var younger: Student = Student(koreanAge: 16)   //middle
younger = Student(bornAt: 1998, currentYear: 2016)  //high

실패 가능한 이니셜라이저

  • 실패 가능성을 내포한 이니셜라이저
  • 이니셜라이저를 잘못 전달하는 등의 상황 때 인스턴스 초기화에 실패할 수 있음
  • init? 키워드
  • 실패 가능한 이니셜라이저는 특정 값을 반환하지는 않음
    • 초기화 실패 시 nil, 초기화 성공 시 초기화의 성공 or 실패 여부를 표현
  • 열거형일 때 유용함
    • 특정 case에 맞지 않는 값이 들어올 때
class Person {
    let name: String
    var age: Int?
    
    init?(name: String) {   //실패 가능한 이니셜라이저
        if name.isEmpty {
            return nil
        }
        self.name = name
    }
}

let ted: Person? = Person(name: "Ted")

디이니셜라이저 (인스턴스의 소멸)

  • 메모리에서 소멸되기 바로 직전에 호출
  • deinit
  • 클래스의 인스턴스에서만 구현할 수 있음
  • 스위프트에서는 인스턴스가 필요없다면 자동으로 메모리에서 해제시켜줌 (ARC)
    —> 디이니셜라이저를 사용해 별도의 메모리 관리 작업을 할 필요는 없음
  • 하지만 인스턴스 내부에서 외부 자원을 사용했다면(인스턴스 내부에서 외부 파일을 열어보는 등) 인스턴스 소멸 직전에 파일을 닫아주는 등의 작업을 해야 함
class FileManager {
    var fileName: String
    
    init(fileName: String) {
        self.fileName = fileName
    }
    func openFile() {
        print("Open File: \(self.fileName)")
    }
    func writeFile() {
        print("Write File: \(self.fileName)")
    }
    func closeFile() {
        print("Close File: \(self.fileName)")
    }
    deinit {
        print("Deinit instance")
        self.writeFile()
        self.closeFile()
    }
}

var fileManager: FileManager? = FileManager(fileName: "abc.txt")
if let manager: FileManager = fileManager {
    manager.openFile()  //Open File: abc.txt
}

fileManager = nil   //Deinit instance
                    //Write File: abc.txt
                    //Close File: abc.txt


[출처] 스위프트 프로그래밍 (야곰), 야곰의 스위프트 기초문법 강좌, 개발하는 정대리 스위프트 강좌

0개의 댓글