DADAHAE's Log
비싼 장난감 가지고 노는 중 (❁´▽`❁)*✲゚*
[TIL] 22-09-22: Swift (옵셔널, 연산자와 표현식)
22-09-22 목요일
2주차

 

 

 

1교시, 2교시, 3교시

 

Swift

데이터 타입, 상수, 그리고 변수
  • 데이터 타입 : 정수(Int), 부동소수점(Float, Double), 문자(”유니코드”), 문자열(“유니코드s”), 불리언(true, false)
  • 상수 : let
  • 변수 : var

 

잠깐 본론으로 들어가기 전에... 모든 조들이 함께하는 게임을 진행했다!

Playground 놀이 규칙

12개의 회고조를 돌면서 한 조당 한 판씩 문제를 푼다. 

단, 입력은 돌아가면서 진행한다.

  • 11 → 7 → 3 → 12 → 9 → 10 → 2 → 4 → 5 → 6 → 8

우리팀 차례에서 조건문에 and, or, not을 사용해서 확인하는 판이 걸렸다! 새로운 개념이 나와서 시간이 조금 걸렸지만 채팅으로 서로 논의하니까 금방 풀 수 있었다. :-)

 

 

옵셔널

옵셔널 타입

Optional type

변수, 상수는 초기화를 하지 않고 미리 만들어둘 수 있다. 그때 값이 들어올 수도, 안들어갈 수도 있는데 이를 표현?해주는게 옵셔널이다.

  • Swift 옵셔널 데이터 타입은 대부분의 다른 프로그래밍 언어에 없는 새로운 개념이다.
    • Swift가 먼저 이 개념을 탑재했고, 다른 언어들도 그 영향을 받아 옵셔널 개념을 적용하고 있다.
  • 옵셔널 타입의 목적은 변수 또는 상수에 값이 할당되지 않은 상황을 처리하기 위해 안전하고 일관된 접근 방식을 제공하는 것이다.
    • 없으면 없는대로 확인했으니까 넘어가자~ 하고 체크가 가능하다.
    • 즉, 내용이 없더라도 진행하는데 문제가 없도록 해준다.
  • 변수를 선언할 때, 데이터 타입 선언 다음에 ‘?’ 문자를 두어 옵셔널이 되게 한다.
var index: Int?
  • 이제 index 변수는 정수값이 할당되거나 아무런 값도 할당되지 않을 수 있다. 내부적으로 컴파일러와 런타임의 관점에서 볼 때 어떤 값도 할당되지 않은 옵셔널은 실제로 nil의 값을 갖는다.
    • nil도 하나의 값이다. nil 자체도 type에 의한 값(value)이다.
      • Int? → 정수형 옵셔널 타입
      • Int → 정수형 타입
      • Float? → 실수형 옵셔널 타입
      • Float → 실수형 타입
  • 옵셔널은 할당된 값이 있는지를 식별하기 위한 테스트를 다음과 같이 쉽게 할 수 있다.
var index: Int?

if index != nil {
	// index 변수는 값이 할당되어 있다.
} else {
	// index 변수는 값이 할당되어 있지 않다.
}

 

 

 

강제 언래핑

Forced unwrapping
  • 만약 옵셔널에 값이 할당되었다면 해당 값이 옵셔널 내에서 ‘래핑되었다(wrapped)’고 말한다.

옵셔널 안에 래핑된 값을 사용할 때는 강제 언래핑(forced unwrapping)이라는 개념을 이용하게 된다.

  • 래핑된 값은 옵셔널 데이터 타입에서 옵셔널 이름 뒤에 느낌표(!)를 두어 추출되게 한다.
  • 상자를 흔들어보고 있는지 없는지 판단하고 뜯는게 아니라, 그냥 바로 뜯는게 강제 언래핑이라고 보면 된다…
var index: Int?

index = 3

var treeArray = ["Oak", "Pine", "Yew", "Birch"]

if index != nil {
	print(treeArray[index!])
} else {
	print("index does not contain a value")
}

// Birch

 

 

  • 옵셔널로 할당된 값을 강제 언래핑하지 않고 직접 접근하면 에러가 발생한다!
var index: Int?

index = 3

var treeArray = ["Oak", "Pine", "Yew", "Birch"]

if index != nil {
	print(treeArray[index])   // 에러 발생...
} else {
	print("index does not contain a value")
}

옵셔널로 선언된 index값을 그냥 가져와서 에러가 났다...

 

  • 강제 언래핑을 시도할 때 주의하지 않으면 에러가 생길 수 있다.
    • 그러므로… 가능하면 사용하지 않는게 좋다!
    • 근데 실제 개발하다보면 써야할 경우도 있고 🤣
var index: Int?

index = 5

var treeArray = ["Oak", "Pine", "Yew", "Birch"]

if index != nil {
	print(treeArray[index]) 
} else {
	print("index does not contain a value")
}

배열에 없는 인덱스 값을 참조하려고 하니 에러가 발생하였다.

 

 

옵셔널 바인딩

Optional binding
  • 강제 언래핑 대신, 옵셔널로 할당된 값은 옵셔널 바인딩(optional binding)을 이용하여 임시 변수나 상수에 할당할 수 있다.
  • 다음의 코드는 두 가지 작업을 수행한다.
    • 지정된 옵셔널이 가지고 있는지를 확인한다.
    • 옵셔널 변수가 값을 가지고 있는 경우에 선언된 상수 또는 변수에 그 값을 할당하고 코드가 실행된다.
    if let constantName = optionalName {
    	...
    }
    
    if var variableName = optionalName {
    	...
    }

 

  • 옵셔널 바인딩
    • if let ~ else { ~ }
var index: Int?

index = 3

var treeArray = ["Oak", "Pine", "Year", "Birch"]

if let myValue = index {
	print(treeArray[myValue])
} else {
	print("index does not contain a value")
}
  • 위 코드는 index 변수에 할당된 값이 언래핑되어 myValue라는 임시 상수에 할당되어 배열에 대한 인덱스로 사용된다.
  • 임시 상수는 if 구문 안에서만 유효하다. (if 구문 실행이 끝나면 이 상수는 더 이상 존재하지 않게 된다)
  • 위의 이유로 옵셔널로 할당된 동일한 이름을 사용해도 충돌이 발생하지 않는다.
if let index = index {
	print(treeArray[index])
} else {
	...
}

그러나!!! 귀찮다고 같은 이름을 쓰지말자. 이렇게 쓴 코드를 코드리뷰 시간에 꼭 말해주자.

같이 협업하는 상황에서 저렇게 하면… 읽기가 힘들어진다.

이론적으로는 가능하지만, 하지마라.

 

 

  • 옵셔널 바인딩은 여러 개의 옵셔널을 언래핑하고 조건문을 포함하는 데 사용될 수 있다.
if let 상수명1 = 옵셔널이름1, let 상수명2 = 옵셔널이름2, let 상수명3 = 옵셔널이름3, ... <조건식> { 
	... 
}
var pet1: String?
var pet2: String?

pet1 = "cat"
pet2 = "dog"

if let firstPet = pet1, let secondPet = pet2 {
	print(firstPet)
	print(secondPet)
} else {
	print("insufficient pets")
}

 

 

  • 다음의 코드는 조건문을 사용하는 예제다.
    • petCount가 1보다 크지 않다면 옵셔널 바인딩이 수행되지 않을 것이다.

 

var pet1: String?
var pet2: String?

pet1 = "cat"
pet2 = "dog"

let petCount = 15

if let firstPet = pet1, let secondPet = pet2, petCount > 1 {
	print(firstPet)
	print(secondPet)
	} else {
	print("insufficient pets")
}

/*
cat
dog
*/

 

 

 

더보기

갑자기 수업 중간에 꿀팁.

 

Swift Evolution

: Swift의 기능을 제안할 수 있는 사이트.

open source로 나와있으니까, 이런 기능을 제안해줄 수 있나? 하고 올려두는 것이다.

Swift Evolution

 

Swift Evolution

 

apple.github.io

 

 

 

강제적으로 언래핑

아예 타입에 느낌표를 쓰는 방법
  • 강제적으로 언래핑되도록 옵셔널을 선언할 수 있다.
  • 이 방식으로 옵셔널을 선언하면 강제 언래핑이나 옵셔널 바인딩을 하지 않아도 값에 접근할 수 있다.
  • 옵셔널을 선언할 때 물음표(?) 대신에 느낌표(!)를 사용하여 강제적으로 언래핑되도록 하는 것이다.
var index: Int! // 이제 옵셔널은 강제적으로 언래핑된다.

index = 3

var treeArray = ["Oak", "Pine", "Yew", "Birch"]

if index != nil {
	print(treeArray[index]) // 이제 index를 언래핑없이 바로 쓸 수 있다.
} else {
	print("index does not contain a value")
}

// Birch
  • 할당된 값이 없거나 nil을 할당할 수 있는 것은 옵셔널 타입뿐이다.
  • 옵셔널이 아닌 변수 또는 상수에는 nil을 할당할 수 없다.
  • 다음의 코드는 모두 유효하지 않다. (옵셔널로 선언된 변수가 아니다)
// var myInt = nil             // NO
// var myString: String = nil  // NO
// let myConstant = nil        // NO

 

 


 

Any, AnyObject 와 nil

Any

  • 스위프트의 모든 데이터 타입을 사용할 수 있다는 뜻
  • 변수 또는 상수의 데이터 타입이 Any로 지정되어 있다면 그 변수 또는 상수에는 어떤 종류의 데이터 타입이든지 상관없이 할당할 수 있다.
var someVar: Any = "dadahae"
someVar = 60     // 가능
someVar = 100.1  // 가능

 

  • 예제 코드 (아래 쪽을 보자)
    • (1) : someAny → Int
      • 100을 할당했기 때문에 타입 추론으로 Int형이 된다.
    • (2) : someAny → String
      • 문자열을 재할당했기 때문에 String 형이 된다.
    • (3) : someAny → Float
      • 실수형 숫자가 재할당되었기 때문에 Float 형이 된다.
    • 컴파일 오류…
      • Any형인 someAny를 Double 형인 someDouble에 넣을 수 없다..!
var someAny: Any = 100   // (1)
someAny = "어떤 타입도 수용 가능합니다" // (2)
someAny = 123.12      // (3)

let someDouble: Double = someAny // 컴파일 오류

 

AnyObejct

  • Any보다는 조금 한정된 의미
  • 클래스와 인스턴스만 할당될 수 있다.
  • Any와 AnyObject는 가능한 사용하지 않는 것이 좋다.
  • 타입에 엄격한 Swift 언어의 특성상 Any 또는 AnyObject로 선언된 변수의 값을 가져다 쓰려면 배번 타입 확인 및 변환을 해줘야 하는 불편과 예기치 못한 오류의 위험 증가의 문제가 생긴다.
  • 타입은 될 수있는 한 정확하게 명시하는 것이 좋다.

 

nil

  • 특정 타입이 아니라 ‘없음’을 나타내는 Swift의 키워드
  • 변수 또는 상수에 값이 들어있지 않고 비어있음을 나타내는 데 사용한다.
  • nil이면 해당 변수 또는 상수에 접근했을 때 잘못된 메모리 접근으로 런타임 오류가 발생한다.
someAny = nil        // 컴파일 오류
someAnyObject = nil  // 컴파일 오류

 

 


 

타입 캐스팅과 타입 검사

타입캐스팅 → 욱여넣는다.

 

타입 캐스팅

Type casting
  • Swift 코드를 작성할 때 컴파일러가 어떤 값의 특정 타입을 식별하지 못하는 경우가 발생할 것이다.
  • 이런 경우는 메서드나 함수가 반환하는 값이 불분명하거나 예상되지 않은 타입의 값일 때 종종 발생한다.
  • 이럴 때는 as 키워드를 사용하여 코드가 의도하는 값의 타입을 컴파일러가 알 수있게 해야 한다. (타입 캐스팅 = 형 변환)
  • object(forked:) 메서드가 반환하는 값을 String 타입으로 처리해야 한다고 컴파일러에게 알려줘야 한다면…
let myValue = record.object(forKey: "comment") as! String

 

업캐스팅

upcasting
  • 타입캐스팅의 두 가지 형태 중 하나
  • 특정 클래스의 객체가 상위 클래스들 중의 하나로 변형되는 것
  • as 키워드를 사용해, 이러한 변환은 성공할 것이라고 줌 - 보장된 변환(guaranteed conversion)
let myButton: UIButton = UIButton()
let myControl = myButton as UIControl

업캐스팅은 밑에서 위로 가는 것

더보기

밑에서 위로 간다? 무슨 말이냐면...

 

클래스들은 상속관계를 가지고 있을 경우 super, sub 으로 상위와 하위 클래스의 관계를 가진다.

어떤 느낌이냐면 아래 그림처럼 큰 항목인 '회사'의 아래에는 '벤츠'라는 회사도 있을 것이고, '현대','기아'와 같은 회사들이 있을 것이다.

여기서 '회사' 클래스는 상위클래스이고 '벤츠', '현대', '기아'는 회사 클래스의 하위 클래스이다.

 

  • as? 를 사용한 옵셔널 바인딩을 사용하면 더 안전하다.

 

 

타입 검사

Type check
  • is 키워드를 사용하여 타입 검사를 할 수도 있다.
  • 다음의 코드는 MyClass라는 이름의 클래스의 인스턴스인지를 검사하는 코드다.
is myObject is MyClass {
	// myObject는 MyClass의 인스턴스이다.
}

 

요약

데이터 타입, 상수, 그리고 변수
  • 상수와 변수를 어떻게 선언하는가
  • 타입 안정성, 타입 추론, 옵셔널의 개념
  • 각각은 Swift 프로그래밍의 핵심 부분으로 오류없는 코드를 만들기 위하여 특별히 제작되었다.

 

 



 

Swift

연산자와 표현식

&&, ||, !, = +, -, /, %, *

 

목표

연산자와 표현식

  • 앞서 배운 것
    • 변수와 상수를 어떻게 사용하는가
    • 여러 데이터 타입
  • 이번에 배울 것
    • 코드와 변수와 상수를 어떻게 활용할까
    • 변수, 상수와 같은 데이터를 가지고 작업하는 가장 기본적인 방법은 표현식(expression) 형태로 작업하는 것이다.
    • 우리가 쓰는 한줄한줄의 문장이 표현식이라고 생각해도 된다.

 

 


 

표현식 구문

Expression
  • 하나의 연산자(operator)
  • 두 개의 피연산자(operand)
  • 할당자(assignment)
    • 값 → copy
    • call by value / call by reference
var myResult = 1 + 2
  • +
    • ‘+’ 연산자
    • 1과 2를 더하는 데 사용
  • =
    • ‘=’ 할당 연산자
    • 덧셈의 결과를 myResult라는 이름의 변수에 할당한다.
  • 1, 2
    • 피 연산자
    • 숫자 외에도 변수, 상수의 혼합도 가능

 


 

기본 할당 연산자

a, the, an …

  • 앞서 본 할당 연산자(’=’ 연산자)는 표현식의 결과를 변수에 저장하는 역할을 한다.
  • 기본적으로 ‘=’할당 연산자는 두 개의 피 연산자를 받는다.
    • 왼쪽의 피연산자 : 값을 할당받는 변수 또는 상수
    • 오른쪽의 피연산자 : 할당할 값, 대체로 여러 종류의 산술식이거나 논리식을 수행하는 표현식으로 왼쪽에 그 결과 반영(copy)
var myResult = 1 + 2
  • var myResult : 왼쪽의 피연산자(할당 받을 대상)
  • 1 + 2 : 오른쪽의 피연산자(할당할 값)
var x: Int?   // 옵셔널 Int 변수 선언
var y = 10    // 두번째 Int 변수 선언과 초기화
x = 10        // x에 값 할당
x = x! + y    // 언래핑한 x와 y의 합을 x에 할당
x = y         // y의 값을 x에 할당

 

 


 

 

산술 연산자

  • Swift는 수학적 표현식을 생성하기 위하여 다양한 연산자를 제공한다.
  • 이들 연산자 대부분은 두 개의 피연산자를 받는 이항 연산자(binary operator)다.
  • 양수를 음수로 만들어주는 단항 음수 연산자(unary negative operator)는 예외적으로 하나의 피연산자를 받는다.
    • 두 개의 피연산자를 받는 뺄셈 연산자(substraction operator)와 대조된다.
var x = -10     // 단향 '-'연산자는 변수 x에 -10을 할당하기 위해 사용한다.
x = x - 5       // 뺄셈 연산자로 x에서 5를 뺀다.
  • +, -, *(곱셈), /(나눗셈), 5(몫)
  • 하나의 표현식 안에 여러 개의 연산자를 사용할 수도 있다.
x = y * 10 + z - 5 / 4

괄호를 써서 연산의 우선순위를 구분해주자.

 

 

 


 

복합 할당 연산자

  • Swift는 산술 또는 노리 연산과 할당 연산자를 결합하기 위해 설계된 연산자들을 다양하게 제공한다.
  • 이러한 연산자들은 연산을 수행한 결과를 피연산자들 중 하나에 저장하기 위해 주로 사용한다.
x = x + y
x += y

// 위 표현식은 모두 같은 의미이다.

 

 


 

 

비교 연산자

  • 스위프트는 비교를 수행하는 데 유용한 논리 연산자들을 가지고 있다.
  • 이들 연산자 모두는 비교 결과에 따라 불리언 결과를 반환한다.
  • 이들 연산자들은 두 개의 피연산자들을 가지고 작업한다는 점에서 이항연산자(binary operator)이다.
  • 비교연산자는 프로그램 흐름 제어 로직을 만드는데 가장 많이 사용된다.
if x == y {
	// 작업 수행
}

 

 


 

 

불리언 논리 연산자

  • Swift는 true 또는 false 값을 반환하도록 설계된, 소위 논리 연산자들도 제공한다.
  • 이러한 연산자들은 피연산자로 불리언 값을 받아서 불리언 결과를 반환한다.
    • NOT (!)
    • AND (&&)
    • OR (||)

 

NOT(!) 연산자

  • 단순히 불리언 변수의 현재 값 또는 표현식의 결과를 반전시킨다.
  • flag라는 이름의 변수가 현재 true라 한다면 변수명 앞에 ! 문자를 두면 값이 false로 바뀔 것이다.
var flag: Bool = true   // 변수는 true이다.
var secondFlag = !flag  // secondFlag에는 false가 저장된다.

 

OR(||) 연산자

  • 두 개의 피연산자 중 하나가 true라고 판단되면 true를 반환하고
  • 두 개의 피연산자 중 어느 것도 true가 아니라면 false를 반환한다.
if (10 < 20) || (20 < 10) {   // true 반환:  OR 연산자를 기준으로 하나가 true이므로.
	print("Expression is true")
}

 

AND(&&) 연산자

  • 두 개의 피연산자 모두 true라고 판단될 때만 true를 반환한다.
if (10 < 20) && (20 < 10) {  // false 반환: AND 연산자를 기준으로 모두 false이기 때문
	print("Expression is true")
}

 

 

 


 

범위 연산자

  • Swift는 값이 범위를 선언할 수 있도록 하는 몇 가지 연산자가 포함되어 있다.
  • 이들 연산자는 프로그램에서 반복 작업을 할 때 매우 중요하다.
  • 닫힌 범위 연산자(closed range operator)
    • x…y : x로 시작하여 y로 끝나는 숫자의 범위, x와 y는 이 범위에 포한된다.
    • 5…8 : 5,6,7,8
  • 반 개방 범위 연산자(half-open range operator)
    • x..<y : x로 시작하는 모든 숫자를 포함하지만 y는 포함되지 않는다.
    • 5..<8 : 5,6,7
  • 단방향 범위 연산자(one-sided range operator)
    • 그 범위 앞의 시작 또는 끝에 도달할 때까지 (또는 다른 조건이 충족할 때까지) 지정된 범위 방향으로 최대한 확장할 수 있는 범위를 지정한다.
    • 범위 선언부의 한쪽 부분을 생략하여 선언한다.
    • x…
    • …y
    • 2… : 예)문자열의 길이와는 상관없이 문자열의 세번째 텍스트부터 시작해서 마지막 문자들까지 지정하는 범위
    • …6 : 첫번째부터 7번째까지의 범위

 

 

삼항 연산자

  • Swift는 코드 내에서 판단을 간단히 하기 위한 방법으로 삼항 연산자(ternary operator)를 지원한다.
조건문 ? 참(true)인 경우의 표현식 : 거짓(false)인 경우의 표현식
  • 삼항 연산자의 동작 방식은 true 또는 false를 반환하는 표현식을 ‘조건문’ 위치에 두는 것이다.
    • 만약 그 결과가 true이면 ‘참인 경우의 표현식’이 수행된다.
    • 만약 그 결과가 false이면 ‘거짓인 경우의 표현식’이 수행된다.
let x = 10
let y = 20

print("Largest number is \\(x > y ? x : y)")

// Largest number is 20

 

 


 

요약

연산자와 표현식
  • 다양한 종류의 연산자
  • 연산자와 표현식은 Swift 코드 내에서 변수와 상수를 변경하고 판단하는 기본 메커니즘을 제공한다.
  • 가장 간단한 형태로는 덧셈 연산자를 이용하여 두 개의 숫자를 더하고 할당 연산자를 이용하여 그 결과를 변수에 저장하는 것이다.
  Comments,     Trackbacks