var 변수 = 값
var 변수:유형 = 값
var 변수:유형 // 선언만 해둠
var (변수1, 변수2, ...) = (값1, 값2, ...)
let 상수 = 값
let 상수:유형 = 값
값이 이상해져도 좋으니까 오류를 발생시키지 말았으면"할 때 사용
var x = y & + 100000
// 정수로 변환
123 + Int(45.67)
// 텍스트로 변환
"123"+ String(456)
Swift의 모든 타입을 지칭하는 키워드
var someAny: Any = 100
someAny = "어떤 타입도 수용 가능합니다"
someAny = 123.12
모든 클래스 타입을 지칭하는 프로토콜
class SomeClass {}
var someAnyObject: AnyObject = SomeClass()
없음을 의미하는 키워드
멤버가 순서(인덱스)를 가진 리스트 형태의 컬렉션 타입
// Array 선언 및 생성
var integers: Array<Int> = Array<Int>()
// 같은 표현
// var integers: Array<Int> = [Int]()
// var integers: Array<Int> = []
// var integers: [Int] = Array<Int>()
// var integers: [Int] = [Int]()
// var integers: [Int] = []
// var integers = [Int]()
// 활용
integers.append(1)
integers.append(100)
print(integers) // [1, 100]
// 멤버 포함 여부 확인
print(integers.contains(100)) // true
print(integers.contains(99)) // false
// 멤버 교체
integers[0] = 99
// 멤버 삭제
integers.remove(at: 0)
integers.removeLast()
integers.removeAll()
// 멤버 수 확인
print(integers.count)
// 인덱스를 벗어나 접근하려면 익셉션 런타임 오류발생
//integers[0]
키와 값의 쌍으로 이루어진 컬렉션 타입
var anyDictionary: Dictionary<String, Any> = [String: Any]()
// Key가 String 타입이고 Value가 Any인 빈 Dictionary
// 같은 표현
// var anyDictionary: Dictionary <String, Any> = Dictionary<String, Any>()
// var anyDictionary: Dictionary <String, Any> = [:]
// var anyDictionary: [String: Any] = Dictionary<String, Any>()
// var anyDictionary: [String: Any] = [String: Any]()
// var anyDictionary: [String: Any] = [:]
// var anyDictionary = [String: Any]()
// 키에 해당하는 값 할당
anyDictionary["someKey"] = "value"
anyDictionary["anotherKey"] = 100
print(anyDictionary) // ["someKey": "value", "anotherKey": 100]
// 키에 해당하는 값 변경
anyDictionary["someKey"] = "dictionary"
print(anyDictionary) // ["someKey": "dictionary", "anotherKey": 100]
// 키에 해당하는 값 제거
anyDictionary.removeValue(forKey: "anotherKey")
anyDictionary["someKey"] = nil
print(anyDictionary)
순서가 없고, 멤버가 유일한 것을 보장하는 컬렉션 타입
var integerSet: Set<Int> = Set<Int>()
integerSet.insert(1)
integerSet.insert(100)
integerSet.insert(99)
integerSet.insert(99)
integerSet.insert(99)
print(integerSet) // [100, 99, 1]
print(integerSet.contains(1)) // true
print(integerSet.contains(2)) // false
integerSet.remove(100)
integerSet.removeFirst()
print(integerSet.count) // 1
// Set는 집합 연산에 꽤 유용합니다
let setA: Set<Int> = [1, 2, 3, 4, 5]
let setB: Set<Int> = [3, 4, 5, 6, 7]
// 합집합
let union: Set<Int> = setA.union(setB)
print(union) // [2, 4, 5, 6, 7, 3, 1]
// 합집합 오름차순 정렬
let sortedUnion: [Int] = union.sorted()
print(sortedUnion) // [1, 2, 3, 4, 5, 6, 7]
// 교집합
let intersection: Set<Int> = setA.intersection(setB)
print(intersection) // [5, 3, 4]
// 차집합
let subtracting: Set<Int> = setA.subtracting(setB)
print(subtracting) // [2, 1]
if 조건문 {
...... 처리 ......
} else if 조건문 {
...... 처리 ......
} else if ...... 필요한 만큼 계속 쓴다 ......
}
var x = 300
switch x {
case 0:
"zero"
case 1...9:
"1번"
case 10...99:
"2번"
case 100...999:
"3번"
default:
"없다"
}
var integers = [1, 2, 3]
let people = ["yagom": 10, "eric": 15, "mike": 12]
for integer in integers {
print(integer)
}
// Dictionary의 item은 key와 value로 구성된 튜플 타입입니다
for (name, age) in people {
print("\(name): \(age)")
}
for 초기화 처리; 조건; 후 처리 {
...... 반복 처리 ......
}
// 예제
for var i = 0; i <10; i ++ {
"index :"+ String (i)
}
while 조건 {
...... 반복 처리 ......
}
do {
...... 반복 처리 ......
} while 조건
repeat {
/* 실행 구문 */
} while 조건
func 함수명(인수) -> 반환 값 {
...... 수행할 작업 ......
return 값
}
// 예제 1
func calc(num:Int) -> Int {
var total:Int = 0
for i in 1...num {
total += i
}
return total
}
calc(100)
// 반환 값이 없는 경우 void로 지정 (생략 가능)
(외부명 변수명:유형)
외부명은 코드를 보다 알기 쉽게하는데 필수적인 기능
func tax(price p:Int, rate r:Double) -> Int {
return Int(Double(p) * (1.0 + r))
}
var res:Int = tax(price:10000, rate:0.08)
함수 내에서 사용할 변수명과 외부명이 같기 때문에 소스 코드도 깔끔해지고 가독성 높아짐
func tax(price:Int, rate:Double) -> Int {
return Int(Double(price) * (1.0 + rate))
}
var res:Int = tax(10000, rate:0.08)
여러 값을 한곳에 모아 처리하는 것
(이름:값, 이름:값, ...)
var person = (name:"Taro", age:35)
person.name
person.age
func tax(price:Int) -> (kakaku:Int, zei:Int) {
let zei:Int = Int(Double(price) * 0.08)
let kakaku:Int = price - zei
return (kakaku:kakaku, zei:zei)
}
var res = tax(10000)
res.kakaku
res.zei
func 함수이름(매개변수1이름: 매개변수1타입, 매개변수2이름: 매개변수2타입 = 매개변수 기본값 ...) -> 반환타입 {
/* 함수 구현부 */
return 반환값
}
// 예제
func tax(price:Int, rate:Double = 0.08) -> Int {
return Int(Double(price) * (1.0 + rate))
}
var res:Int = tax(price:10000, rate:0.08)
var res3:Int = tax(price:12300)
func 함수이름(전달인자 레이블 매개변수1이름: 매개변수1타입, 전달인자 레이블 매개변수2이름: 매개변수2타입 ...) -> 반환타입 {
/* 함수 구현부 */
return
}
// 함수 내부에서 전달인자를 사용할 때에는 매개변수 이름을 사용합니다
func greeting(to friend: String, from me: String) {
print("Hello \(friend)! I'm \(me)")
}
// 함수를 호출할 때에는 전달인자 레이블을 사용해야 합니다
greeting(to: "hana", from: "yagom") // Hello hana! I'm yagom
전달 받을 값의 개수를 알기 어려울 때 사용
func 함수이름(매개변수1이름: 매개변수1타입, 전달인자 레이블 매개변수2이름: 매개변수2타입...) -> 반환타입 {
/* 함수 구현부 */
return
}
func sayHelloToFriends(me: String, friends: String...) -> String {
return "Hello \(friends)! I'm \(me)!"
}
print(sayHelloToFriends(me: "yagom", friends: "hana", "eric", "wing"))
// Hello ["hana", "eric", "wing"]! I'm yagom!
print(sayHelloToFriends(me: "yagom"))
// Hello []! I'm yagom!
반환타입을 생략할 수 없음
(매개변수1타입, 매개변수2타입 ...) -> 반환타입
func greeting(to friend: String, from me: String) {
print("Hello \(friend)! I'm \(me)")
}
var someFunction: (String, String) -> Void = greeting(to:from:)
someFunction("eric", "yagom") // Hello eric! I'm yagom
someFunction = greeting(friend:me:)
someFunction("eric", "yagom") // Hello eric! I'm yagom
// 타입이 다른 함수는 할당할 수 없습니다 - 컴파일 오류 발생
//someFunction = sayHelloToFriends(me: friends:)
func runAnother(function: (String, String) -> Void) {
function("jenny", "mike")
}
// Hello jenny! I'm mike
runAnother(function: greeting(friend:me:))
// Hello jenny! I'm mike
runAnother(function: someFunction)
struct 이름 {
/* 구현부 */
}
struct Sample {
// 가변 프로퍼티
var mutableProperty: Int = 100
// 불변 프로퍼티
let immutableProperty: Int = 100
// 타입 프로퍼티
static var typeProperty: Int = 100
// 인스턴스 메서드
func instanceMethod() {
print("instance method")
}
// 타입 메서드
static func typeMethod() {
print("type method")
}
}
// 가변 인스턴스 생성
var mutable: Sample = Sample()
mutable.mutableProperty = 200
mutable.immutableProperty = 200 // 컴파일 오류 발생
// 불변 프로퍼티는 인스턴스 생성 후 수정할 수 없습니다
// 불변 인스턴스 생성
let immutable: Sample = Sample()
immutable.mutableProperty = 200 // 컴파일 오류 발생
immutable.immutableProperty = 200 // 컴파일 오류 발생
// 불변 인스턴스는 아무리 가변 프로퍼티라도 인스턴스 생성 후에 수정 불가
// 타입 프로퍼티 및 메서드
Sample.typeProperty = 300
Sample.typeMethod() // type method
mutable.typeProperty = 400 // 컴파일 오류 발생
mutable.typeMethod() // 컴파일 오류 발생
// 인스턴스에서는 타입 프로퍼티나 타입 메서드 사용 불가
class 클래스명 {
// 변수(속성, property)과 함수(메소드, method)를 작성한다
}
class Sample {
// 가변 프로퍼티
var mutableProperty: Int = 100
// 불변 프로퍼티
let immutableProperty: Int = 100
// 타입 프로퍼티
static var typeProperty: Int = 100
// 인스턴스 메서드
func instanceMethod() {
print("instance method")
}
// 타입 메서드
// 재정의 불가 타입 메서드 - static
static func typeMethod() {
print("type method - static")
}
// 재정의 가능 타입 메서드 - class
class func classMethod() {
print("type method - class")
}
}
// 인스턴스 생성 - 참조정보 수정 가능
var mutableReference: Sample = Sample()
mutableReference.mutableProperty = 200
mutableReference.immutableProperty = 200 // 컴파일 오류 발생
// 불변 프로퍼티는 인스턴스 생성 후 수정 불가
// 인스턴스 생성 - 참조정보 수정 불가
let immutableReference: Sample = Sample()
immutableReference.mutableProperty = 200
// 클래스의 인스턴스는 참조 타입이므로 let으로 선언되었더라도 인스턴스 프로퍼티의 값 변경 가능
immutableReference = mutableReference // 컴파일 오류 발생
// 참조정보는 변경 불가
immutableReference.immutableProperty = 200 // 컴파일 오류 발생
// 참조 타입이라도 불변 인스턴스는 인스턴스 생성 후에 수정 불가
// 타입 프로퍼티 및 메서드
Sample.typeProperty = 300
Sample.typeMethod() // type method
mutableReference.typeProperty = 400 // 컴파일 오류 발생
mutableReference.typeMethod() // 컴파일 오류 발생
// 인스턴스에서는 타입 프로퍼티나 타입 메서드를 사용 불가
class 클래스명:슈퍼 클래스명 {
// 슈퍼 클래스 : 상속 근원이 되는 클래스
// 서브 클래스 : 슈퍼 클래스를 계승하여 만든 클래스
}
// 예제 1
import Cocoa
class Helo {
var name:String = "Taro";
func say(){
print("Hello, " + name + "!");
}
}
class Hello:Helo { // 서브 클래스 선언
var name2:String = "YAMADA";
func say2(){
print("Hi," + name + "-" + name2 + "!");
}
}
var obj:Hello = Hello(); // 인스턴스 선언
obj.name = "Hanako";
obj.name2 = "TANAKA"; // 상속
obj.say();
obj.say2(); // 상속
// 예제 2
class Friend {
var name:String
init(name:String) { // initializer (뒤에 나옴)
self.name = name
}
}
class BestFriend : Friend {
var age:Int
init(name:String, age:Int) {
self.age = age
super.init(name:name) // 슈퍼 클래스
}
}
var you = BestFriend(name: "Taro", age: 30)
print("\(you.name) (\(you.age))")
인스턴스를 만들 때 필요한 값 등을 인수로 전달
인스턴스를 만들 때 자동으로 호출되는 초기화 처리 전용의 메소드
생성자와 유사한 개념?
import Cocoa
class Helo {
var name:String;
init(name:String){ // 이니셜라이저를 통해 name 프로퍼티를 인수로 만듬
self.name = name; // self : Helo 클래스
}
func say(){
print("Hello, " + name + "!");
}
}
var obj:Helo = Helo(name:"Taro"); // 'Taro'가 인수로 전달됨
obj.say();
슈퍼 클래스에 있는 메소드를 재정의하는 기술
메소드명뿐만 아니라 인수와 반환 값도 정확하게 슈퍼 클래스의 메소드와 동일해야 함.
import Cocoa
class Helo {
var name:String = "Taro";
func say(){
print("Hello, " + name + "!");
}
}
class Hello:Helo {
var name2:String = "YAMADA";
override func say(){ // 슈퍼 클래스(Helo)에 있는 메소드(say) 재정의
print("Hi," + name + "-" + name2 + "!");
}
}
값이 있을 수도 있고 없을 수도 있는 변수를 정의
옵셔널에 초깃값을 지정하지 않으면 기본값은 nil
// 예제 1
var email: String?
print(email) // nil
email = "devxoul@gmail.com"
print(email) // Optional("devxoul@gmail.com")
// 예제 2
// 열거형으로 값 구분 가능
switch optionalValue {
case .none:
print("This Optional variable is nil")
case .some(let value):
print("Value is \(value)")
}
// nil 할당 가능
optionalValue = nil
// 기존 변수처럼 사용 불가
optionalValue = optionalValue + 1 // 연산 불가
var optionalValue: Int! = 100
// 열거형으로 값 구분 가능
switch optionalValue {
case .none:
print("This Optional variable is nil")
case .some(let value):
print("Value is \(value)")
}
// 기본 변수처럼 사용 가능
optionalValue = optionalValue + 1
// nil 할당 가능
optionalValue = nil
// 잘못된 접근(nil값에 접근)
optionalValue = optionalValue + 1 // 런타임 오류 발생
func printName(_ name: String){
print(name)
}
var myname: String? = nil
printName(myName) // 컴파일 오류
// 전달되는 값의 타입이 다름
// 예제 1
func printName(_ name: String){
print(name)
}
var myname: String! = nil
if let name: String = myName {
printName(name)
} else {
print("myName == nil")
}
// name 상수는 if-let 구문 내에서만 사용 가능
printName(name) // 컴파일 오류 발생
// 상수 사용범위를 벗어남
// 예제 2
var myName: String? = "yagom"
var yourName: String? = nil
if let name = myName, let friend = yourName {
print("\(name) and \(friend)")
}
// yourName이 nil이기 때문에 실행 X
yourName = "haha"
if let name = myName, let friend = yourName {
print("\(name) and \(friend)")
}
// yagom and haha
func printName(_ name: String) {
print(name)
}
var myName: String? = "yagom"
printName(myName!) // yagom
myName = nil
print(myName!)
// 값이 없으므로 런타임 오류 발생
var yourName: String! = nil
printName(yourName)
// nil값이 전달되기 때문에 런타임 오류 발생
enum 이름 {
case 이름1
case 이름2
case 이름3, 이름4, 이름5
// ...
}
enum Weekday {
case mon
case tue
case wed
case thu, fri, sat, sun
}
// 열거형 타입과 케이스를 모두 사용 가능
var day: Weekday = Weekday.mon
// 타입이 명확하다면 .케이스 처럼 표현 가능
var day: Weekday = .tue
print(day) // tue
// switch의 비교값에 열거형 타입이 위치할 때
// 모든 열거형 케이스를 포함한다면 default를 작성할 필요 없음
switch day {
case .mon, .tue, .wed, .thu:
print("평일입니다")
case Weekday.fri:
print("불금 파티!!")
case .sat, .sun:
print("신나는 주말!!")
}
// 평일입니다
enum에 type지정 가능. 이는 rawValue의 타입을 의미.
Int로 타입지정
rawValue에 아무 값도 할당하지 않으면, 첫 번째부터 0, 1, 2 순으로 값이 매겨짐
enum Fruit: Int {
case apple = 0
case grape = 1
case peach
case mango = 0 // 정의 불가
// mango와 apple의 원시값이 같음
}
print("Fruit.peach.rawValue == \(Fruit.peach.rawValue)")
// Fruit.peach.rawValue == 2
String 타입지정
rawValue를 할당하지 않으면 case의 값 자체가 rawValue가 됨
enum School: String {
case elementary = "초등"
case middle = "중등"
case high = "고등"
case university
}
print("School.middle.rawValue == \(School.middle.rawValue)")
// School.middle.rawValue == 중등
// 열거형의 원시값 타입이 String일 때, 원시값이 지정되지 않았다면
// case의 이름을 원시값으로 사용합니다
print("School.university.rawValue == \(School.university.rawValue)")
// School.middle.rawValue == university
// rawValue를 통해 초기화 한 열거형 값은 옵셔널 타입이므로 Fruit 타입이 아닙니다
// let apple: Fruit = Fruit(rawValue: 0)
let apple: Fruit? = Fruit(rawValue: 0)
// if let 구문을 사용하면 rawValue에 해당하는 케이스를 곧바로 사용할 수 있습니다
if let orange: Fruit = Fruit(rawValue: 5) {
print("rawValue 5에 해당하는 케이스는 \(orange)입니다")
} else {
print("rawValue 5에 해당하는 케이스가 없습니다")
} // rawValue 5에 해당하는 케이스가 없습니다
enum Month {
case dec, jan, feb
case mar, apr, may
case jun, jul, aug
case sep, oct, nov
func printMessage() {
switch self {
case .mar, .apr, .may:
print("따스한 봄~")
case .jun, .jul, .aug:
print("여름 더워요~")
case .sep, .oct, .nov:
print("가을은 독서의 계절!")
case .dec, .jan, .feb:
print("추운 겨울입니다")
}
}
}
Month.mar.printMessage()
// 따스한 봄~
. | 타입 | 상속 |
---|---|---|
열거형, 구조체 | 값 타입 | 불가능 |
클래스 | 참조 타입 | 가능 |
struct ValueType {
var property = 1
}
class ReferenceType {
var property = 1
}
// 첫 번째 구조체 인스턴스
let firstStructInstance = ValueType()
// 두 번째 구조체 인스턴스에 첫 번째 인스턴스 값 복사
var secondStructInstance = firstStructInstance
// 두 번째 구조체 인스턴스 프로퍼티 값 수정
secondStructInstance.property = 2
// 두 번째 구조체 인스턴스 : 첫 번째 구조체를 똑같이 복사한 별도의 인스턴스
// 두 번째 구조체 인스턴스의 프로퍼티 값을 변경해도 첫 번째 구조체 인스턴스의 프로퍼티 값에는 영향 없음
print("first struct instance property : \(firstStructInstance.property)") // 1
print("second struct instance property : \(secondStructInstance.property)") // 2
// 클래스 인스턴스 생성 후 첫 번째 참조 생성
let firstClassReference = ReferenceType()
// 두 번째 참조 변수에 첫 번째 참조 할당
let secondClassReference = firstClassReference
secondClassReference.property = 2
// 두 번째 클래스 참조는 첫 번째 클래스 인스턴스를 참조
// 두 번째 참조를 통해 인스턴스의 프로퍼티 값을 변경하면 첫 번째 클래스 인스턴스의 프로퍼티 값 변경
print("first class reference property : \(firstClassReference.property)") // 2
print("second class reference property : \(secondClassReference.property)") // 2
{ (매개변수 목록) -> 반환타입 in
실행 코드
}
// 함수를 사용한다면
func sumFunction(a: Int, b: Int) -> Int{
return a + b
}
var sumResult: Int = sumFunction(a: 1, b: 2)
print(sumResult) // 3
// 클로저를 사용한다면
var sum: (Int, Int) -> Int = { (a: Int, b: Int) -> Int in
return a + b
}
sumResult = sum(1, 2)
print(sumResult) // 3
let add: (Int, Int) -> Int
add = { (a: Int, b: Int) in
return a + b
}
let substract: (Int, Int) -> Int
substract = { (a: Int, b: Int) in
return a - b
}
let divide: (Int, Int) -> Int
divide = { (a: Int, b: Int) in
return a / b
}
func calculate(a: Int, b: Int, method: (Int, Int) -> Int) -> Int {
return method(a, b)
}
var calculated: Int
calculated = calculate(a: 50, b: 10, method: add)
print(calculated) // 60
calculated = calculate(a: 50, b: 10, method: substract)
print(calculated) // 40
calculated = calculate(a: 50, b: 10, method: divide)
print(calculated) // 5
// 따로 클로저를 상수, 변수에 넣어 전달하지 않고 함수를 호출할 때 클로저를 작성하여 전달 가능
calculated = calculate(a: 50, b: 10, method: { (left: Int, right: Int) -> Int in
return left * right
})
print(calculated) // 500
// 클로저가 함수의 마지막 전달인자일 때
// 마지막 매개변수 이름을 생략한 후 함수 소괄호 외부에 클로저를 구현 가능
result = calculate(a: 10, b: 10) { (left: Int, right: Int) -> Int in
return left + right
}
print(result) // 20
// Int 타입을 반환할 것이라는 사실을 컴파일러도 알기 때문에 굳이 클로저에서 반환타입을 명시해 줄 필요 X
// 대신 in 키워드는 생략 불가
result = calculate(a: 10, b: 10, method: { (left: Int, right: Int) in
return left + right
})
print(result) // 20
// 후행클로저와 함께 사용 가능
result = calculate(a: 10, b: 10) { (left: Int, right: Int) in
return left + right
}
print(result) // 20
// 클로저의 매개변수 이름이 굳이 불필요하다면 단축 인자이름을 활용 가능
// 단축 인자이름은 클로저의 매개변수의 순서대로 $0, $1, $2… 처럼 표현
result = calculate(a: 10, b: 10, method: {
return $0 + $1
})
print(result) // 20
// 당연히 후행 클로저와 함께 사용할 수 있습니다
result = calculate(a: 10, b: 10) {
return $0 + $1
}
print(result) // 20
// 클로저가 반환하는 값이 있다면 클로저의 마지막 줄의 결과값은 암시적으로 반환값으로 취급
result = calculate(a: 10, b: 10) {
$0 + $1
}
print(result) // 20
// 간결하게 한 줄로 표현해 줄 수도 있습니다
result = calculate(a: 10, b: 10) { $0 + $1 }
print(result) // 20
//축약 전
result = calculate(a: 10, b: 10, method: { (left: Int, right: Int) -> Int in
return left + right
})
//축약 후
result = calculate(a: 10, b: 10) { $0 + $1 }
print(result) // 20
StoryBoard에서 버튼이나 레이블같은 컴포넌트와 연결이 가능
IBAction : Event가 일어난 경우 호출되는 Action
IBOutlet : 값에 접근하기 위한 변수
UI 중에서 어떤 항목을 가리키도록 설정할것인가를 의미
@IBAction :UIButton // 버튼을 가리키기위해 사용