일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- DispatchGroup
- MainScheduler
- Python
- 개발기록
- AJAX
- Xcode
- 앱배포
- Swift
- JavaScript
- jQuery
- 계산기앱만들기
- FileOwner
- 웹
- subscript
- 스위프트
- 딩동말씀
- FLASK
- spring
- iOS계산기
- 계산기앱
- customclass
- 앱버전구하기
- 자바스크립트
- 파이썬서버
- 맥
- iOS앱배포
- iOS배포
- Xib
- 스프링
- ios
- Today
- Total
개발하는 뚝딱이
[swift] 인스턴스 생성 및 소멸 본문
책 <스위프트 프로그래밍 3판 ;야곰 지음> 을 정리한 글입니다.
1.0 인스턴스 생성
- 이니셜라이저를 통해 해당 타입의 새로운 인스턴스를 생성
- init 메서드는 struct, enum의 구현부와 extension에서 구현 가능하지만 class는 구현부에서만 가능
class SomeClass{
init() {
// ...
}
}
struct SomeStruct {
init() {
// ...
}
}
enum SomeEnum {
case someCase
init() {
// 열거형은 초기화할 때 반드시 case 중 하나가 되어야 함
self = .someCase
// ...
}
}
1.1 프로퍼티 기본값
- 구조체와 클래스의 인스턴스를 처음 생성할 때, 옵셔널 저장 프로퍼티를 제외한 모든 저장 프로퍼티에 초깃값 (initial value)을 할당해야 함
- 프로퍼티 기본값이 있으면 초깃값을 할당하지 않아도 초기화 가능
- 이니셜라이저를 통해 초깃값이 할당될 때 프로퍼티 감시자 메소드는 호출되지 않음
struct Area {
var squareMeter: Double
init() {
squareMeter = 0.0 // initial value 할당
}
}
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
1.2 이니셜라이저 매개변수
- 사용자 정의 이니셜라이저를 만들면 기존의 기본 이니셜라이저, 멤버와이즈 이니셜라이저 사용 불가
- 사용자 정의 이니셜라이저를 정의하고, 기본 이니셜라이저나 멤버와이즈 이니셜라이저를 사용하고 싶으면 익스텐션으로 사용자 정의 이니셜라이저를 구현하면 됨
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.587
let roomTwo: Area = Area(fromSquareMeter: 33.06)
print(roomTwo.squareMeter) // 33.06
let roomThree: Area = Area(value: 30.0)
let roomFour: Area = Area(55.0)
Area() // 에러
1.3 옵셔널 프로퍼티 타입
- 초기화 과정에서 값을 초기화하지 않아도 되는 저장 프로퍼티의 경우 옵셔널로 선언
- 초기화 과정에서 값을 지정해주기 어려운 저장 프로퍼티의 경우 옵셔널로 선언
- 옵셔널로 선언한 저장 프로퍼티는 초기화 과정에서 값을 할당해주지 않으면 nil이 자동 할당
class Person {
var name: String?
var age: Int?
init(name: String) {
self.name = name
}
}
let jin: Person = Person(name: "Jin")
print(jin.name) // "jin"
print(jin.age) // nil
jin.age = 99
print(jin.age) // 99
1.4 상수 프로퍼티
- let으로 선언한 저장 프로퍼티
- 인스턴스 초기화 과정에서만 값 할당 가능, 이후에는 변경 불가능
- 클래스 인스턴스의 상수 프로퍼티는 프로퍼티가 정의된 클래스에서만 초기화 가능
- 해당 클래스를 상속받은 자식클래스의 이니셜라이저에서는 부모클래스의 상수 프로퍼티 값을 초기화 할 수 없음
1.5 기본 이니셜라이저와 멤버와이즈 이니셜라이저
- 기본 이니셜라이저 (init메소드)
- 멤버와이즈 이니셜라이저 (타입 이름을 사용한 이니셜라이저 )
- 사용자 정의 이니셜라이저를 정의하지 않으면 클래스나 구조체는 모든 프로퍼티에 기본값이 지정되어 있다는 전제하에 기본 이니셜라이저를 사용
- 기본 이니셜라이저는 저장 프로퍼티의 기본값이 모두 지정되어 있고 동시에 사용자 정의 이니셜라이저가 정의되어 있지 않은 상태에서 제공
- 구조체는 사용자 정의 이니셜라이저인 멤버와이즈 이니셜라이저를 기본으로 제공
- 클래스는 멤버와이즈 이니셜라이저를 지원하지 않음
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)
let size: Size = Size(width: 50.0, height: 50.0)
// 구조체의 저장 프로퍼티에 기본값이 있는 경우
// 필요한 매개변수만 사용하여 초기화
let somePoint: Point = Point()
let someSize: Size = Size(width: 50)
let anotherPoint: Point = Point(y: 100)
1.6 초기화 위임
- 값 타입인 구조체와 열거형은 코드의 중복을 피하기 위해 이니셜라이저가 다른 이니셜라이저에게 일부 초기화를 간단하게 위임 가능함
- 값 타입에서 이니셜라이저가 다른 이니셜라이저를 호출하려면 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)
print(younger) // middle
younger = Student(bornAt: 2002, currentYear: 2020)
print(younger) // high
1.7 실패 가능한 이니셜라이저
- Failable initializer
- 클래스, 구조체, 열거형 등에 모두 정의할 수 있음
- 실패했을 때 nil 반환, 반환타입이 옵셔널 / 성공했을 때는 값을 반환하지 않음
- init 대신에 init? 사용
- 실패하지 않는 이니셜라이저와 실패 가능한 이니셜라이저를 같은 이름과 같은 매개변수 타입을 갖도록 정의할 수 없음
class Person {
let name: String
var age: Int?
init?(name: String) {
if name.isEmpty {
return nil
}
self.name = name
}
init?(name: String, age: Int) {
if name.isEmpty || age < 0 {
return nil
}
self.name = name
self.age = age
}
}
let sue: Person? = Person(name: "Sue", age: 99)
if let person: Person = sue {
print(person.name)
} else {
print("Person wasn't initialized")
}
// Sue
let chope: Person? = Person(name: "chope", age: -10)
if let person: Person = chope {
print(person.name)
} else {
print("Person wasn't initialized")
}
// Person wasn't initialized
let eric: Person? = Person(name: "", age: 30)
if let person: Person = eric {
print(person.name)
} else {
print("Person wasn't initialized")
}
// Person wasn't initialized
1.8 함수를 사용한 프로퍼티 기본값 설정
- 사용자 정의 연산을 통해 저장 프로퍼티 기본값을 설정할 때, 클로저나 함수 사용 가능
- 인스턴스 초기화할 때 함수나 클로저가 호출되면서 연산 결과값이 프로퍼티 기본값으로 제공
- 클로저나 함수의 반환 타입은 프로퍼티의 타입과 일치해야 함
- 클로저 사용 시, 클로저 내부에서 인스턴스의 다른 프로퍼티를 사용하여 연산할 수 없음 (다른 프로퍼티 값이 설정되기 전)
- 클로저 내부에서 self 프로퍼티 사용할 수 없으며 인스턴스 메서드 호출도 할 수 없음
// 클로저를 통한 프로퍼티 기본값 설정
class SomeClass {
let someProperty: SomeType = {
// 새로운 인스턴스 생성하고 사용자 정의 연산을 통한 후 반환
// 반환되는 값의 타입은 SomeType과 같아야 함
return someValue
}()
}
// 클로저를 통한 student 프로퍼티 기본값 설정
struct Student {
var name: String?
var number: Int?
}
class SchoolClass {
var students: [Student] = {
// 새로운 인스턴스를 생성하고 사용자 정의 연산을 통한 후 반환
// 반환되는 값의 타입은 [Student] 타입이어야 함
var arr: [Student] = [Student]()
for num in 1...15 {
var student: Student = Student(name: nil, number: num)
arr.append(student)
}
return arr
}()
}
let myClass: SchoolClass = SchoolClass()
print(myClass.students.count) // 15
2. 인스턴스 소멸
- 클래스의 인스턴스는 디이니셜라이저 Deinitializer를 구현
- 디이니셜라이저는 메모리에서 해제되기 직전 클래스 인스턴스와 관련하여 원하는 정리작업을 구현
- 클래스의 인스턴스가 메모리에서 소멸되기 바로 직전에 호출
- 디이니셜라이저는 클래스의 인스턴스에서만 구현 가능
- 스위프트는 인스턴스가 더 이상 필요하지 않으면 자동으로 메모리에서 소멸시킴
- 소멸시킬 때 디이니셜라이저를 사용해 별도의 메모리 관리 작업을 할 필요는 없지만, 외부 자원을 사용하는 등의 경우에 필요함
- 하나만 구현가능하며 매개변수가 없고 자동호출되므로 별도의 코드로 호출 불가
// 디이니셜라이저의 구현
class SomeClass {
deinit {
print("Instance will be deallocated immediately")
}
}
var instance: SomeClass? = SomeClass()
instance = nil // Instance will be deallocated immediately
// FileManager 클래스의 디이니셜라이저 활용
class FileManager {
var fileName: String
init(fileName: String) {
self.fileName = fileName
}
func openFile() {
print("Open File: \(self.fileName)")
}
func modifyFile() {
print("Modify 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
manager.modifyFile() // Modify File: abc.txt
manager.closeFile() // Close File: abc.txt
}
fileManager = nil
// Deinit instance
// Write File: abc.txt
// Close File: abc.txt
'swift' 카테고리의 다른 글
[swift] 클로저 (0) | 2020.05.07 |
---|---|
[swift] 접근제어 (0) | 2020.05.02 |
[swift] 옵셔널 (0) | 2020.04.28 |
[swift] 메소드 (method) (0) | 2020.04.27 |
[swift] 프로퍼티(property) (0) | 2020.04.15 |