Swift_문법.1

week1. 기본 연산자 - 콜렉션 타입

1. 기본 연산자 (Basic Operators)

-Swift에서는 산술연산자(+, -, /, %), 논리 연산자(&&, ||), 그리고 C에서 지원하지 않는 범위 연산자(a..<b, a...b, 값의 범위 지정 가능)를 지원

-단항unary 연산자: 하나의 대상에 앞뒤에 바로 붙여 사용하는 연산자.
ex) -a, !b, c!
-이항binary 연산자: 두 대상 사이에 위치하는 연산자.
ex) 2 + 3
-삼항ternary 연산자: a ? b : c (Swift에서 삼항 연산자는 이 연산자 하나!)

-할당연산자(Assignment Operator) - 값을 초기화 시키거나 변경 (상수, 변수 모두에서 사용 가능)
ex) ```
let b = 10
var a = 5
a = b //a값은 10

 >다른 언어와 달리 **할당 연산자는 값을 반환하지 않음!!**
 따라서,,

if x = y {
... //x=y는 값을 반환하지 않으므로 error
}


> 할당 연산자가 값을 반환하지 않는 이유 : 동등비교연산자(==)를 사용해야 하는 곳에 할당연산자(=)가 실수로 사용되는 것을 막기 위함

let: 선언 시 처음 입력된 데이터만 저장하게 됨
var: 선언 시 처음 입력된 데이터 이후 추가로 입력 가능하며 마지막에 입력된 데이터가 최종 데이터가 됨

ex)```
let number1 : Int = 10
number1 = 0
	// number1에 입력된 데이터는 변하지 Xx,,
var number2 : Int = 20
number2 = 2
number2 = 30
	// number2는 마지막에 입력된 데이터가 입력됨

-사칙 연산자(Arithmetic Operators): +, -, *, / (4가지 표준 사칙 연산자)

>사칙 연산의 값이 오버플로우 되는 것을 허용하지 Xx,, -> 허용하고 싶으면,, 오버플로우 연산자 이용
>문자열 덧셈 가능
	ex) "hello, " + "world" //hello, world
    

-나머지 연산자(Remainder Operator): %
-단항 음수 연산자(Unary Minus Operator): -
	ex) ```
let three = 3
let minusThree = -three //minusThree는 -3
let plusThree = -minusThree //plusThree는 3 혹은 "minus minus 3"
-단항 양수 연산자(Unary Plus Operator): +

-합성 할당 연산자(Compound Assignment Operators)
ex) ```
var a = 1
a += 2 // a는 3

>**합성 할당 연산자는 값을 반환하지 않음!!**
ex) let b = a+=2  //error

-비교 연산자(Comparison Operators):
a==b, a!=b, a>b, a<b, a>=b, a<=b

>객체 비교를 위해 식별 연산자 ===과 !== 제공,,
>각 비교연산은 true 혹은 false 값을 반환

>같은 타입의 값을 갖는 두 개의 튜플을 비교할 수 O, 비교 방향: 왼쪽 -> 오른쪽, 한번에 한 개의 값만 비교
ex) ```
(1, "zebra") < (2, "apple") 
		//true, 1이 2보다 작고;(>이 시점에 튜플의 비교 종료) zebra가 apple은 비교하지 X
(3, "apple") < (3, "bird")
	    //true, 3이 같고;(>비교하는 튜플이 같기 때문에 다음 순서로 넘어감) apple은 bird보다 작음
("blue", false) < ("purple", true)
		//error, Boolean 값은 < 연산자로 비교할 수 없기 때문에

Swift 표준 라이브러리에서는 7개 요소 미만을 갖는 튜플만 비교할 수 있음

-삼항 조건 연산자(Ternary Conditional Operator): question ? answer1 : answer2 (question 조건이 참이면 answer1, 거짓이면 answer2가 실행)

-Nil 병합 연산자(Nil-Coalescing Operator): a ?? b

>옵셔널 a를 벗겨서unwraps 만약 a가 nil인 경우 b를 반환(a가 옵셔널, b가 a가 nil일 때 할당되는 값)

nil: 값이 없음 (다른 언어에서는 NULL로 사용)
옵셔널 타입만 nil 반환 가능(일반 자료형은 불가)
옵셔널은 별도로 존재 Xx, 기본 자료형에 대응하는 옵셔널 타입(ex_ 옵셔널 Int 타입, 옵셔널 String 타입)
-> nil이거나 nil이 아닌 값만 가질 수 O(nil/ optional("hi"))
자료형 뒤에 ?를 붙여서 일반 자료형 -> 옵셔널 타입으로 변경 가능
ex) var optionalString: String? = "swift"
// 이렇게 일반 값 할당하면 자동으로 옵셔널 객체 내부에 값이 대입된다. 값을 할당하지 않으면 자동으로 nil로 초기화.

>다음 코드의 축약형
```

a != nil ? a! : b

ex)
let defaultValue: Int = 1 // 1
var someOptionalInt: Int? // 초기화가 이루어지지 않았기 때문에 nil
var myNum = someOptionalInt ?? defaultValue // 1
/*
myNum 변수에 someOptionalInt 옵셔널을 할당하려고 시도한다.
but someOptionalInt는 nil.
그렇기 때문에, defaultValue가 할당되어 myNum은 1
*/

someOptionalInt = 3 // Optional(3)
var myNum2 = someOptionalInt ?? defaultValue // 3
/*
myNum2 변수에 someOptionalInt 옵셔널을 할당하려고 시도한다.
현재 someOptionalInt의 값은 Optional(3)이므로 nil이 Xx 
따라서 myNum2에는 someOptionalInt의 값이 할당되는데,
이 때 Optional이 일반 값으로 가공된다. 
따라서 myNum2의 값은 3
*/

nil 병합연산자 - 옵셔널 값이 nil이 아니라면, 해당 옵셔널 값을 일반 값으로 가공시킴
-> 기본값을 할당하기 때문에 사용하기 편리 & 안전성 보장

-범위 연산자(Range Operators)

>닫힌 범위 연산자(Closed Range Operator): (a..b)의 형태로 범위의 시작과 끝이 있는 연산자
ex) ```
for index in 1...5 {
print("\(index) times 5 is \(index * 5)")
}
// 1 times 5 is 5
// 2 times 5 is 10
// 3 times 5 is 15
// 4 times 5 is 20
// 5 times 5 is 25

	>반 닫힌 범위 연산자(Half-Open Range Operator): (a..<b)의 형태로 a부터 b보다 작을 때까지의 범위를 가짐, 즉 a부터 b-1까지 값을 가짐 (배열 다룰 때 유용)
    ex) ```
let names = ["Anna", "Alex", "Brian", "Jack"]
let count = names.count
for i in 0..<count {
	printf("Person \(i+1) is called \(names[i])")
}
// Person 1 is called Anna
// Person 2 is called Alex
// Person 3 is called Brian
// Person 4 is called Jack
>단방향 범위(One-Side Ranges): [a..][..a]의 형태로 범위의 시작 혹은 끝만 지정해 사용하는 범위 연산자 - 지정한 시작 값 혹은 끝 값은 범위에 포함
ex) 특정 값을 포함하는지 여부 확인
```
let range = ...5
range.contains(7)   // false
range.contains(4)   // true
range.contains(-1)  // true
```

-논리 연산자(Logical Operators): 논리 부정 NOT(!a), 논리 곱 AND(a && b), 논리 합 OR(a || b)

ex) 두 개 이상의 논리 연산자 조합 예시
```
if enteredDoorCode && passedRetinaScan || hasDoorKey || knowsOverridePassword {
print("Welcome!")
} 
else {
print("ACCESS DENIED")
}
// Prints "Welcome!"
>논리 연산자 &&와 ||는 왼쪽의 표현 우선시함.

-명시적 괄호(Explicit Parentheses): 명시적으로 괄호를 사용하여 계산 순서 지정 > 가독성!

2. 문자열과 문자(Strings and Characters)

NSString의 메소드를 String에서 캐스팅 없이 사용 가능

-문자열 리터럴
ex) ```
let something = "Some string literal value"

 	>여러줄 문자열 리터럴: """로 여러줄 묶어서 사용 가능
    >백슬래쉬(\)를 사용하여 줄바꿈 가능
    >문자열의 시작과 끝에 빈줄 넣을 수 있다, 들여쓰기 가능
    >특수문자: \0, \,\t,\n,\r,\",\'
     ++\u{n}, n은 1-8자리 십진수 형태로 구성된 유니코드
     ex) let dollaSign = "\u{24}"           	 // $, 유니코트 U+0024

-빈 문자열 초기화

var emtpryString = ""
var anotherEmptyString = String()
	//두 변수의 문자열 값은 같다
>문자열이 비어있는지 여부를 확인하기 위해서 isEmpty 프로퍼티 이용.
```
if emptySting.isEmpty {
	print("Nothing to see here")
}

-문자열 수정
ex) ```
var variableString = "Horse"
variableString += " and carriage"
// variableString = Horse and carriage
let constantString = "Highlander"
constantString += " and another Highlander"
// 문자열 상수(let)로 선언돼 있어 에러발생!

-값 타입 문자열: String은 값 타입(value type) (Character 요소로 구성되어 있음)

>String이 다른 함수 혹은 메소드로부터 샏성되면 String 값이 할당될 때, 이전 String의 레퍼런스를 할당하는 것이 아니라 값을 복사해서 생성
(다른 메소드에서 할당 받은 문자열은 그 문자열을 수정해도 원본 문자열이 변하지 Xx)

-문자: 문자열의 개별 문자를 for-in loop를 사용해 접근할 수 O
ex) ```
for character in "Dog!"{
print(character)
}
//D
//o
//g
//!

	>문자 상수 선언
    ex) ```
let exclamationMark: Character = "!"
>문자 배열 이용 -> 문자열의 초기화 메소드에 인자로 넣어 문자열을 생성할 수 O
ex) ```

let catWords: [Character] = ["C", "a", "t", "!"]
let catString = String(catCharacters)
print(catString)
//Cat!

-문자열과 문자의 결합(Combining Strings) :
append() 또는 + 연산자로 문자열 결합 가능

>"기존문자열".append("추가할 문자열")

ex1)```
let string1 = "hello"
let string2 = " there"
var welcome = string1 + string2
//welcome : "hello there"
//문자열 간 덧셈 가능

ex2) ```
let exclamationMark: Character = "!"
welcome.append(exclamationMark)
// welcome : "hello there!"

```

-문자열 삽입(String Interpolations) :
큰따옴표 중간에 '\ ()'를 사용하여 아무 표현식이나 변수를 삽입하여 문자열로 바꿀 수 O

>객체가 들어가면->해당 객체의 description 값 삽입 / 계산식이 들어가면->계산된 결과값 삽입

ex) ```

let name = "Rosa"
let personalizeGreeting = "Welcom, (name)!"

let mutiplier = 3
let message = "\ (multiplier) times 2.5 is \ (Double(multiplier) * 2.5)"
//message : "3 times 2.5 is 7.5"


	>특정 문자를 포함하고 있는지 여부: contains(_:)를 사용, Character형 문자, String문자열 모두 O, 결과값은 Bool 형
    ex)```
let str = "Apple"
print(str.contains("A")) // true
print(str.contains("a")) // false

-유니코드 : 전 세계의 모든 문자를 컴퓨터에서 일관되게 표현하고 다룰 수 있도록 설계된 국제 표준

>Swift의 네이티브 문자열 타입은 유니코드 스칼라 값으로 만들어짐
>유니코드는 21비트의 숫자로 구성되어 있음

>문자 세기: 문자열의 문자의 숫자를 세기 위해서 count 프로퍼티 이용
ex)```

let string = ""
if string.count == 0{
print("There are no string")
} //There are no string

	>문자열의 접근과 수정: 문자열 메소드 혹은 프로퍼티를 이용하거나 서브스크립트(subscript) 문법 이용

-문자열 인덱스: startIndex, endIndex, index(before:), index(after:), index(_:offsetBy:) 메소드 등 -> 특정 문자에 접근

>startIndex : 문자열의 시작 요소 인덱스를 가리킴
>endIndex : 문자열의 마지막 요소 인덱스 다음을 가리킴
>index(before: _String.Index_) : 인자로 들어온 인덱스 1칸 앞을 가리킴
>index(after: _String.Index_) : 인자로 들어온 인덱스 1칸 뒤를 가리킴
>index(_String.Index_, offsetBy: _String.InexDistance_) : 인자로 들어온 인덱스와 offsetBy 차이만큼 떨어진 곳을 가리킴
>firstIndex(of: _Character_), lastIndex(of: _Character_) : 인자로 들어온 문자가 몇번째 인덱스에 있는지 (Optional)

ex) ```

let str = "ABCDE"
str[str.startIndex] //A
str[str.index(after: str.startIndex)] //B
str[str.index(before: str.endIndex)] //E

str[str.index(str.startIndex, offsetBy: 2] //c
str[str.index(str.endIndex, offsetBy: -2 //D

> 이렇게 접근한 요소는 모두 Character형!!

	ex)```
    //특정 문자의 인덱스 알기
	let str = "Hello World"
	if let index = str.firstIndex(of: "o") {
    	print(index) //4
    }
    if let index = str.lastIndex(of: "o") {
    	print(index) //7 (두번째 "o")
    }
-문자의 삽입과 삭제: insert(:at:), insert(contentsOf:at:), remove(at:), removeSubrange(:)
	ex) ```
var welcome = "hello"
welcome.insert("!", at: welcome.endIndex)
		// welcome : hello!
welcome.insert(contentsOf: " there", at: welcome.index(before: welcome.endIndex))
		// welcome : hello there!
        
welcome.remove(at: welcome.index(before: welcome.endIndex))
		// welcome : hello there
        
let range =  welcome.index(welcome.endIndex, offsetBy: -6)..<welcome.endIndex
welcome.removeSubrange(range)
		// welcome : hello

-부분문자열: prefix(_:)와 같은 서브스크립트 메소드 이용, ->이때 얻은 부분 문자열은 문자열(String) 인스턴스 Xx,, 부분문자열(SubString) 인스턴스
	>단순 참조만 이루어 질 경우 -> 성능 최적화를 위해 SubString 그대로 사용 추천, 부분 문자열을 변형하는 등 기타 활용 및 오랜기간 사용하려면 문자열 인스턴스로 바꿔서 사용하는 것이 Good!
    ```
    let greeting = "Hello, World!"
    let index = greeting.index(of: ",") ?? greeting.endIndex
    let beginning = greeting[..<index]
    	// beginning : Hello
        
    //SubString인 beginning을 String으로 변환
    let newString = String(beginning)
> SubString은 원본 String의 메모리를 참조하여 사용
 	-> SubString을 계속 이용하는 이상 원본 String이 계속 메모리에 남아 있게 됨
    -> 효율이,,,,,그닥,,
>String과 SubString 모두 문자 조작에 필요한 메소드들 공통으로 사용 가능

-접두어 / 접미어 확인: prifix(:), suffix(:)
->반환형은 SubString

ex)```
let str = "aBcDeF"
// 접두어 (앞에서부터 몇 글자) / 접미어 (뒤에서부터 몇 글자)
print(str.prefix(3)) //aBc
print(str.suffix(4)) //cDeF

-접두사 / 접미사 비교: hasPrefix(:), hasSuffix(:)
->반환형은 Bool

	ex)```
	let romeoAndJuliet = [
	    "Act 1 Scene 1: Verona, A public place",
	    "Act 1 Scene 2: Capulet's mansion",
	    "Act 1 Scene 3: A room in Capulet's mansion",
	    "Act 1 Scene 4: A street outside Capulet's mansion",
	    "Act 1 Scene 5: The Great Hall in Capulet's mansion",
	    "Act 2 Scene 1: Outside Capulet's mansion",
	    "Act 2 Scene 2: Capulet's orchard",
	    "Act 2 Scene 3: Outside Friar Lawrence's cell",
	    "Act 2 Scene 4: A street in Verona",
	    "Act 2 Scene 5: Capulet's mansion",
	    "Act 2 Scene 6: Friar Lawrence's cell"
        ]
        
    //문자열 배열에서 접두어 Act 1가 몇개 들어있는지 확인
    var act1SceneCount = 0
	for scene in remeoAndJuliet {
	    if scene.hasPrefix("Act 1 ") {
	        act1SceneCount += 1
	    }
	}
	print("There are \(act1SceneCount) scenes in Act 1")
		// There are 5 scenes in Act 1

-문자열과 문자 비교: == 혹은 != 연산자 사용

>유니코드는 결합된 문자열을 갖고 비교하게 됨.
>같은 유니코드 문자여도 유니코드가 다르면 다른 문자로 판별
>언어와 상관없이 같은 문자면 같은 문자로 취급

-문자열의 유니코드 표현: UTF-8, UTF-16, UTF-32 등 다양한 유니코드 인코딩 방식 사용

3. 콜렉션 타입(Collection Types)

-Swift는 콜렉션 타입으로 배열, 셋, 사전 세 가지를 지원
-콜렉션 변경: 배열, 셋, 사전을
변수(var)에 할당 -> 이 콜렉션은 변경 O,
상수에 할당 -> 변경 X

-배열(Array) > 축약형으로 [Element] 형태로도 사용

>배열 생성
ex) ```
var someInts = [Int]()
print("someInts is of type [Int] with \(someInts.count) items."
	//someInts is of type [Int] with 0 items.
    
someInts.append(3) //배열에 3 추가
someInts = [] //배열 비움, 배열의 아이템 타입은 그대로 Int로 유지.

>기본 값으로 빈 배열 생성: repeating 메소드, count 메소드 이용
ex)```
var threeDoubles = Array(repeating: 0.0, count: 3)
	// threeDoubles : Double 타입의 [0.0, 0.0, 0.0]
>다른 배열을 추가한 배열 생성: + 연산자로 배열을 합칠 수 O
ex)```
var anotherThreeDoubles = Array(repeating: 2.5, count: 3)
var sixDoubles = threeDoubles + anotherThreeDoubles
	//sixDoubles : [0.0, 0.0, 0.0, 2.5, 2.5, 2.5]
>리터럴 이용: [value 1, value 2, value 3] 형태
ex)```
var shoppingList: [String] = ["Eggs", "Milk"]
var shoppingList = ["Eggs", "Milk"]
	// 두 방식 동일

-배열의 원소 개수 확인

>ex) ```
print("The shopping list contains \(shoppingList.count) items.") 
	//The shopping list contains 2 items.

-배열 비었는지 확인: array.isEmpty ->Bool 타입 리턴
-배열에 원소 추가: array.append()혹은 + 연산자 사용
-특정 위치에 원소 추가/삭제/접근

>ex)```
shoppingList += ['a', 'b', 'c']
	//shoppingList.count = 5
shoppingList[2..4] = ["Bananas", "Apples"]
	//2, 3, 4번째 인덱스 아이템을 Bananas, Apples로 변환 
    //즉, 아이템 3개가 2개로 줄었다.
let apples = shoppingList.removeLast()

-배열의 순회: for-in loop
ex) ```
for item in shoppingList {
print(item)
}
//Eggs
//Milk
//Bananas
//Apples

-배열의 값과 인덱스: enumerated()
ex)```
for (index, value) in shoppingList {
	print("Item \(index + 1): \(value)")
    	// Item 1: Eggs
		// Item 2: Milk
		// Item 3: Bananas
		// Item 4: Apples

-셋(Set): 정렬되지 않은 컬렉션(->Set을 print할 경우, 삽입 순서에 상관없이 뒤죽박죽 나옴), 배열과 달리 중복 요소 허용 Xx,,
딕셔너리와 같이 해시를 통해 값을 저장 > 배열에 비해 검색 속도가 빠름
Set 형태로 저장되기 위해서는 반드시 타입이 hashable 이어야 함. (String, Int, Double, Bool 같은 기본 타입은 기본적으로 hashable)
저장되는 자료형은 모두 동일한 자료형이어야 함!
(구조체로 Stack에 저장)
ex) ```
var english: Set = ["A", "B", "C"]
english.insert("D")
if let removeEng = english.remove("C") {
print("\ (removeEng)")
}
//C

	>배열처럼 for-in loop를 이용해 set을 순회할 수 있다.

-값 추가, 삭제
ex)```
var set1: Set = [1, 2, 5, 0]

//1. insert : 값을 추가하고, 추가된 결과를 튜플로 리턴(중복이면 false, 추가된 값)
set1.insert(1) // (false, 1)
set1. insert(10) // (true, 10)

//2. update : 값이 존재하지 않으면 추가 후 nil 리턴, 존재할 경우 덮어쓰기 후 덮어쓰기 전 값 리턴
set1.update(with: 1) // Optional(1)
set1.update(with: 120) // nil

var set1: Set = [1, 2, 5, 0]

// 1. remove() : 한 가지 요소 삭제할 때 사용, 삭제 후 삭제한 값 return (없는 요소 삭제 시 nil 리턴)
set1.remove(1) // Optional(1)
set1.remove(10) // nil

// 2. removeAll() : 전체 요소 삭제
set1.removeAll()

-값 비교: Set은 정렬되지 않은 Collection이기 때문에, 순서 상관없이 모든 요소가 같으면 비교 연산자 true!

-Set 명령

>a.intersection(b): a ∩ b
>a.symmetricDifference(b): (a ∩ b)의 여집합
>a.union(b): a ∪ b
>a.subracting(b): a - b

ex) ```

let A: Set = [1, 3, 5, 7, 9]
let B: Set = [0, 2, 4, 6, 8]
A.union(B).sorted() //[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

-Set의 멤버십과 동등 비교: ==연산자 -> 동등 비교
isSuperset(of:), isStrictSubset(of:), isStrictSuperset(of:), isDisjoint(with:) 메소드 -> 멤버 여부 확인

>isSubset(of:): 부분 집합
```
var set1: Set<Int> = [1, 2, 5, 0]
var set2: Set<Int> = [1, 2]

set1.isSubset(of: set2)               	// false
set2.isSubset(of: set1)               	// true
    >isSuperSet(of:): 상위 집합
    ```
var set1: Set<Int> = [1, 2, 5, 0]
var set2: Set<Int> = [1, 2]
 
set1.isSuperset(of: set2)               // true
set2.isSuperset(of: set1)               // false```

	>isDisjoint(with:): 같은 집합/ 서로수 집합
    	->모든 요소가 다르면 true, 모든 요소가 같으면 false 반환
        ```
var set13: Set<Int> = [1, 2, 5, 0]
var set14: Set<Int> = [1, 2, 5, 0]
var set15: Set<Int> = [3, 7, 9, 10]
 
set13.isDisjoint(with: set14)               // false (같은 집합 : 모든 요소가 동일한 집합)
set15.isDisjoint(with: set13)               // true  (서로수 집합 : 모든 요소가 다른 집합)

-사전(Dictionaries): Key:Value가 함께 저장되는 자료구조, 정렬되지 않은 컬렉션
값은 중복 가능, but 키는 중복 불가!
모든 Key의 자료형은 같아야 하고, 따라서 모든 Value의 자료형도 같아야 함.

Swift의 Dictionary 타입은 Foundation 클래스의 NSDictionary를 bridge한 타입.

-빈 Dictionary 생성

var namesOfIntegers = [Int:String]()

-리터럴을 이용한 Dictionary 생성: [key 1: value 1, key 2: value 2, key 3: value 3]

var airports: [String: String] = = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]

-Dictionary 요소에 접근

var dict1 = ["height": 165, "age" : 100]
 
// 1. 반환 값 - Optional Type
let height = dict1["height"]                   // Optional(165)
let weight = dict1["weight"]                   // nil
 
// 2. 반환 값 - Non Optional Type
let height = dict1["height", default: 150]     // 165
let weight = dict1["weight", default: 200]     // 200

-Dictionary에 요소 추가

var dict1 = ["height": 165, "age" : 100]
 
// 1. Subscript로 추가하기
dict1["weight"] = 100                            // 해당 Key가 없다면, 추가 (insert)
dict1["height"] = 200                            // 해당 Key가 있다면, Value 덮어쓰기 (update)
 
// 2. updateValue(:forKey)
dict1.updateValue(100, forKey: "weight")         // 해당 Key가 없다면, 추가하고 nil 리턴 (insert)
dict1.updateValue(200, forKey: "height")         // 해당 Key가 있다면, Value 덮어쓰고 덮어쓰기 전 값 리턴 (update)

-Key, Value 나열

var dict1 = ["height": 165, "age" : 100]
 
// 1. Key 모두 나열하기
dict1.keys                         // "height, "age"
dict1.keys.sorted()                // "age", "height
 
// 2. Value 모두 나열하기
dict1.values                       // 165, 100
dict1.values.sorted()              // 100, 165

keys, values는 때에 따라 순서가 다르게 출력됨

좋은 웹페이지 즐겨찾기