iOS Class 4
1. 함수(Function) 정의와 호출
1-1. 매개변수 레이블과 시그니처
Swift에서 함수는 함수명 + 매개변수 레이블을 합친 것이 실제 구분되는 이름입니다.
// 1. 기본 형태
func add(x: Int, y: Int) { ... }
add(x: 10, y: 20) // 외부 매개변수명 x, y
// 2. 외부 이름 지정
func add(first x: Int, second y: Int) { ... }
add(first: 10, second: 20) // 외부 매개변수명 first, second
// 3. 외부 이름 생략
func add(_ x: Int, _ y: Int) { ... }
add(10, 20) // 외부 매개변수명 없음 (_ 사용)
// 4. 혼합
func add(_ x: Int, with y: Int) { ... }
add(10, with: 20) // 첫 번째는 없음, 두 번째는 with
UIKit 예시
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
- 함수명:
tableView - 전체 시그니처:
tableView(_:numberOfRowsInSection:) - 자료형:
(UITableView, Int) -> Int - 포인트: Swift에서는 함수 이름 자체는 tableView지만, 매개변수 라벨까지 포함해 구분합니다.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
// 시그니처: tableView(_:cellForRowAt:)
1-2. 디폴트 아규먼트(Default Argument)
func greet(name: String = "Guest") {
print("Hello, \(name)")
}
greet() // Hello, Guest
greet(name: "Tom") // Hello, Tom
- 개념: 매개변수에 미리 값을 지정 → 호출 시 값이 없으면 기본값 사용
- 장점: 함수 호출 간소화, 오버로딩 감소
1-3. 가변 인자(Variadic Parameter)
func print(_ items: Any..., separator: String = " ", terminator: String = "\n")
_ items: Any...→ 외부 이름 없음, 여러 값 가능separator→ 값 사이 구분자terminator→ 출력 마지막 붙는 문자
예시
print("A", "B", "C") // A B C
print("A", "B", "C", separator: "-") // A-B-C
print("Hello", terminator: "!") // Hello!
- 실제 시그니처:
print(_:separator:terminator:)
2. 함수와 클로저
Swift에서 함수는 **1급 객체(First-class Citizen)**입니다.
- 변수에 저장 가능
- 매개변수로 전달 가능
- 반환값으로 사용 가능
func add(x: Int, y: Int) -> Int { return x + y }
print(add(x:10, y:20)) // 30
let add1 = { (x: Int, y: Int) -> Int in return x + y }
print(add1(10, 20)) // 30
print(type(of:add1)) // (Int, Int) -> Int
2-1. 고차 함수(Higher-order function)
func math(x: Int, y: Int, cal: (Int, Int) -> Int) -> Int {
return cal(x, y)
}
// 일반 함수 전달
math(x: 10, y: 20, cal: add) // 30
// 클로저 직접 전달
math(x: 10, y: 20, cal: { (a: Int, b: Int) -> Int in return a + b })
// Trailing closure, 타입 생략, shorthand
math(x: 10, y: 20) { $0 + $1 }
- 포인트: 함수를 값처럼 전달하여 동작 변경 가능
- 문법 축약 과정
- 완전형
{ (Int, Int) -> Int in return a + b } - Trailing closure
{ a, b in a + b } - Shorthand
{ $0 + $1 }
- 완전형
3. 클래스와 속성(Properties)
3-1. 저장 속성 vs 계산 속성
class Man {
var age: Int = 1 // 저장 속성
var weight: Double = 3.5 // 저장 속성
var squaredWeight: Double { // 계산 속성
return weight * weight
}
}
- 저장 속성: 값을 직접 저장
- 계산 속성: 값을 계산 후 반환
3-2. 옵셔널(Optional)
var age: Int? // nil로 초기화 가능
var weight: Double! // 암시적 옵셔널
3-3. 이니셜라이저(Initializer)
class Man {
var age: Int
var weight: Double
init(age: Int, weight: Double) { // Designated initializer
self.age = age
self.weight = weight
}
}
- Designated Initializer: 모든 속성을 초기화하는 주 생성자
- 영어 발음: /ˈdezɪɡˌneɪtɪd ɪˈnɪʃəˌlaɪzər/
- 초기화 완료 전에는 메서드 호출 불가 (
self미완성)
3-4. 클래스 상속과 Override
class Animal {
func sound() { print("동물이 소리를 냅니다") }
}
class Dog: Animal {
override func sound() { print("멍멍!") }
}
override키워드 필수- 부모 메서드 동작 확장 가능:
super.sound()
4. Extension과 계산 속성
extension Double {
var squared: Double { return self * self }
}
let myValue: Double = 3.5
print(myValue.squared) // 12.25
print(3.5.squared) // 12.25
print(myValue.isZero) // false
- extension: 기존 타입에 기능 추가
- computed property: 저장 없이 계산해서 반환
5. Access Modifier (액세스 제어자)
5-1. Swift
| 접근 수준 | 키워드 | 범위 | 패키지(Module) 관점 | 설명 |
|---|---|---|---|---|
| 공개 | public | 어디서든 접근 가능 | 다른 패키지에서도 접근 가능 | 외부 API/타입 공개 |
| 모듈 내부 | internal | 같은 모듈 내 | 패키지 내부만 접근 가능 | 기본값 |
| 파일 내부 | fileprivate | 같은 파일 내 | 패키지와 관계 없음 | 파일 안에서만 접근 가능 |
| 선언 범위 | private | 클래스/구조체 등 내부 | 패키지와 관계 없음 | 선언 범위 내부에서만 접근 가능 |
예시
class Person {
private var name: String = "Unknown"
var age: Int = 0 // internal 기본
public func display() { print("\(name), \(age)") }
}
5-2. 다른 언어 비교
| 언어 | 접근 제어 키워드 | 특징 |
|---|---|---|
| C++ | private, protected, public | OOP 중심, 상속 고려 |
| C# | private, protected, internal, protected internal, public | OOP 중심, 어셈블리 단위 접근 가능 |
| Rust | 기본 private, pub, pub(crate) | 모듈 단위 중심, protected 없음 |
6. 요약
- 함수: 이름 + 매개변수 라벨이 구분 단위, 디폴트값/가변 인자/클로저 가능
- 클로저: 이름 없는 함수, trailing closure, shorthand 사용 가능
- 클래스: 저장 속성, 계산 속성, 옵셔널, init, designated initializer
- 상속/Override: 부모 메서드 재정의 가능, super 사용 가능
- Extension: 기존 타입 확장, 계산 속성 추가
- Access Modifier: 캡슐화와 안전성, Swift/타 언어 비교
- 패키지 관점: internal/public 기준으로 모듈 간 접근 제어


func add(x: Int, y: Int) -> Int { return x+y
}
print(add(x:10, y:20))
{(매개변수 이름: 매개변수 타입, ... ) -> 반환 타입 in // 클로저 표현식 코드
}
let add1 = { (x: Int, y: Int) -> Int in return x+y
}
print(add1(x:10, y:20))
//주의 error: extraneous(관련 없는) argument labels 'x:y:' in call print(add1(10, 20)) //OK
print(type(of:add1)) //?class Man{
var age : Int = 1 //직접 지정
var weight : Double = 3.5
}
class Man{
var age : Int? //옵셔널 변수는 nil로 자동 초기화
var weight : Double! //옵셔널 변수는 nil로 자동 초기화
}
class Man{
var age : Int
var weight : Double
init(){ //initializer로 초기화
age = 1
weight = 3.5
}
}

좋아요! 스위프트(Swift)에서 **접근자(access modifier)**를 실무에서 쓰는 방법을, 실제 개발 상황 중심으로 정리해 드릴게요. 단순 문법보다 **“왜 이렇게 쓰는지, 어디서 쓰는지”**를 이해하는 게 핵심이에요.
1️⃣ 기본 원칙
스위프트 접근자는 코드 캡슐화와 안정성을 위해 쓰입니다.
즉, 외부에서 함부로 속성이나 메서드에 접근하지 못하게 하고, 내부 구현을 숨기는 목적이 있어요.
- 기본값:
internal→ 같은 모듈(앱 또는 프레임워크) 안에서 접근 가능 - 외부 프레임워크 공개:
public - 파일 단위 제한:
fileprivate→ 같은 파일 안에서만 사용 - 클래스/구조체 범위 제한:
private→ 선언 범위 내부에서만 사용
2️⃣ 실무에서 자주 쓰는 패턴
🔹 1. private : 클래스 내부 구현 숨기기
class BankAccount {
private var balance: Double = 0.0
func deposit(amount: Double) {
balance += amount
}
func withdraw(amount: Double) -> Bool {
if amount <= balance {
balance -= amount
return true
}
return false
}
func getBalance() -> Double {
return balance
}
}
balance를 private으로 숨겨서 직접 변경하지 못하게 함- 항상
deposit()/withdraw()같은 메서드를 통해 안전하게 접근 - 실무에서는 데이터 무결성 보장 목적
🔹 2. fileprivate : 같은 파일 내에서만 접근
fileprivate func helperFunction() {
print("같은 파일에서만 사용")
}
- 보통 테스트용 함수나 파일 내부만 쓰는 유틸 함수에 사용
- 다른 파일에서 접근하면 컴파일 오류 발생
🔹 3. internal : 기본값
var name: String = "Guest" // internal
- 같은 모듈 안에서는 자유롭게 접근 가능
- 앱 개발에서는 보통 별도 지정 없이 internal이 기본
- 프레임워크 만들 때, 외부 공개 여부에 따라
public/internal결정
🔹 4. public / open : 프레임워크용
public class APIClient {
public init() {}
public func fetchData() {
// 외부 모듈에서도 사용 가능
}
}
- 프레임워크를 배포할 때 외부에서 접근할 API에 붙임
open은 상속까지 허용- 예:
UIKit에서UIViewController클래스는 open이라 상속 가능
🔹 5. 계산 속성(computed property) + 접근자 조합
class Circle {
private var radius: Double = 1.0
public var diameter: Double {
get {
return radius * 2
}
set {
radius = newValue / 2
}
}
}
- 내부 저장소
radius는 private - 외부에서는
diameter를 통해 간접 접근 가능 - 실무에서 API 형태와 내부 구현을 분리할 때 자주 사용
🔹 6. 테스트 환경에서 internal + @testable
@testable import MyApp
- 테스트용 코드에서 internal 접근 허용
- 실제 앱 코드에서는 외부에서 안 보이지만, 테스트에서 접근 가능
- 실무에서 단위 테스트 작성 시 거의 필수 패턴
3️⃣ 실무에서 기억할 포인트
- 속성은 가능한 private으로 숨기고, 필요하면 메서드/계산 속성을 통해 공개
- 파일 범위 helper는 fileprivate로 제한
- 프레임워크 외부 공개 API는 public/open
- internal은 기본값 → 특별히 외부 공개 필요 없으면 지정 안 해도 됨
- 테스트에서 internal 접근 필요하면
@testable import활용
💡 실무 요약 한 줄
“내부 구현은 최대한 숨기고(private/fileprivate), 외부에서 필요한 기능만 public/open으로 노출 → 안정성 + 유지보수 + 테스트 용이성 확보”