[내일배움캠프] 251223 TIL

Bambu·2025년 12월 23일

내배캠 TIL

목록 보기
5/52

1. STEP 4(마스터). 클로저 / 객체지향 프로그래밍

1) 클로저

  • 캡처(Capture) : 클로저는 외부 변수나 상수의 값을 캡처하여 클로저 내부에서 사용한다.
var number = 10
let closure = { number += 5 }

closure()
print(number) // 15

→ 외부 변수 number를 캡처하여 클로저 내부에서 사용 - number 값이 변화
⇒ 이는 참조 카운트를 증가 시키므로 강한 순환 참조가 일어날 가능성이 있음!
➡︎ 순환 참조 발생 시 캡처리스트 사용

class Counter {
	var number = 10
    
    lazy var closure = { [weak self] in
    	guard let self else { return 0 }
    	self.number += 5
        return self.number
    }
}

weak 혹은 unowned는 참조 타입에만 사용 가능하므로 클래스 생성
[weak self]로 클래스를 약한 참조하여 강한 순환 참조를 방지
[weak self] 사용 시, 클로저 내부에서 self는 옵셔널 타입이므로 guard문 사용
[weak self]guard let self = self else { return 0 }은 너무 많이 사용하는 문법이라 위처럼 축약하여 사용
→ 클로저 생성 시점에 self는 아직 존재하지 않으므로 lazy var로 선언

2) 객체지향 프로그래밍

  • 객체(Object)를 기반으로 프로그램을 설계하는 방식

주요 원칙

  • 캡슐화(Encapsulation) : 데이터를 숨기고 외부에는 필요한 인터페이스만 제공
  • 상속(Inheritance): 기존 클래스를 확장하여 새로운 클래스 생성
  • 다형성(Polymorphism) : 같은 메서드를 다양한 방식으로 동작하게 함
  • 추상화(Abstraction) : 불필요한 세부사항을 숨기고 중요한 부분만 표현
class Animal { // 하나의 클래스로 캡슐화
	var name: String
    
    init(name: String) {
    	self.name = name
    }
    
    func makeSound() {
    	print("Some generic sound")
    }
}

class Dog: Animal { // Animal 클래스를 상속
	override func makeSound() { // makeSound() 메소드를 override하여 다른 방식으로 동작하게 함(다형성)
        print("Bark!")
    }
}

// 위에 구현했던 내용들이 실제 호출 시에는 일일이 보이지 않음(추상화)
let dog = Dog(name: "Buddy")
dog.makeSound() // "Bark!"

직접 구현해보기

STEP 1: 클로저 구현하기

가. 간단한 클로저 구현

var arr = [1, 2, 3, 4, 5]
let someClosure = { arr = arr.map { $0 * 2 } }

someClosure()
print(arr) // [2, 4, 6, 8, 10]

나. 클로저 캡처 이해

var counter = 0
let incrementCounter = { counter += 1 }

incrementCounter() // counter == 1
incrementCounter() // counter == 2
print(counter) // 출력 2

STEP 2: 객체지향 프로그래밍 구현하기

가. 동물 클래스 설계

  • Animal 클래스 생성
class Animal {
	var name: String
    
    init(name: String) {
    	self.name = name
    }
    
    func makeSound() {
    	print("some Sound")
    }
}
  • Animal 클래스를 상속하는 Dog, Cat 클래스 생성
class Dog: Animal {
	override func makeSound() {
    	print("Bark!")
    }
}

class Cat: Animal {
	override func makeSound() {
    	print("Meow!")
    }
}

나. 다형성 확인

let dog = Dog(name: "Doggy")
let cat = Cat(name: "Kitty")

dog.makeSound() // "Bark!"
cat.makeSound() // "Meow!"

→ override하여 덮어쓴 대로 makeSound() 메소드가 동작함

2. iOS 퀴즈 - 접근 제어

접근 제어(Access control) : 소스 파일과 모듈의 코드 접근을 제한하는 것
→ 은닉화를 위해 사용 - 외부에 코드 세부 사항을 노출하지 않기 위해
→ 공익 목적으로 코드를 공유하기 위해 사용하기도 할 것 같음

💡 모듈(module) : 코드 배포의 단일 단위
→ 프레임워크(Framework), 애플리케이션(Application)과 같이 import 키워드로 다른 모듈에서 가져올 수 있는 것

접근 수준

  • open 접근 / public 접근
    : 정의된 모듈의 모든 소스 파일에서 해당 엔티티(entity) 사용 가능
    : open 접근은 클래스에만 사용 가능!
    : 클래스 외의 타입은 Public 접근이 기본
    : 정의한 모듈 import 시, 다른 모듈의 소스 파일에서도 엔티티 사용 가능
  • internal 접근
    : 정의된 모듈의 모든 소스 파일에서 해당 엔티티 사용 가능
    : 일반적으로 앱이나 프레임워크의 내부 구조체 정의 시 사용
  • file-private 접근
    : 정의된 소스 파일 내에서만 해당 엔티티 사용 가능
    : 특정 기능이 파일 전체에서 사용되지만 세부 구현이 외부에 노출되지 않도록 하려는 경우 사용
  • private 접근
    : 해당 엔티티가 선언된 내부, 그리고 같은 파일에 있는 해당 선언의 확장에서만 사용을 허용
    : 특정 기능이 단일 선언 내에서만 사용되고 세부 구현이 외부에 노출되지 않도록 하려는 경우 사용

open 접근과 public 접근의 차이

  • open 접근은 외부 모듈에서 하위 클래스와 재정의를 허용
  • public은 불가 - public 클래스는 외부 모듈에서 해당 클래스를 상속하여 하위 클래스를 생성할 수 없음! 재정의도 불가

➡︎ open > public > internal > file-private > private 순서로 제한적임 (private이 가장 제한적)

profile
안녕하세요, iOS 개발을 공부하고 있는 Bambu입니다. (프로필: Swifticons)

0개의 댓글