#2-1. 데이터 타입, 변수 그리고 배열 [스위프트]

인생노잼시기·2021년 4월 26일
0

🦅 스위프트 문법

목록 보기
5/13

출처: 스위프트 프로그래밍 - 야곰

1. 변수와 상수

  • 변수 var
  • 상수 let

2. 타입 지정(Type Annotation)과 타입 추론(Type Inference)

  • 타입 지정 (권장)
    • var 변수명: 데이터타입 = 값
  • 타입 추론
    • var 변수명 = 값
    var height = 180.5
    print(type(of: height))	//Double

2.1 타입캐스팅

스위프트는 암시적 데이터 타입 변환을 지원하지 않습니다.
이니셜라이저(init)를 통해 새로운 인스턴스를 생성하는 과정입니다.
실제로 인스턴스를 수정하거나 값을 변경하는 작업이 아닙니다. 인스턴스는 메모리에 똑같이 남아 있고 그저 컴퓨터에 힌트를 주는 것뿐입니다.

Int 구조체는 이니셜라이저가 다양하게 이미 정의되어 있다.
StringProtocl 타입의 데이터 text를 Int 타입으로 변경 시, 적절치 못한 매개변수가 전달된다면(예를 들어 A123) 새로운 인스턴스가 생성되지 않을 수 있다.

var value: Double = 3.3
var convertedValue: Int = Int(value)
convertedValue = 5.5	//오류, Cannot assign value of type 'Double' to type 'Int'

var stringValue: String = "123"
var integerValue: Int? = Int(stringValue)
print(integerValue) //Optional(123)

stringValue = "A123"
integerValue = Int(stringValue)
print(integerValue) //오류, nil == Optional.none

is와 as 연산자 활용하기

  • 타입 확인 연산자 is
    Coffee클래스를 상속받은 Latte클래스(your)와 Americano클래스(my)
class Coffee {
    let name: String
    let shot: Int
    
    var description: String {
        return "\(shot) shot(s) \(name)"
    }
    
    init(shot: Int) {
        self.shot = shot
        self.name = "coffee"
    }
}

class Latte: Coffee {
    var flavor: String
    
    override var description: String {
        return"\(shot) shot(s) \(flavor) latte"
    }
    
    init(flavor: String, shot: Int) {
        self.flavor = flavor
        super.init(shot: shot)
    }
}

class Americano: Coffee {
    let iced: Bool
    
    override var description: String {
        return "\(shot) shot(s) \(iced ? "iced" : "hot") americano"
    }
    
    init(shot: Int, iced: Bool) {
        self.iced = iced
        super.init(shot: shot)
    }
}

let coffee: Coffee = Coffee(shot: 1)
print(coffee.description)

let myCoffee: Americano = Americano(shot: 2, iced: false)
print(myCoffee.description)

let yourCoffee: Latte = Latte(flavor: "green tea", shot: 3)
print(yourcoffe)

print(coffee is Coffee)      //true
print(coffee is Americano)   //false
print(coffee is Latte)       //true

print(myCoffee is Coffee)    //true
print(yourCoffee is Coffee)  //true

print(myCoffee is Latte)     //false
print(yourCoffee is Latte)   //true

print(type(of: coffee) == Coffee.self)      //true
print(type(of: myCoffee) == Coffee.self)    //false
print(type(of: yourCoffee) == Coffee.self)  //false

if let actingOne: Americano = coffee as? Americano {    //부모가 자식으로 X
    print("This is Americano")
} else {
    print(coffee.description)   //1 shot(s) coffee
}

if let actingTwo: Coffee = coffee as? Coffee {      //부모가 부모로 || 같은 타입으로 -> as도 가능
    print("This is just Coffee")    //This is just Coffee
} else {
    print(coffee.description)
}
  • 메타 타입 Meta Type: 타입의 타입
    • 클래스 타입(SomeClass.Type), 구조체 타입, 열거형 타입, 프로토콜 타입(SomeProtocol.Protocol) 등...
    • self를 사용하면 타입을 값처럼 표현할 수 있다.
      SomeClass.self라고 표현하면 SomeClass의 인스턴스가 아니라 SomeClass 타입을 값으로 표현한 값을 반환한다. SomeProtocol.self라고 표현하면 SomeProtocol 프로토콜을 값으로 표현한 값을 반환합니다.
    • Int, String이 struct로 표현되어 있고 struct가 값타입임을 기억하자.
protocol SomeProtocol {}
class SomeClass: SomeProtocol {}

let intType: Int.Type = Int.self
let stringType: String.Type = String.self
let stringValueType: String = "StringValue".self
let classType: SomeClass.Type = SomeClass.self
let protocolProtocol: SomeProtocol.Protocol = SomeProtocol.self

var someType: Any.Type

someType = intType
print(someType)     //Int

someType = stringType
print(stringType)   //String, 타입을 표현하는 값

print(stringValueType)  //StringValue, 값

someType = classType
print(someType)     //SomeClass

someType = protocolProtocol
print(someType)     //SomeProtocol

2.2 다운캐스팅 as❓ as❗️

부모클래스의 타입을 자식클래스의 타입으로 캐스팅하는 것

if let actingThree: Americano = myCoffee as? Americano {    //자식이 부모로 O
    print("This is Americano")      //This is Americano
} else {
    print(coffee.description)
}

2.3 Any, AnyObject (지양)

Any는 모든 타입, AnyObject는 클래스 타입

3. 기본 데이터 타입

기본 데이터 타입은 모두 해시 가능한 값이다 (Hashable 프로토콜을 따른다.)

1. 정수 Int(권장), UInt

UInt(-부호를 포함하지 않는 0을 포함한 양의 정수)
시스템 아키텍처에 따라 8, 16, 32, 64비트가 있다

  • 기본Int는 64비트로 되어있다! 엄청 크구나😲
  • UInt8.max -> 2^8 = 256-1 (0때문에-1, 0~255)
  • UInt8.min -> 얘는 당연히 0이다
  • Int8.max -> 2^7=128-1 (부호1비트때문에2^7, 0 ~ 127)
  • Int8.min -> 2^7=128 (부호1비트때문에2^7, -128 ~ -1)
  print(Int.max)	//9223372036854775807 19자리
  print(Int.min)	//-9223372036854775808
  print(UInt.max)	//18446744073709551615
  print(UInt.min)	//0

  print(Int64.max)	//9223372036854775807
  print(Int64.min)	//-9223372036854775808

  print(Int32.max)	//2147483647 10자리
  
  print(UInt8.max)	//255
  print(Int8.max)	//127
  print(Int8.min)	//-128

2. Bool

var boolean: Bool = true
boolean.toggle()	//false

3. 실수 Float, Double(권장)

  • Double: 64비트, 소수점 15자리까지
  • Float: 32비트, 소수점 6자리까지
- double:
부호1 + 지수11비트 + 가수52비트 = 64비트
정밀도는 15이다
- float:
부호1 + 지수8 + 가수23 = 32비트
정규화를 통해 24까지 표현이 가능하다
10^7 < 2^24 < 10^8 정밀도는 7이다

4. Character

유니코드9 단 하나의 문자

let happyImoji: Character = "😄"
print(happyImoji)	//😄

5. String

유니코드9 문자열
유니코드 스칼라는 UInt32값으로 표현되는 21비트 숫자

var introduce: String = String()
introduce.append("ㅈㅏㄱㅣㅅㅗㄱㅐ")
print(introduce + "ㅅㅣㅈㅏㄱ")
print(introduce.count)	//8
print(introduce.isEmpty)	//false

let unicodeScalarValue: String = "\u{2665}"
print(unicodeScalarValue)	//♥
  • 그 외 메서드
    • 접두어체크(hasPrefix), 접미어체크(hasSuffix)
    • 대문자로(uppercased), 소문자로(lowercased)

6. Any, AnyObject, nil

  • Any: 모든 데이터 타입
  • AnyObject: 클래스의 인스턴스만

random함수

Float.random(in: 1.5...4.3)	//1.9126894

var array: [Int] = [0, 1, 2, 3, 4]
print(array.randomElement())    //Optional(1)
print(array.shuffled())    //[4, 2, 0, 3, 1]    원본 유지
print(array)    //[0, 1, 2, 3, 4]
array.shuffle() //원본 변경
print(array)    //[4, 3, 1, 0, 2]

var string: String = "string"
print(string.shuffled())

### Never?

4. 리터럴

  • 정수, 진수표현: 0b, 0o, 0x
  • 문자열, 특수문자: \n, \t, \, \", \0
let number: Int = 10
print(#"ㅌㅡㄱ수ㅁㅜㄴ자 미ㅅㅏㅇㅛㅇ \" ㅁㅜㄴ자ㅇㅕㄹ 보ㄱㅏㄴ버ㅂ\#(number)"#)	//ㅌㅡㄱ수ㅁㅜㄴ자 미ㅅㅏㅇㅛㅇ \" ㅁㅜㄴ자ㅇㅕㄹ 보ㄱㅏㄴ버ㅂ10
#으로 감싸면 \"이 깨져서 보인다

Tuple튜플

typealias Person = (name: String, age: Int<, height: Double)
let me: Person = ("ㄴㅏ", 12, 123.4)
let sister: Person = ("ㄴㅏㅁ", 14, 234.5)
print("\(me.name) + \(me.1)")  //ㄴㅏ + 12
print("\(sister.height), \(sister.0)")	//234.5, ㄴㅏㅁ

컬렉션형Collection

  • 배열Array: 버퍼Buffer라서 필요에 따라 크기가 변경됨
- Array<String>
- [String]

배열의 내장함수

var names: Array<String> = ["yagom", "chulsoo", "younghee", "yagom"]
//var names: [String] = ["yagom", "chulsoo", "younghee", "yagom"] // 위와 동일한 표현 [String], Array<String>

var emptyArray: [Any] = []
//var emptyArray: [Any] = [Any]()
//var emptyArray: [Any] = Array<Any>()  //위와 동일한 표현들
print(emptyArray.isEmpty)   //true
print(names.count)  //4


print(names[2]) //chulsoo
names[2] = "jenny"
print(names[2]) //jenny
//print(names[4]) //error: Execution was interrupted, reason: EXC_BREAKPOINT (code=1, subcode=0x18ec081b8). 인덱스 오류

names.append("elsa")
names.append(contentsOf: ["john", "max"])
print(names)
names.insert("happy", at: 2)    //["yagom", "chulsoo", "jenny", "yagom", "elsa", "john", "max"]
print(names)    //["yagom", "chulsoo", "happy", "jenny", "yagom", "elsa", "john", "max"]

print(names.firstIndex(of: "yagom"))    //Optional(0)
print(names.firstIndex(of: "christal")) //nil
print(names.first)  //Optional("yagom")
print(names.last)   //Optional("max")

let firstItem: String = names.removeFirst()
//let firstItem: String = names.removeLast()
print(firstItem)    //yagom
let indexZeroItem: String = names.remove(at: 0)
print(indexZeroItem)    //chulsoo
print(names[1 ... 3])   //["jenny", "yagom", "elsa"]
  • 딕셔너리Dictionary
    키는 중복될 수 없다
typealias StringIntDictionary = [String: Int]

//var numberForName: Dictionary<String, Int> = Dictionary<String, Int>()
//var numberForName: [String, Int] = [String, Int]()
//var numberForName: StringIntDictionary = StringIntDictionary()
//var numberForName: [String: Int] = [:]    //위와 동일한 표현들

var numberForName: [String: Int] = ["yagom": 100, "chulsoo": 200, "jenny": 300]

print(numberForName.isEmpty)    // false
print(numberForName.count)  // 3

print(numberForName["chulsoo"]) //Optional(200)
print(numberForName["minji"])   //nil

numberForName["chulsoo"] = 150
print(numberForName["chulsoo"]) //Optional(150)

numberForName["max"] = 999
print(numberForName["max"]) //Optional(999)

print(numberForName.removeValue(forKey: "yagom"))   //Optional(100)

print(numberForName.removeValue(forKey: "yagom"))   //nil

print(numberForName["yagom", default: 0])   //0
  • 세트Set
    순서가 없고 값이 중복되지 않는다
    해시 가능한 값이 들어와야 한다???
    Array<Int>[Int]처럼 줄일 수 없다
    교집합(intersection), 여집합(symmetricDifference), 합집합(union), 차집합(subtracting)을 표현하기 좋다.
    isDisjoint, idSubset, isSuperset 등의 메서드가 있다.
var numbers = [100, 200, 300]
print(type(of: numbers))    //Array<Int>    형태가 []이라 Set가 아니라 Array타입으로 타입추론한다


//var names: Set<String> = Set<String>()
//var names: Set<String> = []   위와 동일

var names: Set<String> = ["yagom", "chulsoo", "younghee", "yagom"]

print(names)    //["chulsoo", "yagom", "younghee"]  순서가 그냥 아무렇게나 되네???
print(names.count)  //3

names.insert("jenny")
print(names.count)  //4

print(names.remove("chulsoo"))  //Optional("chulsoo")
print(names.remove("john")) //nil

print(names.sorted())   //["jenny", "yagom", "younghee"]

열거형Enum이늄

옵셔널Optional은 열거형Enum으로 구현되어 있다!

기본 열거형

enum School {
    case primary
    case elementary
    case middle
    case high
    case college
    case university
    case graduate
}

var highestEducationLevel: School = School.university
//var highestEducationLevel: School = .university (위와 동일)
highestEducationLevel = .graduate  //값 변경하기
print(highestEducationLevel)	//graduate

원시 값

rawValue 프로퍼티 사용하기

enum WeekDays: Character {
    case mon = "월", tue = "화", wed = "수", thu = "목", fri = "금", sat = "토", sun = "일"
}

let today: WeekDays = WeekDays.fri
print("오늘은 \(today.rawValue)요일입니다.")

항목 순회

enum School: CaseIterable {
    case primary
    case elementary
    case middle
    case high
    case college
    case university
    case graduate
}

let allCases: [School] = School.allCases
print(allCases)     //[School.primary, School.elementary, School.middle, School.high, School.college, School.university, School.graduate]

순환 열거형

열거형 항목의 연관 값이 열거형 자신의 값일 때
이진 탐색 트리 등 순환 알고리즘 구현 시 유용하다

indirect enum ArithmeticExpression {
    case number(Int)
    case addition(ArithmeticExpression, ArithmeticExpression)
    case multiplication(ArithmeticExpression, ArithmeticExpression)
}

let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let sum = ArithmeticExpression.addition(five, four)
let final = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))

//순환 함수
func evaluate(_ expression: ArithmeticExpression) -> Int {
    switch expression {
    case .number(let value):
        return value
    case .addition(let left, let right):
        return evaluate(left) + evaluate(right)
    case .multiplication(let left, let right):
        return evaluate(left) * evaluate(right)
    }
}

let result: Int = evaluate(final)
print("(5 + 4 ) * 2 = \(result)")   //(5 + 4 ) * 2 = 18

5. 참조형 타입

  • class
  • closure

Class, Struct
class는 참조타입
struct는 값타입

값타입과 참조타입은 뒤에서 라이프타임 ARC와 함께 공부해보자👊

profile
인생노잼

0개의 댓글