궁금한 내용을 검색해보세요!
이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
서근 개발노트
티스토리에 팔로잉
SWIFT/Grammar

Swift : 기초문법 [인스턴스 #4 클로저 사용 프로퍼티 기본값, 디이니셜라이저]

서근
QUOTE THE DAY

-
Written by SeogunSEOGUN

반응형

본 게시글은 yagom님의 Swift 프로그래밍 3판을 참고하여 작성되었습니다.

 

클로저를 사용한 프로퍼티 기본값 설정

사용자 정의 연산을 통해 저장 프로퍼티의 기본값을 설정하려면 클로저나 함수를 사용해 프로퍼티 기본값을 제공할 수 있다. 인스턴스를 초기화할 때 함수나 클로저가 호출되며 연산 결괏값을 프로퍼티 기본값으로 제공하게 된다. 그렇기에 클로저나 함수의 retrun 타입은 반드시 프로퍼티 타입과 일치해야 한다.

 

만약 프로퍼티의 기본값을 설정하기 위해 클로저를 사용하면 클로저가 실행되는 시점은 초기화할 때 인스턴스의 다른 프로퍼티 값이 설정되기 전이라는 걸 알아야 한다. 즉, 클로저 내부에서는 인스턴스의 다른 프로퍼티를 사용하여 연산할 수 없다.

  • 클로저 내부에서 다른 프로퍼티를 사용하여 연산 불가
  • 다른 프로퍼티에 기본값이 있어도 연산 불가
  • 클로저 내부에서 self 프로퍼티 사용 불가
  • 인스턴스 메서드 호출 불가

클로저를 통한 프로퍼티 기본값 설정

class SomeClass {
  let someProperty: SomeType = {
     // 새로운 인스턴스를 생성하고 사용자 정의 연산을 통한 후 return 함
     return someValue // someType과 동인한 타입이 리턴되어야함
  
  } () // 클로저를 실행하기 위한 소괄호. 
       // 만약 소괄호가 없다면 프로퍼티의 기본값은 클로저 그 자체가 되므로 주의
}

someProperty의 타입이 만약 Int 라면 반환 값도 Int로 타입이 동일해야 한다. 또, 클로저 뒤에 붙은 ( ) 소괄호는 클로저를 실행하기 위한 소괄호로써, 만약 소괄호가 없다면 프로퍼티의 기본값은 클로저의 그 자체가 되므로 주의해야 한다.

struct Student {
    var name: String?
    var number: Int?
}

class SchoolClass {
    var students: [Student] = {
        // 새로운 인스턴스 생성 후, 사용자 정의 연산을 통한 후 반환 함
        // 반환 되는 타입은 [Student]여야 함
        var arr: [Student] = [Student]()  
        return arr
    } ()
}

↪︎  클로저를 통한 student 프로퍼티 기본값 설정

 

일단 코드를 보면 Student 구조체와 SchoolClass가 있는데 students 프로퍼티는 Student 구조체의 인스턴스를 요소로 갖는 Array 타입이다. SchoolClass 클래스의 인스턴스를 초기화하게 되면 students 프로퍼티의 기본값을 제공하기 위해 클로저가 동작하게 한다.

struct Student {
    var name: String?
    var number: Int?
}

class SchoolClass {
    var students: [Student] = {
        var arr: [Student] = [Student]()
        
        for num in 1...10 {
            var student: Student = Student(name: nil, number: num)
            arr.append(student)
        }
        return arr
    } ()
}

let Aclass: SchoolClass = SchoolClass()
print(Aclass.students.count) //10

클로저가 동작하면 1부터 10까지의 학생을 생성하여 배열에 할당하게 되고, Aclass 인스턴스는 생성이 되는 동시에 students 프로퍼티에 10명의 학생이 있는 상태가 되게 된다.

TIP
 
 

iOS 활용
iOSUI 등을 구현할 때, UI 컴포넌트를 클래스의 프로퍼티로 구현하고, UI 컴포넌트 생성과 동시에 컴포넌트의 프로퍼티를 기본적으로 설정할 때 유용하게 사용된다.

인스턴스 소멸 디이니셜라이저

클래스의 인스턴스에서는 디이니셜라이저 Deinitializer를 구현할 수 있다. 단어 그대로 이니셜라이저의 반대 역할이다. 메모리에서 해제되기 직전 클래스 인스턴스와 관련해 원하는 정리 작업을 구현할 수 있다. 

 

디이니셜라이저는 클래스의 인스턴스가 메모리에서 소멸되기 바로 직전에 호출되고, deinit 키워드를 사용하여 디이니셜라이저를 구현하면 자동으로 호출된다. 

 

주의할 점은 클래스에서만 디이니셜라이저를 구현할 수 있다는 점이다.

  • deinit 키워드를 사용함
  • 인스턴스 소멸 직전에 호출됨
  • 모든 프로퍼티에 접근 가능. 프로퍼티 값 변경 가능
  • 클래스에서만 디이니셜라이저 구현 가능
  • 디이니셜라이저는 단 하나만 구현 가능
  • 이니셜라이저와는 다르게 매개변수를 갖지 않음. ( ) 소괄호 사용 안 함
  • 자동으로 호출하기 때문에 별도의 코드로 호출 불가
  • swift는 자동으로 필요하지 않은 인스턴스를 메모리에서 소멸시킴
  • 인스턴스 내부에 외부 자원을 사용하거나 큰 파일을 저장해줘야 하는 경우 디이니셜라이저 사용

디이니셜라이저는 인스턴스를 소멸하기 바로 직전에 호출되기 때문에 인스턴스의 모든 프로퍼티에  접근 가능하고 프로퍼티 값을 변경할 수 있다.

import Darwin

class SomeClass {
    deinit {
        print("인스턴스가 메모리에서 소멸됩니다.")
    }
}

var instance: SomeClass? = SomeClass()
instance = nil //인스턴스가 메모리에서 소멸됩니다.

디이니셜라이저를 간단하게 구현해보자면 위 코드처럼 사용하면 된다. 또 다른 예제를 한번 살펴보도록 하자!

class FileManager {
  var fileName: String
  
  init(fileName: String) {
    self.fileName = fileName
  }
  
  func modifyFile() {
     print("파일 수정 \(self.fileName)")
  }
  func openFile() {
     print("파일 열기 \(self.fileName)")
  }
  
  func writeFile() {
     print("파일 쓰기/저장 \(self.fileName)")
  }
  
  func closeFile() {
     print("파일 닫기 \(self.fileName)")
  }
  
  deinit {
   print("인스턴스를 메모리에서 소멸시킵니다.")
   self.writeFile()
   self.closeFile()
  }
}

var fileManager: FileManager? = FileManager(fileName: "서근 개발블로그.txt")

if let manager: FileManager = fileManager {
   manager.openFile()
   manager.modifyFile()
}

fileManager = nil

FileManager인스턴스가 파일을 불러와서 사용하고, 인스턴스 사용이 끝난 후에는 파일의 수정사항을 저장하고 다시 닫아주기 때문에 메모리에서 파일이 제거/해제되어야 하기 때문에 인스턴스가 메모리에서 해제되기 직전에 파일을 닫아주는 역할을 하게 된다.

 

여기서 디이니셜라이저를 활용하게 되면 메모리 관리에 탁월하고 설계한 로직에 따라 인스턴스가 메모리에서 해제되기 직전에 적절한 작업을 할 수 있다.

 

 

읽어주셔서 감사합니다🤟

 

 


잘못된 내용이 있으면 언제든 피드백 부탁드립니다.


서근


위처럼 이미지 와 함께 댓글을 작성할 수 있습니다.