Swift

Swift - 5. 객체 지향 프로그래밍 기초

iosos 2023. 12. 27. 19:26

 

객체(인스턴스)란

  • 소프트웨어 애플리케이션을 구축하는 블록으로 쉽게 사용하고 재사용 할 수 있는 독립적인 기능 모듈
  • 작업을 수행하기 위한 객체나 인스턴스에서 접근되고 호출되는 속성(프로퍼티)과 함수(메서드)로 구성
  • 객체를 구성하는 데이터 변수와 함수를 포괄적으로 클래스 멤버라고 함

 

클래스

  • 객체가 생설될 때의 모습 정의
  • 메서드, 프로퍼티 정의

 

 

클래스 선언

  • 새로운 스위프트 클래스를 선언할 때, 새롭게 만드는 클래스가 어떤 부모 클래스에서 파생되었는지 지정
  • 클래스에 포함할 프로퍼티와 메서드 정의
// 기본 구문 
class 클래스 이름 : 부모 클래스 {
	// 프로퍼티
	// 인스턴스 메서드 
	// 타입 메서드
}
  • 프로퍼티 : 클래스 내에 포함될 변수나 상수 정의
  • 인스턴스 메서드, 타입 메서드 : 클래스에서 호출되는 메서드들과 클래스의 인스턴스 정의
    • 특정 작업을 수행하는 클래스 고유의 함수

 

// BackAccount 클래스
class BackAccount {
    
}
  • 클래스 이름은 각 단어의 첫 번째 문자를 대문자로 선언 (UpperCamelCase)
  • 프로퍼티 이름은 lowerCamelCase

 

 

 

클래스에 인스턴스 프로퍼티 추가

  • 객체지향 프로그래밍의 핵심 목적 : 데이터 캡슐화
  • 데이터 캡슐화 : 클래스에 저장되고 접근될 수 있는 데이터는 오직 해당 클래스 내에 정의된 메서드만을 통해서 접근
  • 프로퍼티(인스턴스 변수) : 클래스 내의 캡슐화된 데이터
class BackAccount {
    var accountBalance : Float = 0  // 계좌에 남은 잔고
    var accountNumber : Int = 0     // 계좌 번호
}

 

 

메서드 정의

  • 클래스의 성격에 맞는 특정 작업을 수행하기 위해 호출되는 코드 루틴
  • 타입 메서드 vs 인스턴스 메서드
    • 타입 메서드 : 클래스 레벨에서 동작 (ex. 클래스의 새로운 인스턴스 생성)
      • 인스턴스 메서드와 동일하지만, 선언부 앞에 class 키워드가 붙음
    • 인스턴스 메서드 : 클래스의 인스턴스에 대한 작업 (ex. 두 개의 프로퍼티에 대한 연산)
      • 자신이 속하게 될 클래스의 여는 괄호와 닫는 괄호 안에 선언
class BackAccount {
    var accountBalance : Float = 0  // 계좌에 남은 잔고
    var accountNumber : Int = 0     // 계좌 번호
    
    // 인스턴스 메서드
    func displayBalance(){
        print("Number \(accountNumber)")
        print("Current balance is \(accountBalance)")
    }
    
    // 타입 메서드
    class func getMaxBalance(){
        return 100000.00
    }
}
  • 클래스를 설계할 때, 이 클래스에 저장할 수 있는 최대 금액을 알기 위하여 클래스 자신의 타입 메서드를 호출
  • 이를 통해 애플리케이션이 클래스 인스턴스를 생성하지 않아도 클래스 자체에서 새로운 고객의 정보 저장 식별 가능

 

 

 

클래스 인스턴스 선언 및 초기화

  • 위 클래스를 가지고 작업을 하려면 인스턴스를 생성해야 함
// 인스턴스 생성
var account1 : BankAccount = BankAccount()

 

 

클래스 인스턴스 초기화 및 소멸

  • 클래스는 인스턴스를 생성하는 시점에 해야 할 초기화 작업이 있을 수 있음
  • init 메서드 안에서 구현
  • BackAccount 클래스 내에선, 클래스 인스턴스가 생성될 때마다 계좌번호와 잔액 초기화 해야 함
class BackAccount {
    var accountBalance : Float = 0  // 계좌에 남은 잔고
    var accountNumber : Int = 0     // 계좌 번호
    
	// 초기화
    init(number : Int, balance : Float){
        accountNumber = number
        accountBalance = balance
    }
    
    // 인스턴스 메서드
    func displayBalance(){
        print("Number \(accountNumber)")
        print("Current balance is \(accountBalance)")
    }
}

// 인스턴스 생성
var account1 = BankAccount(number : 12312312, balance : 400.54)

 

 

 

  • 스위프트 런타임 시스템에 의해 클래스 인스턴스가 없어지기 전에 해야 할 정리 작업은 클래스 안에 소멸자(deinitializer)를 구현
class BankAccount {
    var accountBalance : Float = 0  // 계좌에 남은 잔고
    var accountNumber : Int = 0     // 계좌 번호
    
    // 초기화
    init(number : Int, balance : Float){
        accountNumber = number
        accountBalance = balance
    }
    
    // 소멸자
    deinit{
        // 필요한 작업 수행
    }
    
    // 인스턴스 메서드
    func displayBalance(){
        print("Number \\(accountNumber)")
        print("Current balance is \\(accountBalance)")
   
 }
}
// 인스턴스 생성
var account1 = BankAccount(number : 12312312, balance : 400.54)

 

 

메서드 호출 및 프로퍼티 접근

  • 점 표기법 (dot notation) 이용
  • 클래스인스턴스.프로퍼티명
  • 클래스인스턴스.인스턴스메서드()
// 인스턴스 변수 값 접근 
var balance1 = account1.accountBalance

// 프로퍼티 값 설정
account1.accountBalance = 6789.98

// 메서드 호출 
account1.displayBalance()

// 타입 메서드 호출 시 클래스 인스턴스가 아니라 클래스를 호출해야 함
var maxAllowed = BankAccount.getMaxBalance()

 

 

 

저장 프로퍼티 vs 연산 프로퍼티

  • 저장 프로퍼티 : 상수나 변수에 담기는 값 (계좌이름, 번호 프로퍼티)
  • 연산 프로퍼티 : 프로퍼티에 값을 설정하거나 가져오는 시점에서 어떤 계산이나 로직에 따라 처리된 값
    • 게터(getter)를 생성하고 선택적으로 세터(setter) 메서드를 생성하며, 연산을 수행할 코드 포함
    • ex) 은행 수수료를 뺀 현재 잔액을 담는 프로퍼티 추가 (getter)
    • 부동 소수점 값을 매개변수로 받아서 수수료를 뺀 결과를 프로퍼티에 할당
class BankAccount {
    var accountBalance : Float = 0  // 계좌에 남은 잔고
    var accountNumber : Int = 0     // 계좌 번호
    var fees : Float : 25.00        // 은행 수수료
    
    var balanceLessFees : Float{
        get{
            return accountBalance - fees
        }
	set(newBalance){
            accountBalance = newBalance - fees
        }
    }
	...
}

// 현재의 잔액에서 수수료를 뺀 값을 얻는 코드와 새로운 값을 설정하는 코드
var balance1 = account1.balaceLessFees
account1.balaceLessFees = 12123.12

 

 

 

지연 저장 프로퍼티

  • 프로퍼티 초기화 방법
    1. 직접 할당
    2. 초기화 작업에서 할당
    3. 클로저 사용
// 1. 직접 할당
var myProperty = 10

// 2. 초기화 작업에서 할당
class myClass {
	let title : String
	init(title : String){
		self.title = title
	}
}

// 3. 클로저 사용
class myClass {
	var myProperty : String = {
		var result = resourceIntensiveTask()
		result = processData (data : result)
		return result
	}()
..
}	
  • 클로저의 경우 초기화 작업이 리소스와 시간이 많이 사용됨
    • 해당 프로퍼티가 코드 내에서 실제로 사용되는지와는 상관없이 클래스 인스턴스가 생성될 때마다 초기화 작업이 수행되기 때문

→ 효율적인 방법 : 프로퍼티로 최초 접근할 때만 초기화 작업 (lazy 사용)

class myClass {
	lazy var myProperty : String = {
		var result = resourceIntensiveTask()
		result = processData (data : result)
		return result
	}()
..
}

 

 

 

self 사용하기

  • 현재 클래스 인스턴스에 속한 메서드나 프로퍼티를 가리킬 때 프로퍼티와 메서드 앞에 self를 사용
class MyClass {
	var myNumber = 1

	func addTen(){
		self.myNumber += 10
		// myNumber += 10
	}
}

→ self는 디폴트이기 때문에 안 써도 됨

 

단, 프로퍼티나 메서드를 클로저 표현식 내에서 참조할 경우 반드시 사용해야 함

document?.openWithCompletionHandler({(success:Bool) -> Void in 
	if success {
		self.ubiquityURL = resultURL
	}
})

 

 

  • 함수의 매개변수가 클래스 프로퍼티와 동일한 이름일 때도 self 사용
class MyClass{
	var myNumber = 10
	
	func addTen(myNumber : Int){
		print(myNumber)      // 함수의 매개변수 값을 출력
		print(self.myNumber) // 클래스 프로퍼티 값을 출력 
	}
}

 

 

 

프로토콜

  • 클래스가 충족해야 하는 최소한의 요구사항을 정의하는 규칙들의 집합
  • protocol 키워드 사용
  • 클래스가 반드시 포함해야 하는 메서드나 프로퍼티를 정의
  • 어떤 클래스가 프로토콜을 채택했으나, 요구사항을 충족하지 않는다면 에러 발생
  • 아래 프로토콜을 채택한 클래스는 name 프로퍼티와 buildMessage() 메서드 반드시 포함해야 함
protocol MessageBuilder {
	var name : String {get}
	func buildMessage() -> String
}

class MyCalss : MessageBuilder {

}

// -> 에러 발생
class MyClass : MessageBuilder{
	var name : String
	
	init(name : String){
		self.name = name
	}

	func buildMessage() -> String {
		"Hello " + name
	}
}

 

 

 

불투명 반환 타입

  • 특정 반환 타입(구체화된 타입)을 지정하지 않고, 불투명 반환 유형을 사용하면 지정된 프로토콜을 따르는 모든 타입이 반환될 수 있음
  • 프로토콜 앞에 some 키워드를 붙여 선언
  • doubleFunc1() 함수가 Equatable 프로토콜을 따르는 모든 타입의 결과가 반환된다고 선언
  • Int, String 모두 Equatable 프로토콜을 따른다면 아래와 같이 선언 가능
func doubleFunc1 (value : Int) -> some Equatable {
	value * 2
}

func doubleFunc2 (value : String) -> some Equatable {
	value + value
}

'Swift' 카테고리의 다른 글

Swift - 7. 구조체  (0) 2023.12.28
Swift - 6. 서브 클래싱과 익스텐션 개요  (0) 2023.12.28
Swift - 4. 함수, 메서드, 클로저 개요  (1) 2023.12.26
Swift - 3. 제어 흐름  (0) 2023.12.26
Swift - 2. 연산자와 표현식  (0) 2023.12.24