값이 변경 가능한 변수보다는 상수를 사용하는 것이 더 안전하고 버그를 줄일 수 있어서 상수 사용이 권장된다!
let num = 360
print(num.isMultiple(of: 3)) //3의 배수인지 확인하는 메서드
let random = Int.random(in: 0...300) // 0~300 랜덤으로 수를 뽑아내는 메서드
option키 변수, 상수에 갖다대고 클릭하면 타입 확인 가능!
Double - 소수점까지 나타내주는 타입
boolean - true, false
var isSingle = true
isSingle.toggle() //true, false 간 한번씩 바꿔주는 메서드이다.
isSingle // false
string interpolation - ()
서로 관계 있는 값들 모아서 표현한 것
특정 타입들 표현할 때 좋다.
enum WeekDay {
case mon
case tue
case wed
case thu
case fri
}
var today: WeekDay = .mon
//직접 string 값으로 넣는 것보다 에러를 줄일 수 있어서 enum 통해 명시적으로 표현해준다.
var mp3: MediaType {
case audio(String)
case video(String)
}
//포맷, 확장자를 같이 받음
var mp3: MediaType = .audio("mp3")
var h264: MediaType = .video("h264")
enum Weather {
case sun
case cloud
case rain
}
var weather: Weather = .sun
switch weather {
case .sun:
print("맑아요")
case .cloud:
print("흐려요")
case .rain:
print("비와요")
}
let languageCode = [
"한국": "ko",
"미국": "en",
"일본": "ja"
]
for (key, value) in languageCode {
print("\(key)키의 코드는 \(value)이다.")
}
딕셔너리는 순서가 보장이 되지 않는다!
값이 있을 수도, 없을 수도 있음을 표현한다.
let languageCode = [
"한국": "ko",
"미국": "en",
"일본": "ja"
]
let krCode = languageCode["한국"]
let deCode = langauageCode ["독일"] //이러면 nil값 나옴
nil값이 나올 수 있기 때문에 deCode 타입을 확인해보면 String? 으로 나온다.
func call(name: String) {
print("hello, \(name)")
}
let callName = call //상수에 함수 할당
callName("cat")
함수를 미리 만들어 놓지 않을 경우는 바로 클로저 할당도 가능하다.
let helloName = { (name: String) in
print("hello, \(name)")
} //상수에 바로 클로저 할당
helloName("cat")
컬렉션 타입 - 배열, 딕셔너리와 같이 데이터를 묶어서 표현하는 것
클로저는 이런 컬렉션 타입과 함께 filter, map, reduce 등 고차함수와 자주 쓰인다.
let nameHasT = members.filter { name in
return name.hasPrefix("T")
}
let doubledPrice = prices.map { price in
return price * 2
}
let totalRevenue = revenue.reduce(0) {
partialResult, next in
return partialResult + next
}
//합친 값을 넘겨준다.
초기값을 0으로 놓고 더한 값이 계속 partialResult로 들어와서 계산된다.
사용자가 원하는 데이터 타입을 만들 때 사용한다.
내부에 변수나 기능(함수)들을 함께 넣을 수 있다.
구조체 내부의 변수를 변경할 경우에는 mutating 키워드를 사용해야한다!
struct Album { // 멤버 변수들 // stored property let title: String let artist: String var isReleased = false
func description() -> String {
return "\(title) by \(artist)"
}
// 구조체 내부 멤버 변수의 값을 변경하는 경우, mutating 키워드 이용
mutating func release() {
self.isReleased = true
}
}
var easyOnMe = Album(title: "Easy On Me", artist: "Adele")
print(easyOnMe.description())
// Easy On Me by Adele
print(easyOnMe.isReleased)
easyOnMe.release()
print(easyOnMe.isReleased)
// false
// true
### 클래스
구조체와 같이 사용자가 원하는 데이터 타입을 만들 때 사용한다.
다른점은
상속이 가능하고,
구조체는 값을 복사하지만 클래스는 값을 참조한다.
또한 클래스는 멤버와이즈 이니셜라이저(생성자)를 기본으로 만들어주지 않는다.
- 생성자: 클래스, 구조체를 생성할 때 사용한다. init 키워드로 선언.
init(name: String, hours: Int) {
self.name = name
self.hours = hours
}
> 구조체는 이것 자동으로 만들어주지만 클래스는 해줘야한다.
상속가능한 클래스
```swift
class Employee {
var name: String
var hours: Int
init(name: String, hours: Int) {
self.name = name
self.hours = hours
}
func work() {
print("I'm working now...")
}
func summary() {
print("I work \(self.hours) hours a day. ")
}
}
class iOSDeveloper: Employee {
override func work() {
print("I'm developing iOS app now.")
}
override func summary() {
print("I work \(self.hours/2) hours a day.")
}
}
//override하면 기존의 메서드를 덮어써서 수정할 수 있다.
struct Phone {
var modelName: String
var manufacturer: String
var version: Double = 1.0
}
let normalWorker = Employee(name: "Kim", hours: 8)
normalWorker.work()
normalWorker.summary()
// I'm working now...
// I work 8 hours a day.
let developer = iOSDeveloper(name: "Jason", hours: 8)
developer.work()
developer.summary()
// I'm developing iOS app now.
// I work 4 hours a day.
// Reference vs. Copy
var iPhone1 = Phone(modelName: "iPhone 13", manufacturer: "Apple")
var iPhone2 = iPhone1
iPhone2.modelName = "iPhone 14"
print(iPhone2.modelName)
print(iPhone1.modelName)
// iPhone 14
// iPhone 13
var jrDeveloper1 = iOSDeveloper(name: "John", hours: 8)
var jrDeveloper2 = jrDeveloper1 //1이 가리키는 포인터만 복사해서 같은 놈을 바라보고 있음
jrDeveloper1.name = "Billy"
print(jrDeveloper1.name)
print(jrDeveloper2.name)
// Billy
// Billy
클래스, 구조체가 값을 저장하고 있는 프로퍼티
값을 저장하진 않고 기존 stored property 활용하거나 특정값 전달할 때 사용하는 프로퍼티
struct Watch {
let model: String
let manufacturer: String
var description: String {
return "\(model) by \(manufacturer)"
}
}
struct Person {
let firstName: String
let lastName: String
var fullName: String {
return "\(firstName) \(lastName)"
}
}
let appleWatch = Watch(model: "Watch 7", manufacturer: "Apple")
print(appleWatch.description)
// Watch 7 by Apple
let jason = Person(firstName: "Jason", lastName: "Lee")
print(jason.fullName)
// Jason Lee
제공하고 싶은 역할-기능,속성을 미리 정의해 놓은 것
(반장의 역할)
다른 타입이 해당 프로토콜 역할 제공하려면 conform 준수해서, 따라서 제공한다.
protocol Coach {
var name: String { get set }
var currentTeam: String { get }
func training()
func direct()
}
struct Mourinho: Coach {
var name: String = "Jose Mourinho"
var currentTeam: String = "AS Roma"
func training() {
print("Traing Player")
}
func direct() {
print("Direct Game")
}
}
let mourinho = Mourinho()
print("\(mourinho.name), \( mourinho.currentTeam)")
mourinho.training()
mourinho.direct()
// Jose Mourinho, AS Roma
// Traing Player
// Direct Game
기존 타입에 새로운 역할-기능,속성을 추가하고 싶을 때 사용한다.
extension String {
func contains(s: String) -> Bool {
return self.range(of: s) != nil
}
func replace(target: String, with: String) -> String {
return self.replacingOccurrences(of: target, with: with)
}
}
let testString = "Hello iOS Developer!!"
let replaced = testString.replace(target: "Hello", with: "안녕하세요")
print(replaced)
// 안녕하세요 iOS Developer!!
print(testString.contains(s: "iOS"))
// true