nil
오류로부터 안전하게 코드를 작성할 수 있도록 돕는 핵심적인 도구입니다.null
또는 nil
값 때문에 런타임 오류(앱 크래시)가 발생하는 경우가 많지만, Swift는 옵셔널을 통해 이러한 위험을 사전에 방지할 수 있도록 설계되었습니다.nil
오류로부터 안전하게 코드를 작성할 수 있도록 돕는 핵심적인 도구입니다.null
또는 nil
값 때문에 런타임 오류(앱 크래시)가 발생하는 경우가 많지만, Swift는 옵셔널을 통해 이러한 위험을 사전에 방지할 수 있도록 설계되었습니다.func 함수이름(매개변수1: 타입, 매개변수2: 타입) -> 반환타입 {
// 함수가 수행할 작업 코드
return 반환값 // 반환타입이 있을 경우
}
// 1. 매개변수 없고, 반환값 없는 함수
func sayHello() {
print("안녕하세요, Swift 함수!")
}
sayHello() // 함수 호출: 안녕하세요, Swift 함수!
// 2. 매개변수 있고, 반환값 없는 함수
func greet(name: String) {
print("안녕, \(name)! 만나서 반가워.")
}
greet(name: "배팀장") // 함수 호출: 안녕, 배팀장! 만나서 반가워.
// 3. 매개변수 있고, 반환값 있는 함수
func addNumbers(num1: Int, num2: Int) -> Int {
let sum = num1 + num2
return sum
}
let result = addNumbers(num1: 10, num2: 20)
print("두 숫자의 합: \(result)") // 출력: 두 숫자의 합: 30
func sendMessage(to recipient: String, message: String) {
print("To \(recipient): \(message)")
}
// 호출 시 매개변수 레이블 사용: to, message
sendMessage(to: "김철수", message: "오늘 저녁에 볼까?")
// 출력: To 김철수: 오늘 저녁에 볼까?
// 매개변수 레이블을 생략하고 싶다면 '_' 사용
func printMessage(_ msg: String) { // _로 레이블 생략
print(msg)
}
printMessage("레이블 없이 호출!") // 출력: 레이블 없이 호출!
{ (매개변수들) -> 반환타입 in
// 클로저가 수행할 작업 코드
return 반환값 // 반환타입이 있을 경우
}
// 1. 가장 기본적인 클로저 예시
let simpleClosure = {
print("이것은 간단한 클로저입니다.")
}
simpleClosure() // 클로저 호출: 이것은 간단한 클로저입니다.
// 2. 매개변수와 반환값이 있는 클로저
let sumClosure: (Int, Int) -> Int = { (a: Int, b: Int) -> Int in
return a + b
}
let total = sumClosure(5, 7)
print("클로저로 계산한 합: \(total)") // 출력: 클로저로 계산한 합: 12
// 3. 클로저 표현식의 간략화 (Swift의 강력한 기능!)
// 3.1. 타입 추론
let multiplyClosure: (Int, Int) -> Int = { (a, b) in
return a * b
}
print("클로저로 계산한 곱: \(multiplyClosure(3, 4))") // 출력: 클로저로 계산한 곱: 12
// 3.2. 단일 표현식 암시적 반환 (return 생략)
let subtractClosure: (Int, Int) -> Int = { (a, b) in
a - b
}
print("클로저로 계산한 차: \(subtractClosure(10, 3))") // 출력: 클로저로 계산한 차: 7
// 3.3. 인자 이름 축약 ($0, $1 등)
let divideClosure: (Int, Int) -> Int = { $0 / $1 } // $0은 첫 번째 인자, $1은 두 번째 인자
print("클로저로 계산한 나눗셈: \(divideClosure(20, 4))") // 출력: 클로저로 계산한 나눗셈: 5
// 일반적인 클로저 전달 방식
func doSomething(completion: () -> Void) {
print("작업 시작...")
completion() // 작업 완료 후 클로저 실행
}
doSomething(completion: {
print("작업 완료!")
})
// 후행 클로저 사용 방식 (더 간결!)
func doAnotherSomething(completion: () -> Void) {
print("다른 작업 시작...")
completion()
}
doAnotherSomething { // 소괄호 밖으로 클로저 이동
print("다른 작업 완료!")
}
프로그래밍에서 변수는 값을 저장하는 공간이라고 생각하면 쉽습니다. 이 공간에 저장된 값은 프로그램이 실행되는 동안 언제든지 변경될 수 있습니다. Swift에서 변수를 선언할 때는 var
키워드를 사용합니다.
💡 왜 사용할까요? 사용자의 입력값, 계산 결과, 실시간으로 변하는 상태(예: 게임 점수, 현재 시간) 등을 저장할 때 유용합니다.
Swift 예시
var welcomeMessage = "안녕하세요, Swift 세계에 오신 것을 환영합니다!"
print(welcomeMessage) // 출력: 안녕하세요, Swift 세계에 오신 것을 환영합니다!
welcomeMessage = "다시 만나서 반갑습니다!" // 값 변경
print(welcomeMessage) // 출력: 다시 만나서 반갑습니다!
var userScore = 0 // 게임 점수
print("현재 점수: \(userScore)")
userScore = 100 // 점수 증가
print("새로운 점수: \(userScore)")
위 예시에서 welcomeMessage
와 userScore
는 var
로 선언되었기 때문에 나중에 다른 값으로 변경할 수 있습니다.
변수와 달리 상수는 한 번 값이 할당되면 프로그램이 끝날 때까지 그 값을 절대 변경할 수 없습니다. Swift에서 상수를 선언할 때는 let
키워드를 사용합니다.
💡 왜 사용할까요? 변하지 않는 고정된 값(예: 수학에서의 파이(π) 값, 앱 버전 번호, 고정된 메시지)을 저장하여 코드의 안정성을 높이고, 실수를 줄이는 데 도움이 됩니다. Swift는 기본적으로 상수를 사용하는 것을 권장합니다.
📝 Swift 코드 예시:
let maximumNumberOfLoginAttempts = 3 // 최대 로그인 시도 횟수
print("최대 로그인 시도 횟수: \(maximumNumberOfLoginAttempts)")
let companyName = "Apple Inc." // 회사 이름
print("회사 이름: \(companyName)")
// maximumNumberOfLoginAttempts = 5 // 에러 발생! 상수는 값을 변경할 수 없습니다.
maximumNumberOfLoginAttempts
와 companyName
은 let
으로 선언되었으므로 값을 변경하려고 하면 컴파일 에러가 발생합니다. 이는 개발자의 의도치 않은 값 변경을 방지하여 코드의 견고함을 높여줍니다.
Swift는 타입에 안전한(Type-safe) 언어입니다. 이는 Swift가 모든 변수와 상수에 저장되는 값의 데이터 타입을 명확하게 알고 있다는 의미입니다. 데이터 타입은 그 값이 숫자(정수, 소수), 문자, 참/거짓 등 어떤 종류의 값인지를 Swift에게 알려줍니다.
Swift는 대부분의 경우 개발자가 타입을 명시하지 않아도 초기값을 보고 스스로 타입을 추론(Type Inference)합니다. 하지만 필요하다면 직접 타입을 명시할 수도 있습니다.
💡 주요 데이터 타입:
10
, -5
, 0
)3.14
, -0.5
, 100.0
)Double
보다 적은 메모리를 사용하지만 정밀도가 낮습니다. (잘 사용되지 않음)true
) 또는 거짓(false
) 두 가지 값만 가집니다. 조건문에서 많이 사용됩니다."Hello"
, "Swift Programming"
)'A'
, '😀'
)📝 Swift 코드 예시 (타입 추론 및 명시):
// 타입 추론 (Swift가 알아서 타입을 결정)
var age = 30 // Int로 추론
let pi = 3.14159 // Double로 추론
var isLoggedIn = true // Bool로 추론
let appName = "MyAwesomeApp" // String으로 추론
// 타입 명시 (개발자가 직접 타입을 지정)
var temperature: Double = 25.5
let statusCode: Int = 200
var isEnabled: Bool = false
let greeting: String = "안녕하세요"
// 주의: 다른 타입의 값을 할당할 수 없습니다.
// temperature = "스물다섯점오" // 에러 발생! String을 Double 변수에 할당할 수 없습니다.
오늘은 Swift 프로그래밍의 가장 기본적인 세 가지 요소, 즉 값을 저장하는 공간인 변수(var
) 와 상수(let
), 그리고 값의 종류를 나타내는 데이터 타입에 대해 알아보았습니다.
var
: 값이 변할 수 있는 데이터를 저장할 때 사용합니다.let
: 한 번 할당되면 변하지 않는 데이터를 저장할 때 사용합니다. (Swift는 let
사용을 권장합니다!)이 개념들을 잘 이해하고 나면, 다음 단계로 나아갈 준비가 된 것입니다. 다음 블로그에서는 Swift의 흐름 제어(조건문과 반복문)에 대해 자세히 알아보도록 하겠습니다.
내용 중에 틀린 부분이 있으면 댓글로 알려주세요.
iOS 개발자가 되기 위한 여정을 응원합니다! Swift, SwiftUI, 그리고 외부 기기 연동 기술을 빠르고 정확하게 습득하기 위한 체계적인 학습 로드맵을 안내해 드립니다.
가장 먼저 iOS 앱 개발의 핵심 언어인 Swift에 대한 탄탄한 이해가 필요합니다.
현대적이고 선언적인 UI 프레임워크인 SwiftUI를 통해 사용자 인터페이스(UI) 개발을 시작합니다.
SwiftUI와 함께 iOS 앱 개발에 필요한 다양한 프레임워크를 학습하고, 외부 기기 연동 방법을 익힙니다.
이 로드맵은 일반적인 가이드이며, 개인의 학습 속도와 배경지식에 따라 조절될 수 있습니다. 무엇보다 중요한 것은 흥미를 잃지 않고 꾸준히 학습하는 것입니다. 즐겁게 개발 여정을 시작하시길 바랍니다! 😊
SwiftUI에서 EnvironmentValues에 대해서 설명하고 있는 Developer Site
https://developer.apple.com/documentation/swiftui/environmentvalues
@Environment(\.verticalSizeClass) var verticalSizeClass
와 같이 환경 변수의 값을 가져올 수 있다.
SwiftUI Attributes Cheat Sheet: https://jaredsinclair.com/2020/05/07/swiftui-cheat-sheet.html
@State,
@Binding,
@ObservedObject,
@EnvironmentObject
@Environment
에 대해서, 어떤 경우에 사용하는 것이 맞는지 설명이 되어 있음.
참고할만함.
override func viewWillAppear(_ animated: Bool) {
//화면이 표시될때, Keyboard표시에 대한 이벤트가 발생하면 호출되는 함수를 등록한다.
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
func keyboardWillShow(_ notification:NSNotification) {
//키보드가 표시 될때, ToolBar의 위치를 올려준다.
moveToolbarUp(with: notification)
}
func keyboardWillHide(_ notification:NSNotification) {
//키보드가 사라질 때, ToolBar의 위치를 아래로 내려준다.
moveToolbarDown(with: notification)
}
fileprivate func moveToolbarUp(with notification:NSNotification) {
self.moveToolBar(isUp: true, with: notification)
}
fileprivate func moveToolbarDown(with notification:NSNotification) {
self.moveToolBar(isUp: false, with: notification)
}
fileprivate func moveToolBar(isUp up:Bool, with notification:NSNotification) {
if let userInfo = notification.userInfo {
//let beginFrame = (userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
let duration = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue
let animationOptions = UIViewAnimationOptions(rawValue: (userInfo[UIKeyboardAnimationCurveUserInfoKey] as! NSNumber).uintValue)
let frame = self.toolbar.frame
let rect:CGRect = CGRect(x: frame.origin.x,
y: frame.origin.y + endFrame.size.height * (up ? -1 : 1),
width: frame.size.width,
height: frame.size.height)
UIView.animate(withDuration: duration,
delay: 0.0,
options: animationOptions,
animations: { () -> Void in
self.toolbar.frame = rect
}, completion: nil)
}else{
//UserInfo가 없을 경우..
}
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
//화면이 옆으로 돌아갈 때, 호출되는 이벤트로, 이벤트 발생 시, 키보드를 아래로 내려주면 이동 후에 다시 선택하면 되도록 한다
self.inputTextField.resignFirstResponder();
}
override func viewWillAppear(_ animated: Bool) {
//화면이 표시될때, Keyboard표시에 대한 이벤트가 발생하면 호출되는 함수를 등록한다.
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardDidShow(_:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardDidHide(_:)), name: NSNotification.Name.UIKeyboardDidHide, object: nil)
}
override func viewWillDisappear(_ animated: Bool) {
//화면이 사라질 때, keyboard 표시에 대한 이벤트를 받지 않도록, 등록을 삭제한다.
NotificationCenter.default.removeObserver(self)
}
//키보드가 표시 될 때 호출 되는 함수
func keyboardWillShow(_ notification:NSNotification) {
print(notification)
info(name: "Keyboard Will beShown", with: notification)
somethingDo(with: notification)
}
func keyboardDidShow(_ notification:NSNotification) {
info(name: "Keyboard Was Shown", with: notification)
}
//키보드가 사라질 때, 호출 되는 함수
func keyboardWillHide(_ notification:NSNotification) {
info(name: "Keyboard Will beHidden", with: notification)
somethingDo(with: notification)
}
func keyboardDidHide(_ notification:NSNotification) {
info(name: "Keyboard Was Hidden", with: notification)
}
NSConcreteNotification 0x610000242460 {name = UIKeyboardWillShowNotification; userInfo = {
UIKeyboardAnimationCurveUserInfoKey = 7;
UIKeyboardAnimationDurationUserInfoKey = "0.25";
UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {375, 258}}";
UIKeyboardCenterBeginUserInfoKey = "NSPoint: {187.5, 796}";
UIKeyboardCenterEndUserInfoKey = "NSPoint: {187.5, 538}";
UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 667}, {375, 258}}";
UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 409}, {375, 258}}";
UIKeyboardIsLocalUserInfoKey = 1;
}}
fileprivate func info(name str:String, with notification:NSNotification) {
if let userInfo = notification.userInfo {
let frameBegin = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue ?? CGRect.zero
let frameEnd = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue ?? CGRect.zero
let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber ?? NSNumber.init(value: 0)
let duration = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber ).doubleValue
print("\(str) (\(Int(frameBegin.origin.x)),\(Int(frameBegin.origin.y)),\(Int(frameBegin.size.width)),\(Int(frameBegin.size.height))), (\(Int(frameEnd.origin.x)),\(Int(frameEnd.origin.y)),\(Int(frameEnd.size.width)),\(Int(frameEnd.size.height))) curve:\(curve), duration:\(duration)")
}
}