[250320] 접근제어자, 프로토콜

ON&OFF·2025년 3월 19일

iOS TIL

목록 보기
7/18

접근제어자

open

  • 모든 외부 모듈에서 접근할 수 있는 접근제어자
  • 가장 개방적인 접근 수준
  • 유일하게 class 에서만 사용 가능
    • 상속이 가능하고 재정의 가능하기 때문에!

public

  • 모든 외부 모듈에서 접근할 수 있는 접근제어자
  • 가장 개방적인 접근 수준

internal

  • 기본값 접근제어자로 설정하지 않았다면 internal
  • 동일한 모듈에서 접근 가능

fileprivate

  • 동일한 파일 내부에서만 접근할 수 있는 접근 제어자

private

  • 가장 제한적인 접근 제어자
  • 해당 요소를 선언한 스코프(예를 들어 class, struct, enum의 코드블록)에서만 사용 가능
  • struct 에서 private 프로퍼티가 있다면 멤버와이즈 init을 사용할 수 없어서 직접 init을 작성해야 합니다.

모듈이란?

  • 모듈은 코드 배포의 단일 단위입니다.
  • Swift에서는 import를 사용하여 다른 모듈에서 가져올 수 있습니다.

프로토콜

  • 프로토콜 자체는 기능을 구현하지 않으며, 오직 설계만 제공합니다.
  • class, struct, enum 에서 프로토콜을 채택할 수 있으며, 프로토콜에서 정의한 프로퍼티와 메소드를 모두 구현해야 합니다.
    • 프로토콜을 채택하는 방법은 타입의 이름 뒤에 : 콜론을 넣은 후 프로토콜 이름을 작성하면 됩니다.
    • 프로토콜은 여러 개를 채택 할 수 있으며, 프로토콜 이름을 , 로 구분합니다.
  • 프로토콜에서 정의된 프로퍼티는 항상 var 로 선언되어야 합니다.
  • 프로토콜에서 정의하는 프로퍼티는 읽기 전용 { get } 또는 읽기-쓰기 가능 { get set } 으로 설정할 수 있습니다.
    • { get } 으로만 설정해도 프로퍼티의 값을 변경할 수 있지만, 명시적으로 작성하면 코드의 의도를
      쉽게 파악할 수 있습니다.
  • 프로토콜에서 정의하는 메소드는 이름,파라미터, 리턴타입만 선언하며, 구현부 { } 는 작성하지 않습니다.
  • Swift에서 프로토콜은 다른 언어에서 말하는 인터페이스 개념과 유사합니다.
  • protocol 프로토콜이름 {
    	// 프로퍼티 정의
    	// 메소드 정의
    }
    protocol FullyNamed {
    	var fullName: String { get } 	
    	func sayMyFullName() -> String // 구현부는 작성하지 않습니다.
    }
// 1개의 프로토콜 채택
protocol FullyNamed {
	var fullName: String { get } 	
	func sayMyFullName() -> String // 구현부는 작성하지 않습니다.
}
class Person: FullyNamed { // FullyName 프로토콜을 채택합니다.
    var fullName: String  // FullyName 프로토콜에 있는 fullName 프로퍼티를 구현해야 합니다.   
    func sayMyFullName() -> String { // 프로토콜에 있는 메소드를 구현해야 합니다.
        return fullName
    }   
    init(fullName: String) {
        self.fullName = fullName
    }
}
var person = Person(fullName: "Brody")
print(person.fullName) // "Brody" 출력
print(person.sayMyFullName()) // "Brody" 출력
// 여러개의 프로토콜 채택
protocol FullyNamed {
    var fullName: String { get }    
    func sayMyFullName() -> String
}
protocol ShortNamed {
    var shortName: String { get }
}
class Person: FullyNamed, ShortNamed { // 프로토콜 여러개를 채택하는 클래스입니다.
    var fullName: String    
    func sayMyFullName() -> String {
        return fullName
    }    
    var shortName: String {
        return "ShortName"
    }    
    init(fullName: String) {
        self.fullName = fullName
    }
}
var person = Person(fullName: "Brody")
print(person.fullName) // "Brody" 출력
print(person.sayMyFullName()) // "Brody" 출력
print(person.shortName) // "ShortName" 출력
  • 클래스 전용 프로토콜 만들기

    • class 전용 프로토콜은 struct, enum에서 사용될 수 없습니다.
    • 프로토콜 정의 시, AnyObject를 채택하면 클래스 전용 프로토콜로 만들 수 있습니다.
      protocol OnlyClassProtocol: AnyObject {
      }

확장

  • 기존의 class, struct, enum, protocol 타입에 새로운 기능을 추가할 수 있는 키워드입니다.
  • 타입의 원본 코드를 수정하지 않고도 수평적인 기능을 확장 할 수 있어 코드의 유지 보수와 가독성이 향상됩니다.
  • extension 키워드를 사용하여 기존 타입을 확장할 수 있습니다.
  • 하나 이상의 프로토콜을 extension으로 추가해 적용할 수 있습니다.
    이를 통해 기존 타입을 수정하지 않고 프로토콜 요구사항을 구현할 수 있어 코드 유지보수가 편리해집니다.
  • 하나의 타입에 extension 여러 번 가능합니다.
  • 확장할 수 있는 것들은 아래와 같습니다.
    • 연산 프로퍼티
      • 확장된 곳에서 저장 프로퍼티는 사용할 수 없습니다.
    • 메소드
    • 새로운 초기화 init
    • 중첩된 타입(Nested Type)
// 확장할 수 있는 것들

struct Person {
    let lastName: String
    let firstName: String
    let age: Int
}

protocol FullyNamed {
    var fullName: String { get }
    
    func sayMyFullName() -> String
}

// extension에서 연산 프로퍼티를 구현할 수 있습니다.
extension Person {
    var nameAge: String {
        return "\(firstName)(\(age)세)"
    }
}

// extension에서 메소드를 구현할 수 있습니다.
extension Person {
    func sayHello() {
        print("\(firstName)님 안녕하세요?")
    }
}

// extension에서 protocol을 채택하여 구현할 수 있습니다.
extension Person: FullyNamed {
    var fullName: String {
        return "\(lastName)\(firstName)"
    }
    
    func sayMyFullName() -> String {
        return "제 이름은 \(fullName)입니다."
    }
}


let person = Person(lastName: "홍", firstName: "길동", age: 20)

print(person.nameAge) // extension에서 구현한 연산프로퍼티를 사용할 수 있습니다.
person.sayHello()     // extension에서 구현한 메소드를 호출할 수 있습니다.
print(person.fullName) // extension에서 구현한 프로토콜을 사용할 수 있습니다.
print(person.sayMyFullName()) // extension에서 구현한 프로토콜을 사용할 수 있습니다.

/* 출력 값
길동(20세)
길동님 안녕하세요?
홍길동
제 이름은 홍길동입니다.
*/
profile
안 되면 될 때까지

0개의 댓글