간단한 앱 만들기

간단한 전광판 앱을 만들기 위해 레이아웃을 배치했다. Autoshrink를 통해서 최소 글자 크기를 지정할 수 있다.

코드와 레이아웃을 연결하기 위해서 마우스 우클릭으로 끌어다 놓으면 Outlet이나 Action을 연결할 수 있다.
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var textField: UITextField!
@IBOutlet weak var label: UILabel!
@IBAction func displayText(_ sender: UIButton) {
label.text = textField.text
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}

입력한 텍스트를 화면에 표시할 수 있도록 했다.
이번에는 애니메이션 기능을 추가해보자.

import UIKit
class ViewController: UIViewController {
@IBOutlet weak var textField: UITextField!
@IBOutlet weak var label: UILabel!
@IBAction func displayText(_ sender: UIButton) {
label.text = textField.text
UIView.animate(withDuration: 10, delay: 0, animations: {
self.label.center.x -= self.view.bounds.width
})
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}

버튼을 누르면 텍스트가 왼쪽으로 이동하도록 만들었다.

핸드폰을 옆으로 기울이면 레이아웃이 다 깨지기 때문에 오토레이아웃을 고려하여 만들어야 한다.
연산자 복습
Swift에는 ++, -- 연산자가 없다. 그렇기 때문에
var x = 10
x += 1
print(x)
이런식으로 +=나 -=를 사용하면 된다.


nil 합병 연산자로 nil이 아닐 때의 값을 지정할 수 있다.

스위프트에서는 for in 반복문을 사용한다.

xcode에서 위와 같이 노란 삼각형이 뜰 때가 있는데 더 나은 수정할 수 있는 사항이 있을 경우 추천해주는 것이다.
위와 같은 경우는 x를 사용하지 않기 때문에 _로 대체할 수 있다는 것이다.

이런식으로 문자열 안에 \()를 사용하면 변수의 값을 문자열 안에서 사용할 수 있다.

&&로 연결하면 논리식이 둘 다 참일 때 사용하고, 콤마(,)는 조건이 둘 다 참일 때 사용한다.
Optional
var x : Int?
print(x) // nil
var y : Int? = 10
print(y) // Optional(10)
?를 지정하면 옵셔널을 사용한다는 것이다. 값을 지정하지 않으면 nil이고, 값을 지정하면 Optional(10)으로 저장되어 있는 것을 알 수 있다.
var x : Int? = 10
print(x!) // 10
!를 사용하면 Optional을 풀고 안에 있는 10이라는 값을 가져올 수 있다.

그런데 값이 지정되지 않았을 때 !로 옵셔널을 풀려고 하면 오류가 발생한다.
var x : Int?
if x != nil {
print(x!)
} else {
print("nil")
}
이런식으로 nil이 아닐 때만 값을 사용하도록 할 수 있다.

x!=nil 이렇게 붙여서 사용하면 !가 우선순위가 더 높기 때문에 오류가 발생한다. 그렇기 때문에 x != nil이라고 띄어쓰기를 잘 해서 사용해야 한다.
옵셔널 바인딩
var x : Int?
x = 10
if let xx = x {
print(x,xx)
}
else {
print("nil")
}

옵셔널 바인딩을 이용하면 옵셔널을 푼 값이 저장되어있는 변수나 상수를 바로 사용할 수 있다.

이런식으로 같은 변수명으로 사용할 수도 있다.

심지어는 그냥 x라고만 사용해도 똑같이 작동한다.
스위프트 5.7부터 가능한 방법으로 short form 이라고 한다.
var x : Int?
var y : Int?
x = 1
y = 2
print(x, y)
if let x, let y {
print(x, y)
}
else {
print("nil")
}

콤마(,)로 여러 옵셔널 값을 한번에 푸는 것도 가능하다.

변수나 상수가 하나라도 nil이라면 거짓으로 판단해서 else 블럭이 실행된다.
nil 합병 연산자
var x : Int?
x = 1
var y = x ?? 0
print(y) // 1
nil 합병 연산자는 ?? 앞에 옵셔널 변수를, 뒤에는 nil일 때 사용할 값을 지정한다.
??를 사용해서 nil이 아닐 경우 반환되는 값은 옵셔널이 풀린 값으로 반환된다.
var x : Int?
//x = 1
var y = x ?? 0
print(y) // 0
이렇게 x가 nil이면 0이 출력된다.

?와 !

선언할 때 !를 사용하는 것도 옵셔널이지만 약간의 차이가 있다. 이를 암묵적 언래핑이라고 한다.

옵셔널로 사용할 수 없는 경우에 자동으로 언래핑하는 방법이다.

let a : Int! = 1
let b : Int = a
let c : Int = a!
let d = a
let e = a + 1
print(a,b,c,d,e)


Swift에서 옵셔널(Optional)을 사용하는 두 가지 방법, 즉 ?와 !는 다음과 같은 차이점을 가집니다.
기준? (옵셔널)! (강제 언래핑)
| 정의 | 값이 있을 수도 있고, 없을 수도 있는 경우 사용 | 값이 반드시 있을 것이라고 확신할 때 사용 |
| 사용 시점 | 변수 선언 시 | 변수 사용 시 |
| 안전성 | 안전함. 값이 nil일 수 있음을 명시적으로 표현 | 위험할 수 있음. nil이면 런타임 오류 발생 |
| 반환 값 | Optional<Type> | Type |
| 사용 예시 | var name: String? | var name: String! or print(name!) |
| 사용 이유 | 값의 존재 여부가 확실하지 않을 때 안전한 코드 작성을 위해 | 개발자가 값이 nil이 아니라는 것을 확신하고, 매번 언래핑하는 번거로움을 피하기 위해 |
| 언래핑 방법 | 옵셔널 바인딩(if let, guard let), 옵셔널 체이닝, nil 병합 연산자 등을 사용해 안전하게 언래핑 | 변수 또는 상수에 직접 접근함으로써 강제로 언래핑 |
요약하자면, ?는 옵셔널 변수를 선언할 때 사용하며, 이는 값이 nil일 수 있음을 안전하게 다루기 위한 방법입니다. 반면, !는 주로 변수가 이미 값으로 초기화되었음을 확신할 때 사용하며, 이를 통해 강제로 언래핑합니다. 하지만, !를 사용할 때는 해당 변수가 nil이 아니라는 것을 확실히 알고 있어야 하며, 그렇지 않을 경우 런타임 오류가 발생할 위험이 있습니다.
함수

func sayHello() -> Void { // -> Void 는 생략 가능
print("Hello")
}
sayHello()
이런식으로 함수를 사용한다.
리턴값이 없을 경우 -> Void를 생략할 수 있다.
//int add(int x, int y) { // C, C++
// return (x+y);
//}
//add(10,20);
func add(x: Int, y: Int) -> Int {
return x+y
}
print(add(x:10, y:20))

여기서 x와 y는 parameter이지만 스위프트에서는 argument label을 생략했을 경우 자동으로 parameter name과 동일하게 사용한다.

//int add(int x, int y) { // C, C++
// return (x+y);
//}
//add(10,20);
func add(x: Int, y: Int) -> Int {
return x+y
}
print(add(x:10, y:20)) // parameter name만 지정
func add1(first x: Int, second y: Int) -> Int {
return x+y
}
print(add1(first:10, second:20)) // argument label
func add2(_ x: Int, _ y: Int) -> Int {
return x+y
}
print(add2(10, 20)) // argument label 생략
func add3(_ x : Int, with y : Int) -> Int {
return(x + y)
}
print(add3(10, with:20)) // 혼합
가능한 4가지 방식을 정리해보았다.
함수의 자료형
func add(x: Int, y: Int) -> Int {
return x+y
}
// print(add(x:10, y:20)) // parameter name만 지정
print(type(of: add))
func add1(first x: Int, second y: Int) -> Int {
return x+y
}
// print(add1(first:10, second:20)) // argument label
print(type(of: add1))
func add2(_ x: Int, _ y: Int) -> Int {
return x+y
}
// print(add2(10, 20)) // argument label 생략
print(type(of: add2))
func add3(_ x : Int, with y : Int) -> Int {
return(x + y)
}
// print(add3(10, with:20)) // 혼합
print(type(of: add3))
함수도 자료형이 있는데 한번 확인해보았다.

argument label이나 parameter name과는 상관없이 타입에 관련된 정보만 출력된 것을 알 수 있다.
결국 자료형은 네 함수 모두 동일한 것이다.
func add(x: Int, y: Int) -> Int {
print(#function)
return x+y
}
// print(add(x:10, y:20)) // parameter name만 지정
// print(type(of: add))
add(x:10, y:20)
func add1(first x: Int, second y: Int) -> Int {
print(#function)
return x+y
}
// print(add1(first:10, second:20)) // argument label
// print(type(of: add1))
add1(first:10, second:20)
func add2(_ x: Int, _ y: Int) -> Int {
print(#function)
return x+y
}
// print(add2(10, 20)) // argument label 생략
// print(type(of: add2))
add2(10, 20)
func add3(_ x : Int, with y : Int) -> Int {
print(#function)
return(x + y)
}
// print(add3(10, with:20)) // 혼합
// print(type(of: add3))
add3(10, with:20)
함수의 이름
func add(x: Int, y: Int) -> Int {
print(#function)
return x+y
}
// print(add(x:10, y:20)) // parameter name만 지정
// print(type(of: add))
add(x:10, y:20)
func add1(first x: Int, second y: Int) -> Int {
print(#function)
return x+y
}
// print(add1(first:10, second:20)) // argument label
// print(type(of: add1))
add1(first:10, second:20)
func add2(_ x: Int, _ y: Int) -> Int {
print(#function)
return x+y
}
// print(add2(10, 20)) // argument label 생략
// print(type(of: add2))
add2(10, 20)
func add3(_ x : Int, with y : Int) -> Int {
print(#function)
return(x + y)
}
// print(add3(10, with:20)) // 혼합
// print(type(of: add3))
add3(10, with:20)

스위프트에서 함수명은 위에서는 add가 아니라 argument label과 콜론(:)을 포함한 것까지가 함수명이다.
https://developer.apple.com/documentation/uikit/uitableviewdatasource
UITableViewDataSource | Apple Developer Documentation
The methods that an object adopts to manage data and provide cells for a table view.
developer.apple.com

위의 사이트를 들어가보면 argument label을 기준으로 함수를 찾을 수 있다.

한 함수의 자료형과 함수명을 살펴보자.
tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
함수의 자료형은?
(UITableView, Int) -> Int
함수명은?
tableView(_:numberOfRowsInSection:)
디폴트 매개변수

func add(x: Int, y: Int = 0) -> Int {
//print(#function)
return x+y
}
// print(add(x:10, y:20)) // parameter name만 지정
// print(type(of: add))
print(add(x:10))

https://developer.apple.com/documentation/uikit/uiview/1622515-animate
animate(withDuration:animations:completion:) | Apple Developer Documentation
Animate changes to one or more views using the specified duration and completion handler.
developer.apple.com

() -> Void 는 매개변수, 리턴값이 모두 없는 함수를 의미하고,
((Bool) -> Void)? = nil 은 매개변수는 Bool 타입이고 리턴값이 Void인 함수이다. = nil은 디폴트 매개변수이다.
클래스



프로퍼티는 초기값이 있어야 한다. 그 중 한 방법이 클래스에 알맞은 생성자를 만드는 것이다.
class Man {
var age : Int = 0
var weight : Double = 0.0
}
이런식으로 초기값을 주면 에러가 사라진다.

class Man {
var age : Int?
var weight : Double?
}
이런식으로 옵셔널로 지정해도 된다.

XCode에서 이런식으로 프로퍼티가 !로 설정되어 있는 이유는 초기값이 없기 때문이다.
class Man{
var age : Int = 1
var weight : Double = 3.5
func display(){ // 인스턴스 메서드
print("나이=\(age), 몸무게=\(weight)")
}
}
var soft : Man = Man()
print(soft.age)
print(soft.weight)
soft.display()


이렇게 타입을 명시적으로 적어주지 않아도 된다.
'공부 > Swift' 카테고리의 다른 글
| [iOS][6주차] TableView & 간단한 앱 만들기 2 / 다운캐스팅, 옵셔널 (0) | 2024.04.11 |
|---|---|
| [iOS][5주차] Swift 문법 복습 / TableView (0) | 2024.04.04 |
| [iOS][2주차] 스위프트 복습 (0) | 2024.03.14 |
| [iOS][1주차] 들어가기 (0) | 2024.03.07 |
| [Swift][13주차] BMI 계산기 (0) | 2023.11.27 |