[Swift3입문]2. 변수, 상수 그리고 기본적인 형들

2017-02-15
23 Views

변수와 상수는 프로그램에 나오는 값을 기억하기 위한 그릇이다. 모든 변수 및 상수는 형을 가지고 있으며, 형은 그것들에게 대입할 수 있는 값의 종류를 나타낸다. 변수 및 상수는 일정한 범위 내 프로그램에서 참조가 가능하고 필요에 따라 값을 다시 사용할 수 있다. 이번 내용에서는 Swift 3.0 언어의 변수 및 상수를 처리하는 방법 기본적인 형들을 정리해본다.

1. 변수, 상수 및 형에 의한 값 관리

변수 및 상수 값의 저장에 사용한다. 변수는 설정된 값을 변경할 수 있고 상수는 설정된 값을 변경할 수 없다. 프로그램의 규모가 커질수록 값 관리는 복잡해지고, 변수 및 상수의 구별은 고려하지만 변경은 최소화한다.

형은 변수와 상수에 들어있는 값의 종류를 알 수 있다. Swift 언어는 숫자나 문자열등의 일반적인 프로그램에 나오는 일반적인 값을 나타내는 형은 내장되어 있다. Swift언어의 주요 내장된 형은 Bool형, 숫자형은 String, Array<Element>형, Dictionary<Key, Value>형, 범위형인 Optional<Wrapped>형, Any형에 대해서 이제 알아볼 것이다. 또한 형은 표준 라이브러리에서 제공하는 것 이외에 독자적인 형도 정의할 수 있다.

2. 변수와 상수

변수는 값을 저장하기 위한 그릇에 이름과 형을 가지고 있다. 이름은 변수명이라고 하며, 변수명은 프로그램에서 변수에 접근하는데 사용한다. 형은 변수가 가지는 값의 종류에서 변수에 어떤 값을 대입할 수 있는지를 보여준다. 변수는 형이 일치하는 값이면 몇번이나 다시 할당할 수 있다. 상수는 값을 가진 그릇으로 변수와 비슷하지만 값이 다시 할당할 수 없다. Swift 언어는 한번 대입한 값을 변경할 필요가 있는 경우 변수를 사용하여 변경할 필요가 없으면 상수를 사용한다. 상수를 사용하면 값 변경을 고려할 필요없고, 변경이 예상되지 않는 값을 업데이터하는 오류를 범하지 않을 수 있다.

선언방법

변수는 var, 상수는 let이란 키워드를 사용하여 아래와 같이 선언한다.

아래 예제에서는 첫번째 줄은 변수명 a라는 Int형 변수를 선언하고 두번째 줄은 정수명 b는 Int형 정수를 선언한다.

변수 및 상수의 선언형태는 var, let의 선언 차이만 있다. 문법은 변수가 사용할 수 있는 것들이 많고 정수도 사용할 수 있다. 변수 및 상수 선언시 형명을 나타내는 : Int형태는 형 주석(Type annotation)이라고 하며 주석은 의미를 가지는 변수 및 상수형을 명시적으로 결정하는 역할을 한다.

형추론

변수 및 상수는 선언과 동시에 값을 할당할 수 있다. 아래 에는 Int형 정수 a를 선언함과 동시에 100을 대입하고 있다.

100은 Int형이기 때문에 형주석이 없어도 상수 a형이 Int형이라고 추론할 수 있다. 이처럼 대입되는 값에서 형을 유추할 수 있는 경우 형주석을 생략할 수 있다. 형주석을 생략하면 변수 및 상수 형은 대입되는 값에 따라 달라진다. 에로 선언할 때 Int형값을 대입하면 Int형으로 인식되고 String형값을 대입하면 String형이 된다.

위와 같이 프로그램에서 암시적으로 형을 결정하는 구조를 형추론이라고 말한다. 일반적으로 형추론을 사용한다면 형주석을 생략하고 형주석이 없으면 변수 및 상수 형을 결정할 수 없는 경우에만 형주석을 추가한다.

형 확인방법

형주석과 형추론에 의해 결정되는 변수 및 상수형을 확인하려면 type(of:)함수를 이용한다. type(of:)함수는 실행할 때 형을 리턴하는 함수로 다음과 같이 사용한다.

100을 통해 형추론된 상수 a의 형을 확인하려면 다음과 같이 작성한다. type(of: a)의 결과는 Int.Type이라고 나온다.

팁으로 Xcode로 코딩할 때 변수와 상수형을 표시하는 QuickHelp라는 기능이 있는데 이를 활용해보자. 형을 알고 싶은 변수나 상수에 커서를 가져가고 Xcode 메뉴에서 [Help] – [Quick Help for Selected Item] (Control + Command + ?키)를 선택하면 아래 화면처럼 변수 및 상수형 정보가 팝업으로 표시된다. 또는 Xcode 메뉴에서 [View] – [Utilities] – [Show Quick Help Inspector] (Control + Command + 2키)를 누르면 화면 오른쪽에 상세화면으로 형 상태를 보여준다.

Swift 언어에서 변수나 상수명은 알파벳 및 숫자뿐만 아니라, 한글 및 중국어, 이모티콘도 사용이 가능하다. 그러나 실제로 알파벳과 숫자만 사용하는 것이 실무 개발의 현실이다. 또한 변수 및 상수명은 이름과 형을 가질 필요가 있다. 즉, 형주석을 사용하거나 값을 할당하여 해당 형을 결정해야 한다.

예로 다음과 같이 형주석도 값도 대입하지 않는 코드는 형이 결정하지 않았기 때문에 컴파일 오류가 발생한다.

할당방법

변수와 상수에 값을 할당하려면 = 연산자을 기준으로 좌측에 변수 및 상수명을 입력하고 우측에 해당 값을 입력한다.

아래 예는 Int형 변수 a를 선언하고 10값을 대입하는 것을 보여준다.

Swift 언어에서는 변수 및 상수를 안전하게 이용하기 위해서 할당에 관련 몇가지 규정이 있는데 이에 대한 규정을 컴파일러에서 체크하기 때문에 규정을 어긴 프로그램을 실행할 수 없다.

변수 및 상수에 할당할 수 있는 값은 변수와 상수 형에 일치하고 있는 것만 가능하다. 예로 형주석에 지정된 형과 대입하는 값형이 일치하지 않는 경우 컴파일 오류가 발생한다. 아래 예는 Int형 형주석이 추가된 상수 a에 Int형값 100을 대입하여 오류가 발생하지 않지만 다음으로 Int형주석이 추가된 상수 b에 String값 “대한민국”을 대입하여 컴파일 오류가 발생한다.

대입에 의한 형이 정해진 경우도 동일하다. 선언할 때 Int형 값을 할당한 변수에 String값을 선언했기 때문에 컴파일 오류가 발생한다. 변수 및 상수는 다른 변수와 상수값을 할당할 수 있다. 이 경우 대입은 원래 변수와 상수에 대입하는 변수 및 상수형이 일치해야 한다.

+ 연산자등의 연산결과나 함수호출 결과등 처리결과값을 리턴하는 형태를 표현식이라고 한다. 식이 리턴값 형이 변수나 상수형과 일치하는 경우, 변수 및 상수에 할당한다. 아래 예는 Int형과 Int형의 연산결과인 Int형값을 Int형 정수에 대입는 표현식을 보여준다.

지금까지의 예로 나온 3이나 1 및 “대한민국”등의 값을 프로그램에 직접 표기하는 형을 리터럴이라고 하며 Swift언어에서는 변수 및 상수값이 존재하지 않는 것을 nil이라는 리터럴로 표현하지만 대부분의 형은 nil리터털을 허용하지 않는다. 아래 예는 Int형 변수에 nil리터럴을 할당하고 있지만 Int형에 nil리터럴을 할당하면 오류가 발생한다.

변수와 상수가 처음하는 것은 초기화가 있다. 초기화하지 않는 변수 및 상수값을 가지고 있지 않기 때문에 그대로 값을 사용할 수 없습니다. 따라서 컴파일러는 초기화되지 않는 변수 및 상수 사용을 감지하고 컴파일 오류가 발생한다. 아래 예는 Int형 변수 a가 초기화되기 전에 이용되어 오류가 발생하는 것을 보여준다.

초기화되지 않는 변수 및 상수의 사용은 컴파일 오류가 발생하기 때문에 컴파일이 가능한 프로그램은 초기화디지 않은 변수 및 상수에는 접근할 수 없다. 따라서 Swift언어 기반 프로그래밍에서는 초기화되지 않는 상태의 변수 및 상수에 대한 접근은 안된다는것을 명심하자.

또한 변수는 몇번이라도 재할당이 가능하지만, 상수는 재할당이 금지되어 있기 때문에 다시 할당하는 경우 컴파일 오류가 발생한다.

상수는 다시 할당할 수없기 때문에, 반드시 상수의 선언과 동시에 값을 할당할 수 없다. 예로 상수선언만 하는 경우에도 대입이 한반밖에 하지 않는 것을 고려해서 작업한다면 오류가 발생하지 않는다.

실제로 대입은 한번밖에 되지 않는 코드이지마 컴파일러가 이를 보장하지 못하면 컴파일 오류가 발생한다. 예로 정수 index에 1이 있는 상태에서 a = index가 한번만 실행되지만 컴파일러는 상수 a에 한번만 대입된다는 것을 보장하기 어렵기 때문에 컴파일 오류가 발생한다.

3. 범위

범위는 변수, 상수, 함수, 형 이름의 범위를 나타내는 것을 말한다. 범위는 그 범위에 따라 전역, 로컬 범위로 나뉜다. 동일한 범위내에 동일한 이름은 여러개가 존재할 수 없으며, 변수, 상수, 함수형의 종류가 다르더라도 이름을 고유해야 한다.

또한 여기서는 변수 및 상수를 에로 범위를 설명하지만 함수 및 형의 범위도 동일하다.

로컬 범위는 함수나 구문에 의해 정의되는 범위를 말한다. 로컬 범위는 선언된 변수나 상수는 함수나 구문이 있는 실행문 내부에서만 유효한 범위이며 외부에서는 참조할 수 없다.아래 예제는 함수 examFunction()에 상수a를 선언하고 있다. examFunction()함수안이 범위이기 때문에 상수a를 볼 수 있지만 함수 외부는 포함되지 않아 a를 참조할 수 없다.

로컬 범위에서 선언된 변수나 상수는 제한된 범위에서만 참조되지 않기 때문에 의도하지 않은 변경이 일어나기 어렵다.

전역 범위는 모든 함수의 형 선언에도 포함되지 않는 범위를 말한다. 전역 범위에 선언된 변수와 상수는 어디서나 볼수 있다. 아래 예는 전역상수 a를 정의하는 함수 examFunction()내부와 외부에서 참조한다.

전역 범위에 선언된 변수 및 상수는 어디에서나 동일한 이름으로 참조할 수 있기 때문에 의도치 않는 변경이 있을 수 있어 되도록 전역 변수나 상수명을 바로 알수 있는 이름으로 짓도록 하자.

4. Bool형

이번에는 참과 거짓을 따질때 사용하는 Bool형에 대해 알아보자. 어떤 하나의 명제가 참인지 거짓인지를 나타내는 값을 Bool형의 값이라고 한다.

Bool형 상수값

참거짓값을 나타내는 리터럴을 Bool형 상수값에 true와 false로 나타낸다. 참거짓값의 대입 부분의 변수와 상수형이 형주석에 의해 명시되어 있지 않으면 Bool형이 된다.

논리연산

논리는 참거짓값에 대한 연산을 말하며, Bool형은 부정, 논리곱, 논리합이 있으며, Swift연산자의 배치위치로 전치 연산자와 사칙 연산자, 후치 연산자로 구분하며 전치 연산자는 -a, 변수 및 상수사이에 들어가는 사칙연산자 a+b와 같은 형태가 있고 후치연산자는 a!와 같은 변수 및 상수 뒤에 배치한다.

부정

부정은 참거짓값의 진위를 반대로 처리하는 논리를 말한다. Bool형의 부정으로 처리하려면 전치 연산자!로 사용한다. 아래 예제에서는 정수a에 true를 대입하여 상수b에 상수 a의 부정이다를 정의해본다.

논리곱

논리곱으로 주어진 여러가지 참거짓값이 모두 참이면 참이 되는 논리이다. 2개의 Bool형값의 논리적 요구하려면, && 연산자를 사용한다. && 연산자는 삽입하는 사칙연산자이며 양쪽의 Bool형값을 얻는다. 예로 2개의 Bool형 값조합이 교집합으로 정리하여 각 상수 a, b, c, d에 대입한다.

논리합

논리합은 주어진 여러가지 참거짓값 중 적어도 한개가 참이어야 하는 논리이다. 2개의 Bool형값의 논리합은 || 연산자를 사용한다. 아래 예는 2개의 Bool형 값 조합의 논리합을 정리하면 각 상수 a, b, c, d에 대입한다.

5. 수치형

수치를 나타내는 수치형에 대해서 정리해본다. 지금까지의 설명에 정수를 나타내는 Int형을 소개했는데 Swift 언어에서는 Int형 이외에도 다양한 수치 자료형이 있다.

숫자리터럴

수치를 나타내는 리터럴을 숫자리터럴이라고 하며 정수 리터럴, 부동소수점 리터럴등이 있다. 100과 같은 정수 상수값은 정수값을 나타내고 3.14등의 부동소수점 리터럴 값을 나타낸다. 정수 리터럴은 나중에 설명하는 Int형이나 Int64형등의 정수에 대입할 수 있다. 대입시 변수나 상수형이 명시되어 있지 않다면 정수 리터럴은 기본적인 Int형이다.

또한 부동소수점 리터럴도 기본형을 가지고 있고 할당 대상 변수 및 상수의 형아 형주석에 명시되어 있지 않다면  Double형으로 인식된다,

수치형 종류

Swift언어의 숫자는 크게 분류하면 정수형과 부동소수점 2가지로 나눌 수 있다.

정수형은 정수를 나타내는 형이다. 정수형은 유지할 수 있는 값의 비트수등에 따라 다양한 형으로 분류된다. 대표적인 정수는 Int형이다. Int형 비트수는 32비트 플랫폼에서 32비트, 64비트 플랫폼에서 64비트로 나뉜다. 고정 비스트수의 정수는 Int8, Int16, Int32, Int64이 있고, 각각 8비트, 16비트, 32비트, 64비트이다. 각 형의 최소값과 최대값은 아래와 같다.

  • Int8: -128 (최소값) ~ 127 (최대값)
  • Int16: -32,768 ~ 32,767
  • Int32: -2,147,483,648 ~ 2,147,483,647
  • Int64: -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807

정수의 최소값과 최대값은 정적인 속성 min, max를 통해 접근할 수있다. 사용하는 방법은 형명에 .(점)을 붙이고 속성을 추가해서 사용할 수 있다.

부동소수점은 소수를 나타내는 숫자를 말하며,Float형과 Double형이 있고 각각 32비트, 64비트의 고정비트수를 가진다. 부동소수점은 최소값, 최대값을 나타내는 속성은 없고, Float형은 약 10에 38제곱의 값을 나타낼 수 있고 Double형은 약 10에 308제곱값을 나타낸다.부동소수점형은 비트숭에 따라 표현할 수 있는 값의 범위뿐만 아니라, 값의 정밀도도 다른 것에 주의하자. 64비트 Doubel형은 최소 15자리의 정밀도를 가지며, Float형은 최소 6자리의 정밀도를 가진다.

부동소수점 형은 정적인 속성으로 NaN(Not a Number)을 나타내는 nan도 있다. 이는 연산할때 부정한 값이 전달되어 버린 경우 연산을 할 수 없다는 것을 나타낸다. 부정 소수점형에 대한 잘못된 연산을 하게 되면 값은 nan이 된다. 이 때 값이 NaN인지를 체크하는 isNaN속성을 true로 리턴한다.

수치형끼리의 상호변환

Swift언어는 정수형끼리나 부동소수점끼리라고 해도 형이 다르면 할당할 수 없다. 아래 예처럼 Int64형 상수b에 Int형 상수 a의 값을 대입하거나 Double형 정수 d에 Float형 상수 c에 값을 할당할 수 없다.

숫자를 다른 숫자형으로 변환하라면 이니셜라이저를 사용해야 한다. 이니셜라이저는 자료형 값을 만들고 초기화하는 것으로 형명()이라는 형식으로 실행한다. 수치형은 다른 수치형값에서 자신의 형값을 생성하는 이니셜라이저가 준비되어 있기 때문에 변환이 가능하다. 아래 예는 대입할 수없는 값을 이니셜라이저를 사용하여 할당할 수 있는 자료형값으로 변환한다.

이니셜라이저와 함수 ()(괄호)에 입력한 값이 되는 인자를 열거할 수 있고 생성하려는 형보다 정확한 형으로 초기화하면 생성된 형의 정밀도에 맞추기 위해 반올림한다.

수치형 작업

연산자와 수학함수를 사용한 수치작업방법을 정리해본다.

비교연산자는 숫자끼리의 대소관계를 보여준다.

true값을 리턴해주는 조건

  • == : 왼쪽과 오른쪽이 일치할 때
  • != : 좌측과 우측이 일치하지 않는 경우
  • > : 좌측이 우측보다 클때
  • >= : 좌측이 우측보다 크거나 같을 때
  • < : 우측이 좌측보다 클때
  • <= : 우측이 좌측보다 크거나 같을 때

Swift언어의 비교연산자는 비교대상이 되는 두 숫자형이 일치하는 경우에만 사용할 수 있다. 형이 일치하지 않으면 컴파일 오류가 발생한다. 다른 형의 값을 비교하려면 명시적 변환을 하여 일치시킨후 처리해야 한다.

이렇게 처리하는 것이 번거롭지만 자동변환을 허용하면 예상하지 못한 오류가 발생할 수 있기 때문에 형 안전성을 고려한 것이다.

산술연산자는 아래와 같은 형태로 제공한다.

위와 같은 산술연산자도 두 숫자형이 일치해야 사용가능하다.

수치형 변수에 대해서는 이런 연산자와 대입연산자 =를 합친 복합대입연산자를 사용할 수 있다.복합 대입연산자는 산술 및 할당을 동시에 하고 좌측에 산술결과를 대입한다.

Foundation 표준 라이브러리에서는 삼각함수의 고급 함수가 있는데 sin(_:) 삼각함수 및 log(_:)로그함수 및 파이값은 Float형의 정적인 속성인 pi가 있다.

6. String형

이번에는 알파벳이나 한글과 같은 문자열을 나타내는 String형에 대해 알아보자.

문자열 리터럴

문자열을 나타내는 리터럴을 문자열 리터럴이라고 하며 “abcd”나 “대한민국”과 같이 “(큰따옴표)로 문자열을 둘러싸면 문자열 리터럴로 해석한다. 문자열 리터럴에는 문자열을 나타내는 String형과 문자를 나타내는 Character 형이 있다. 문자열 리터럴의 기본형은 String형이다.

문자열 리터럴을 표기할 때 한줄씩 끊어서 넣고 싶다거나 할 때 \(백슬레시)를 넣고 특수문자를 표현할 수 있는데 이것을 이스케이프 시퀀스라고 한다.

  • \n :  줄바꿈
  • \r : 캐리지 리턴
  • \” : 큰 따옴표
  • \’ : 작은 따옴표
  • \\ : 백슬래시
  • \0 : null문자

또한, \()을 사용하면 값을 문자열 리터럴에 포함하여 사용할 수 있다. 이 방법은 평가결과를 문자열리터럴에 포함하여 처리할 수 있다.

물론 숫자결과값만 가능한 것이 아니라, String형 값도 삽입이 가능하다.

String형 개별문자를 표현하기

String형의 개별문자는 Character형으로 표시되고 Character형 묶음은 String.CharacterView형으로 표시된다. 이 형은 String형에 중첩하여 정의되어 있는지를 나타낸다.

Character형은 “a”와 같은 단일문자를 말한다. Character형값은 String형과 동일하게 문자열 리터럴로 표현할 수 있다. 문자열 리터럴의 기본 형은 String형으로 되어 있기 때문에 문자열 리터럴에서 Character형 변수 및 상수를 만들려면 형주석을 붙이는 방법이 있다.

String.CharacterView형은 Character형의 컬렉션을 나타내는 형으로 컬렉션은 데이터집합을 함께 저장하는 데이터구조에서 요소 열거 및 요수수를 계산하는 기능이 있다. String.CharacterView형은 일반적으로 별도로 만드는 것이 아니라 String형의 characters속성에 이미 존재하는 것을 사용한다. 만약 String.CharacterView형에서 Character형 요소를 제거하려면 서브스크립트라는 기능을 이용한다. 서브스크립트는 컬렉션에 인덱스를 통해 요소를 얻고 변경하는 기능이며 컬렉션에 []대괄호로 묶은 인덱스를 지정하여 컬렉션 인덱스라는 형으로 사용한다.startIndex속성, endIndex속성, index(_: offsetBy:)메소드를 사용한다.

endIndex속성은 종료인덱스를 말하는데 마지막 문자의 인덱스가 아니라 그 다음 인덱스라는 것을 기억하자. 즉, endIndex속성값을 그대로 지정하면 런타임 오류가 발생하기 때문에 주의하자.

마지막 문자 인덱스와 n번째 문자의 인덱스를 얻으려면 index(_: offsetBy:)메소드를 사용하여 startIndex속성 및 endIndex속성이 리턴하는 값이다. index(_: offsetBy:)메소드는 컬렉션 .index(원본인덱스, offsetBy: 지정숫자)라는 형식이다.

숫자값의 상호 변환

String형 및 수치형 상호변환에는 이니셜라이저를 사용한다.

String형 값을 Int형으로 변환하는 경우 Int형 이니셜라이저를 사용한다. 문자열은 반드시 숫자형으로 되어 있다고 할 수 없기 때문에 String형에서 수치형으로의 변환은 실패할 수 있다. 따라서 Int형 이니셜라이저는 nil이 될 수 있는 Optional<Int>형 값을 리턴한다. 수치로 변환할 수 없는 문자열을 변환하면 결과는 nil이 된다.

String 및 Character형 조작하기

Swift 언어는 기본적으로 문자열은 String형으로 취급하고 문자는 Character형으로 취급한다.

비교는 ==연산자를 사용한다. 비교시 주의해야 할 점은 암시적 변환은 존재하지 않기 때문에 어느쪽이든 한쪽 형을 맞춰야 한다.

다음 String형끼리의 결헙에 +연산자를 사용할 수 있다. 그외 append(_:)메소드를 이용하여 같은 형끼리 결합할 수 있다.

단, 표준 라이브러리는 대소문자를 구별하지 않고 비교하거나 무낮열 탐색등의 기능은 준비되어 있지 않기 때문에 Foundation 코어 라이브러리를 사용해야 한다.

두문자열 간의 순서비교부분에서는 compare(_: option:)메소드로 2개의 문자열 사이 순서를 확인한다. option에 .caseInsensitive을 선언하여 대소문자를 구별하지 않고 값을 얻고 있다. 문자열 검색 부분에서는 range(of:)메소드에서 “대한민국” 문자열에 “대한”이 어떤 범위에 포함되어 있는지를 확인해준다.

7. Array<Element>형

배열을 나타내는 Array<Element>형에 대해 알아보자. 배열은 순서를 가진 컬렉션으로 Element에 구체적인 형을 선언하여 Array<String>형이나 Array<Int>형 형태로 구현한다. 이때 <>내에 플레이스홀더형을 가진 것을 제네릭형이라고 말한다. 또한 Array<Element>형은 [Element]라는 구문형태가 준비되어 있다.

배열리터럴

Array<Element>형을 [1, 2, 3, 4, 5]와 같은 배열리터럴을 사용하여 표현할 수 있다. 배열 상수값은 []안에 쉽표(,)로 구분하여 열거한다.

배열 리터럴이 포함요소형에서 Array<Element>형의 플레이스홀더형인 Element를 추론한다. 예로 배열리터럴은 String요소만 가지고 있는 경우 [String]형으로 추론한다.

단, 빈 배열리터럴의 경우, 요소가 존재하지 않는 경우 추론을 할수 없다. 따라서 빈 배열리터럴 형주석을 추가하여 형을 명시하는 것이 좋다.

Element형의 값을 요소로 사용할 수 있다. 예로 [Int]형은 Int형 값을 사용할 수 있고 [String]형은 String형값을 사용할 수 있다

Element형에는 어떤 형이라도 적용할 수 있다. 예로, Element형에 [Int]형을 적용하여 Int형 배열의 벼을을 나타내는 [Int]형을 나타낼수 있다. [[Int]]형처럼 배열을 요소로 가지는 배열을 2차원 배열이라고 한다.

요소형은 다른 형값을 포함하면 컴파일 오류가 발생한다. 예로, [Int]형에 String값 “a”를 포함시키는 경우 오류가 발생한다.

Array<Element>형 조작하기

Array<Element>형 요소에 접근하려면 서브스크립트를 사용한다. 서브스크립트의 인수는 요소 인덱스를 나타내는 Int형 값을 사용한다. 첫번째 요소 인덱스는 0에서 1, 2순서대로 이어진다. 인덱스가 범위에서 벗어나거나 하면 오류가 발생한다.

Array<Element>형 값에 대한 요소의 추가, 변경, 결합, 삭제를 할 수 있는데 기존 요소를 변경하려면 변경시 요소 인덱스를 서브스크립트의 인자로 대입 연산자 =를 사용하여 새 값을 설정한다.

요소 끝에 추가하려면 append(_:)메소드를 사용한다. Array<Element>형의 append(_:)메소드는 Element형값을 인수로 얻는다. 예로  [Int]형 변수 i에 Int형 5를 추가한다.

임의의 위치에 요소를 추가하려면 insert(_:at:)메소드를 사용한다. insert(_:at:)메소드는 추가요소로 추가하는 위치의 인덱스를 인수로 얻는다.

+연산자 형이 일치하는 Array<Element>형을 결합할 수 있다.

요소제거는 임의의 인덱스 요소를 삭제하는 remove(at:)메소드와 마지막 요소를 삭제하는 removeLast() 메소드, 모든 요소를 삭제하는 removeAll()메소드가 있다.

8. Dictionary<Key, Value>형

사전을 나타내는 Dictionary<Key, Value>형을 알아보자. 사전은 키와 값을 쌍으로 가진 컬렉션이며 키를 원래 값에 접근하기 위한 용도로 사용된다. 키와 값의 쌍 사이에 순서는 상관없다. 키는 접근 대상의 구분을 사용되기 떄문에 고유하며 값은 중복되어도 문제가 없다.

Array<Element>형과 마찬가지로 Dictionary<Key, Value>형의 Key와  Value플레이스홀더 형이 있다. 실제로 Dictionary<String, Int>는 [String:Int]로 표시한다.

사전 리터럴

Dictionary<Key, Value>형은 [“key1”: “value1”, “key2”: “value2”]와 같은 사전 리터럴로 표현한다. 예로 키가 String형 값을 Int형 사전 리터럴은 [String: Int]형과 추론된다.  사전 리터럴은 키와 값은 :으로 연결하며 페어링한 요소를 ,(콤마)로 구분해서 []에 열거한다.

사전 리터럴은 Dictionary<Key, Value>형의 Key형은 키형에서 Value형은 값형에서 유추된다. 예로, 키가 String형값을 Int형 사전리터럴은 [String: Int]형 추론을 한다. 요소가 하나도 존재하지 않거나 키와 값에 여러가지 형이 혼재하는 경우는 사전 리터럴 형을 유추하지 못할 수 없다.

또한, 요소가 하나도 존재하지 않거나 키 및 값에 여러가지 형이 존재하는 경우 사전 리터럴 형을 유추하지 못할 수 있고 이런 경우 변수 및 상수형주석을 사용하여 형을 명시해야 한다. 아래 예는 빈사전 리터럴 [:]의 할당정보에 대해 [String:Int]형의 형주석을 추가하여 형을 결정한다.

Dictionary<Key: Hashable, Value>형이며 Key형에 제한되어 있다. : Hashable부분은 형식제약조건이며 Key형에 Hashable프로토콜을 지키는 것으로 제한한다.

Hashable프로토콜은 그 형의 값을 바탕으로 해시값이 계산가능한지를 나타내는 프로토콜로 해시값은 원래값에서 특정 알고리즘에서 산출되는 Int형값이다. Key형이 Hashable프로토콜을 지킬 필요가 있는 해시값이 키의 고유성을 필수로 한다.

Hashable프르토콜의 형은 String형이나 Int형이 있고 예로 String형값 “a”의 hashValue은 값이 있고 Int형값 1, hasValue는 1이 되고 있다. 반대로 Hashable 프로토콜을 지키지않는 형은 Array<Element>형등이 있다. Key형과 달리 Value형은 형제한이 없다. 따라서 Value형에 [Int]형을 적용하여 [String: [Int]]형으로 하거나 [String: Int]형으로 처리할 수 있다.

Key형과는 다른 형의 키와 Value형은 다른 형의 값을 설정하면 컴파일 오류가 발생한다.

Dictionary<Key, Value>형 조작하기

Dictionary<Key, Value>형의 값에 접근하려면 서브스크립트를 사용한다. 서브스크립트 인수는 Key형 값으로 지정한다. 예로 [String: Int]형의 값에 접근할 경우, 아래와 같이 처리한다.

Dictionary<Key, Value>형은 Array<Element>형과 다르게 서비스크립트에서 값이 없는 경우에도 런타임 오류가 발생하지 않는다. 대신 서비스크립트가 리턴하는 값은 nil을 확인하고 처리하기 위해 Optional<Value>형값을 리턴하기 위해 사용된 값이 nil이 아닌 것을 확인하고 값을 사용해야 한다.

Dictionary<Key, Value>형 값의 변경, 추가, 삭제도 서브스크립트를 사용한다. 서브스크립트 인수 Key형 값을 지정하고 대입 연산자 =를 사용하여 새 값을 지정한다. 서비스크립트에서 지정한 키가 이미 존재하는 경우 값 변경이 되고 키가 존재하지 않으면 신규 추가가 되고 새값에 nil을 설정하면 값이 삭제된다.

9. 범위형

범위형은 Range<Bound>형, CountableRange<Bound>형, ClosedRange<Bound>형, CountableClosedRange<Bound>형등이 있다. 이들 종류에 따라 다양하게 조합해서 사용할 수 있고, 계산 가능한 범위는 Int형 범위와 같이 범위에 포함되는 값도 정해지는 거이다. 계산이 불가능한 범위는 Double형 범위와 같이 범위에 포함되는 값수가 정해지지 않는다. 실제로 Range<Float>형이나 CountableClosedRange<Int>형처럼 Bound형에 구체적인 형을 지정해서 사용한다.

범위연산자

범위연산자는 범위형 값은 범위 연산자를 이용하여 생성한다. 범위연산자는 반개구간을 만들 때 ..< 연산자와 닫힌 간격을 만드는 … 연산자 두가지를 사용한다.

반개구간은 범위의 시작점 또는 끝점 중 하나만 포함하는 구간이다.

범위형 ~ 구간

  • Range<Bound> ~ 반개구간 (계산 불가능)
  • CountableRange<Bound> ~ 반개구간 (계산 가능)
  • ClosedRange<Bound> ~ 닫힌구간 (계산 불가능)
  • CountableClosedRange<Bound> ~ 닫힌구간(계산 가능)

Swift언에서 오른쪽 열린 구간은 존재하지 않기 때문에 앞으로는 왼쪽 열린 구간의 반개구간을 사용한다.

..< 연산자를 사용하여 반개구간을 나타내는 Range<Bound>형과 CountableRange<Bound>형 값을 생성할 수 있다. ..< 연산자는 삽입한 연산자는 좌측에 범위의 시작값, 오른쪽에 범위 종료값을 지정한다. 예로 Double형 1.0이상 3.5미만의 구간을 나타내는 Range<Double>형 값을 만들기 위해 1.0 ..< 4.5처럼 선언한다.

..< 연산자 양쪽이 Int형인 경우 계산가능한 CountableRange<Bound>형 값이 생성된다. CountableRange<Bound>형 요소를 열거하기 위한 프로토콜로 Sequence프로토콜을 지키기 때문에 for-in문을 사용하여 해당 요소에 순차적으로 접근할 수 있다. 반개구간이기 때문에 1 ..< 5는 5가 범위에 포함되지 않는 것에 주의하자.

..< 연산자 양쪽이 Int형이라고 해도 형주석을 사용하면 Range<Bound>형 값도 생성할 수 있다.

한편, Double형 범위는 계산불가능하기 때문에, 형주석을 사용해도 CountableRange<Bound>형 값을 생성할 수 없다.

… 연산자는 닫힌 간격을 범위의 시작점과 끝점을 포함한 구간으로 ClosedRange<Bound>형과 CountableClosedRange<Bound>형 값을 생성할 수 있다. … 연산자도 삽입시 연산자는 좌측에 범위의 시작값, 오른쪽에 범위 종료값을 지정한다. 예로 Double형 1.0이상 4.5이하의 범위를 나타내는 ClosedRange<Double>형 값을 생성하려면 1.0 … 4.5로 선언한다. … 연산자 양쪽이 Int형인 경우 계산 가능한 CountableClosedRange<Bound>형값이 생성된다. Sequence프로토콜을 지키기 때문에 for-in문을 사용하여 해당 요소에 순차적으로 접근할 수 있다. 닫힌 간격이기 때문에 1 … 5일 경우 5가 포함된다.

… 연산자 양쪽이 Int형이라고 해도, 형주석을 사용하면 ClosedRange<Bound>형 값도 생성할 수 있다.

한편, Double형 범위는 계산이 불가능하기 때문에 형주석을 사용해도 CountableClosedRange<Bound>형 값을 생성할 수 없다.

또한, ..< 연산자와 … 연산자에 의해 범위형 값을 생성하는 경우, Bound형은 연산자 양쪽 값형에서 유추한다. 예로 양쪽갑 형이 Int형이면 Bound형은 Int형이 되고, Double형이면 Bound형도 Double형이다.

정수 f에 Range<Float>형에 형주석을 추가하여 ..< 연산자결과형을 Range<Float>형으로 선언한다.

Bound형은 대소관계를 비교하기 위한 프로토콜로 Comparable프로토콜을 지켜 다양한 형을 적용할 수 있지만 두가지 형은 같아야 한다. 시작값이 Int형이면 끝값도 Int형이어야 한다.

범위형 사용하기

범위형은 범위 끝값을 리턴하는 속성 lowerBound(범위 시작값 리턴)와 upperBound(범위 끝값 리턴)가 준비되어 있다.

만약, 형범위에 특정값이 들어있는지를 확인하려면 contains(_:)메소드를 사용한다. 결과는 Bool형값을 리턴해준다.

10. Optional<Wrapped>형

Optional<Wrapped>형은 값이 있는지 비어 있는지를 나타내는 형이다. Swift 언어의 변수 및 상수는 기본적으로  nil을 허용하지 않지만 nil허용이 필요할 경우 Optional<Wrapped>형을 사용한다. 이떄 Wrapped형을 실제로는 Optional<Int>형처럼 구체적인 형을 지정해서 사용한다. Wrapped 형에는 어떤 형이라도 지정할 수 있다.

Optional<Wrapped>형의 2가지 케이스

Optional<Wrapped>형은 Wrapped형의 값이 있는지, 없는지 2가지를 나타낸다.

열거형은 여러가지 식별자를 요약한 형으로 각각의 식별자를 케이스라고 한다. Optional<Wrapped>형은 .none, .some 두가지 케이스를 정의하고 있다. .none은 값이 없는 경우, 즉, nil과 동일하고 .some은 값이 존재하는 경우이다.

Optional<Wrapped>형의 .none과 nil리터럴이 매핑되어 있기 때문에 값이 .none이면 nil이라고 하기도 한다.

.some값을 생성하는 경우 해당 값에서 형추론을 할 수 있는데 이를 이용하면 아래와 같이 작성할 수 있다.

한편, .none을 생성하는 경우 형 추론할 수 있는 값이 없기 때문에 그대로 <Wrapped>를 생략할 수 없다.  .none생성에서 <Wrapped>을 생략하려면 형주석을 대입하는 쪽의 변수와 상수형을 지정하는 방법에서 형을 결정해야 한다.

.some생성은 값에서 형추론이 가능하지만, .none생성은 형을 명시해야 한다.

Optional<Wrapped>형 값 생성하기

열거형 케이스로 만드는 것보다 간단하게 할 수 있기 때문에 편리하다.

또한 Optional<Wrapped>형의 .none은 nil리터럴을 대입하여 생성할 수 있다.

단, nil리터럴은 기본형이 존재하지 않기 때문에, nil리터럴 대입쪽 변수 및 상수형은 형주석등을 우선적으로 해야 한다.

또한 .some값을 인수로 받아 초기화 Optional(_:)를 사용하여 생성이 가능하며 이니셜라이저에 전달된 인수에서 형추론된다.

변수 및 상수형에 형주석등을 통해 Optional<Wrapped>형인 경우 Wrapped형값을 대입하여 .some을 만들 수 있다.

Optional<Wrapped>형 풀기 (값얻기)

값을 가지고 있지 않은 상태도 고려해야 하기 때문에 Wrapped형 변수 및 상수처럼 취급하기 어렵다.

Optional<Wrapped>형값을 가지는 Wrapped형값에 대한 작업을 하려면 Optional<Wrapped>형값에서 Wrapped형값을 추출해야 한다.

  • 선택적 바인딩
  • ?? 연산자
  • 강제풀기(Unwrap)

선택적 바인딩(Optional Binding)은 조건분기문이나 반복문 조건에 Optional<Wrapped>형 값을 전달값의 유무에 따라 처리를 전환하는 값이 존재하면 Wrapped형 추출방법이다. 선택적바인딩은 if-let문을 이용해서 처리한다.

아래 예는 a에 값이 존재하기 때문에 b에 값을 할당한 if문을 실행문이 실행된다.

??연산자는 Optional<Wrapped>형에 값이 없으면 기본값을 지정하려면 중간값 연산자??를 사용한다. ??연산자는 왼쪽 Optional<Wrapped>형값, 오른쪽에는 Wrapped형값을 얻는다.

강제풀기(forced unwrapping)은 !연산자에 의해 Optional<Wrapped>형에서 Wrapped형의 값을 추출하는 방법이다. 강제풀기를 하려면  값을 변환하는 식끝에 !연산자를 추가한다.

주의해야 할 점은 값 존재가 상당히 명백한 부분이나 값이 존재하지 않으면 프로그램을 종료하고 싶은 부분이 아닌 경우에는 강제풀기를 사용하는 것을 권장하지 않는다.

선택적 체인(Optional Chaining)

선택적 체인은 풀기를 하지 않고 Wrapped형 속성이나 메소드 접근하는 방법이다. Optional<Wrapped>형에서 Wrapped형 속성에 접근하려면 일단 선택적 바인딩으로 랩핑해야 한다.

램핑하지 않고 Wrapped형 속성이나 메소드에 접근할 수 있는 방법이 있다.

다음 예는 선택적 체인을 통해 contains(_:)메소드를 호출하여 범위에 지정값이 포함되는지를 체크할 수 있다.

선택한 체인은 Optional<Wrapped>형 변수 및 상수가 nil이 있으면 이후 작성된 속성이나 메소드에 접근하지 않고 nil을 리턴한다.

ImplicityUnwrappedOptional<Wrapped>형

값이 있는지 빈값인지를 nil을 허용하는 형식은 Optional<Wrapped>형 이외에 ImplicityUnwrappedOptional<Wrapped>형이 있다. ImplicityUnwrappedOptional<Wrapped>형값에 접근시 암시적으로 강제풀기를 하기 위한 값이 들어 있는지 없는지를 허용하면서 Wrapped형과 같게 사용할 수 있다.

11. Any형

모든 형을 나타내는 Any형에 대해서 알아보자. Any형은 모든 형 암묵적으로 별도 프로토콜이 구현되어 있다. Any형의 변수 및 상수는 어떤 형도 대입한다.

Any형은 지금까지의 형처럼 리터럴이나 이니셜라이저에 의한 값을 생성하는 것은 아니다.

Any형 변수 및 상수에 대입하면 원래 형의 정보가 손실되어 버리기 때문에 원래 형이 가능했던 조작을 할 수 없을 수 있다.

이런 Any형에 의한 대입값에 대한 조작이 어려워지기 때문에 가능한 Any형 사용을 피하는 것을 추천한다.

12. 튜플형

여러가지 형을 하나의 형으로 취급 처리할 수 있는 것이 튜플형이다. 튜플형을 정의하려면 요소가 되는 형을 ()으로 구분하여 (형1, 형2, 형3) 형태로 열거한다. 튜플형의 요소에는 어떤 형으로도 지정할 수 있고 원소갯수에 제한없다.

튜플형 값은 튜플이며 튜플을 생성하려면 요소가 되는 값을 ()에 구분하여 (요소1, 요소2, 요소3)처럼 열거한다.

요소 접근하기

튜플 요소에 접근하려면 색인 사용 및 요소명 접근, 대입접근 등이 있다.

색인사용은 튜플 요소는 인덱스를 통해 접근할 수 있다. 변수 및 상수를 지정하고 변수명 인덱스라는 형식으로 접근한다.

요소명에 접근하려면 튜플을 정이할 때 각 요소명을 붙여 해당 이름을 통해 요소를 접근할 수있다. 요소명을 정의하려면 튜플요소 앞에 요소명:을 추가하여 (요소명1: 요소1, 요소명2: 요소2)형태로 작성한다.

대입접근은 튜플에 요소 몇개가 있는 변수 및 상수를 ()내에서 구분하여 열거한 것도 할당할 수 있다.

또한, 여러개의 변수 및 상수를 ()내에 동시에 선언할 수 있다.

Void형

요소 형이 0개의 튜플형을 Void형이라고 하며 값이 존재하지 않는 것이다.

nil리터럴도 값이 존재하는 것을 나타내는데 사용하지만 이것은 값 유무 중 무를 나타내는 것이다. 한편 Void형은 값이 존재하는장소가 아님을 나타낸다. Void형은 이런 성질은 함수 리턴값이 없는 것을 나타내는 용도로 사용된다.

13. 형변환

형변환은 변수 및 상수형보다 범용적인 형이나 구체적인 형으로 취급하는 경우이다.

형 판정하기

값형이 특정형인지 연부를 확인하려면 is 연산자를 사용한다. is연산자는 좌측에 검증할 식을 넣고 우측에 검증하려는 형을 넣는 연산자이다. 결과는 Bool형값을 리턴한다.

상위형 캐스팅

상위형 케스팅은 연산자 as를 사용하고 좌측값을 우측형값으로 취급한다.

하위형 캐스팅

하위형 캐스팅은 연산자 as?를 사용한다.

 

 

Facebook Comments

You may be interested

페이지 로딩 위치에 따른 사용자 시선 유도
Swift 3.0
shares3 views
Swift 3.0
shares3 views

페이지 로딩 위치에 따른 사용자 시선 유도

MJ Kim - 4월 29, 2017

로딩되는 표시를 표시할 위치를 조금 고민해보면서 사용자경험(UX)를 개선하기 위함을 고려해서 정리해 본다. 로딩을 생각해보면 대부분 한가운데에 표시하면 된다고 생각하지만, Twitter…

iOS와 Android UX의 차이점
Swift 3.0
shares2 views
Swift 3.0
shares2 views

iOS와 Android UX의 차이점

MJ Kim - 4월 29, 2017

최근 필자가 iOS와 Android를 같이 개발하다보니 UX의 차이점을 기억하고자 정리해본다.  이를 정리하는 이유는 운영체제별로 차이점을 이해하고 그 차이점을 극복하기 위함이다.…

모바일 앱 아키텍처
Swift
shares26 views
Swift
shares26 views

모바일 앱 아키텍처

MJ Kim - 4월 22, 2017

이 내용은 나름대로 개발해본 내용을 토대로 정리해본 모바일 앱 아키텍처에 대한 내용이다. 이를 정리한 이유는 오래된 아키텍처부터 최근 아키텍처까지 정리해보고…