버튼 추가
버튼 클릭시, 새로운 알럿 띄우기
새로운 버튼 추가 하기
뷰컨트롤러에 버튼 액션 연결하기
메소드 새로 추가하기
표현방식
{(인자들) -> 반환타입 in 로직 구현}
#Inline Closure 예시
le reverseNames = names.sorted(by: {(s1:String, s2:String) -> Bool in return s1>s2})
코드의 동작의 흐름을 주로 조절할 때 사용
코드를 건너뛰는 상황 or 반복적으로 코드 돌릴때
예)
# 조건 > 코드수행 > 조건 > 코드수행
print("--- While")
var i = 0
while i < 10 {
print(i)
i+=1
}
# 코드수행 > 조건 > 코드수행 > 조건
print("---Repeat")
i = 0
repeat{
print(i)
i+=1
} while i< 10
# 반복적으로 코드 수행
print("----for loop")
# 10 포함 됨
let closedRange = 0...10
# 10 포함 안됨
let halfClosedRange = - ..<10
var sum =0
for i in closedRange {
print("-----> \(i)")
sum += i
}
print("----> total sum : \(sum)")
#근간이 되는 놈들이 모아져 있는 곳
import Foundation
# 사인 그레프
var sinValue: CGFloat = 0
for i in closedRange {
sinValue = sin(CGFloat.pi/4 * CGFloat(i))
}
let name = "Jason"
# 쓰지않는 변수를 대체로 _ 이것을 사용
for _ in closedRange {
print("---> name \(name)")
}
for i in closedRange{
if i % 2 == 0 {
print("----> 짝수 : \(i)")
}
}
for i in closedRange where i%2==0 {
print("----> 짝수 : \(i)")
}
for i in closedRange {
if i == 3 {
continue
}
print("---->\(i)")
}
for i in closedRange where i!=3 {
print("----> 3아닌 숫자 : \(i)")
}
# 이중 중첩은 효율성이 떨어지기때문에 가급적 x
for i in closedRange {
for j in closedRange {
print("gugudun -> \(i) *\(j) = \(i*j)")
}
}
let num = 10
switch num {
case 0 :
print("---> 0입니다. " )
case 0...10 :
print("---> 0 10 사이 입니다. " )
case 10 :
print("---> 10입니다. " )
default :
print("----> 나머지입니다.")
}
let pet = "bird"
case "dog","cat","bird" :
print("---> 집동물이네요? ")
default :
print("---> 잘 모르겠습니다. " )
}
let num = 5
switch num {
case _ where num%2==0 :
print("--->짝수")
default :
print("--->홀수")
}
let coordinate = (x:10, y:10)
switch coordinate{
case (0,0):
print("---> 원점 이네요")
case (_,0):
print("---> x축 이네요")
case (0,_):
print("---> y축 이네요")
default :
print("---> 좌표 어딘가")
}
let coordinate = (x:10, y:10)
switch coordinate{
case (0,0):
print("---> 원점 이네요")
case (let x,0):
print("---> x축 이네요,x:\(x)")
case (0,let y):
print("---> y축 이네요,y:\(y)")
case (let x, let y) where x ==y :
print("---> x,y와 같음 = \(x),\(y)")
case (let x, let y) :
print("---> 좌표 어딘가 x,y = \(x),\(y)")
}
method는 object에 속해서 기능을 수행하는 반면에
function은 독립적으로 호출이 가능
import UIKit
func printName(){
print("---> My name is Jason")
}
printName()
# param 1개 ( 파라미트 1개)
# 숫자를 받아서 10을 곱해서 출력한다.
func printMultipleOfTen(value : Int) {
print("\(value) * 10 = \(value *10) ")
}
printMultipleOfTen(value : 5)
# param 2개
# 물건값과 갯수를 받아서 전체 금액을 출력하는 함수
func printTotalPrice(price: Int, count: Int) {
print("Total Price : \(price * count)")
}
printTotalPrice(price:1500, count:5)
func printTotalPrice(가격 price: Int,갯수 count: Int) {
print("Total Price : \(price * count)")
}
printTotalPrice(가격:1500, 갯수:5)
#### price를 default로 하고 싶을 때
func printTotalPriceWithDefaultValue(price: Int = 1500, count: Int) {
print("Total Price : \(price * count)")
}
printTotalPriceWithDefaultValue(count : 5)
printTotalPriceWithDefaultValue(count : 10)
printTotalPriceWithDefaultValue(count : 7)
printTotalPriceWithDefaultValue(count : 1)
# price의 가격을 바꾸고 싶으면 이렇게 사용
printTotalPriceWithDefaultValue(price : 2000, count : 1)
####
func totalPrice(price: Int, count : Int) -> Int {
let totalPrice = price * count
return totalPrice
}
let calculatedPrice = totalPrice(price:10000, count : 77)
calculatedPrice
# 도전 문제
import UIKit
# 성,이름을 받아서 fullname을 출력하는 함수 만들기
func FullName(frist : String, name : String){
let fullname = frist+name
print(fullname)
}
FullName(frist:"이", name:"하연")
func printFullName(fristName : String, lastName : String){
print("fullname is \(fristName)\(lastName)")
}
printFullName(firstName:"하연",lastName:"이")
# 1번에서 만든 함수인데, 파라미터 이름을 제거하고 fullname 출력하는 함수 만들기
func FullName(_ frist : String, _ name : String){
print("fullname is \(frist)\(name)")
}
FullName("이","하연")
# 성,이름을 받아서 fullname을 return하는 함수 만들기
func FullName(frist : String, name : String) -> String {
return "\(frist) \(name)"
}
let fullname =FullName(frist : "이", name:"하연")
fullname
func printTotalPrice(price: Int, count : Int){
print(" Total Price : \(price * count) ")
}
func printTotalPrice(price: Double, count : Double){
print(" Total Price : \(price * count) ")
}
func printTotalPrice(가격: Int, 개수 : Int){
print(" 총 가격은 : \(가격 * 개수) ")
}
파라미터로 들어온 변수를 변경하고 싶을 경우에 in-out 키워드 사용 (copy in , copy out)
var value = 3
func incrementAndPrint(_ value : inout Int){
value += 1
print(value)
}
incrementAndPrint(&value)
fun add ( _a : Int, _b : Int) -> Int {
return a+b
}
fun subtract( _a : Int , _b : Int ) -> Int {
return a-b
}
# 함수자체를 변수로 할당
var function = add
function(4,2)
function = subtract
function(4,2)
func printResult(_ function: (Int,Int)->Int, _a:Int,_b:Int){
let result = function(a,b)
print(result)
}
printResult(add,10,5)
printResult(subtract,10,5)
존재하지 않음 : nil
import UIKit
var carName : String? = "Tesla"
var penilName : String?
penilName = nil
penilName = "signal"
// 과제1: 여러분이 최애하는 영화배우의 이름을 담는 변수를 작성해주세요 ( 타입 String?)
var actorName : String?= nil
actorName = "전지현"
// 과제2: let num = Int("10") -> 타입은 뭘까요?
타입 : Int
let num = Int("10hi")
타입 : nil
var carName : String?
carName = nil
carName = "땡크"
결과 : Optional("땡크")
이유 : 박스 안에 value가 있는 형태
내가 원하는 거 : 박스 안의 value만 추출 하고 싶음
-> print(carName!)
if let unwrappedCarName = carName {
print(unwrappedCarName)
}else{
print("Car Name 없다")
}
func printParsedInt(from : String) {
if let paredInt = Int(from) {
print(paredInt)
//if else ... 계속 하게 되면
// Cyclomatic Complexity 됨
} else{
print("Int로 컨버팅 안된다")
}
}
//printParsedInt(from : "100") // if
printParsedInt(from: "헬로우 마이네미이즈") // else
func printParsedInt(from : Stinrg){
guard let parsedInt = Int(from) else{
print("Int로 컨버팅 안된다" )
return
}
print(parsedInt)
}
printParsedInt(from: "헬로우 마이네미이즈")
let myCarName: String = carName ?? "모델 S"
-> 이 경우는 값이 없으니 디폴트 값인 모델 S로 나옴
carName = "모델 3"
let myCarName: String = carName ?? "모델 S"
-> 이 경우는 있으니까 모델 3으로 나옴
let favoriteFood : String? = "한우"
if let foodName = favoriteFood {
print(foodName)
else{
print("좋아하는 음식 없음")
}
func printNicName(name: Stinrg?){
guard let nickName = name else{
print("nickname 만들어 보자")
return
}
print(nickName)
}
//printNicName(name: "하연닉네임")
printNicName(name: nil)
Rule 규칙!
1. 통에 담을 때에는 같은 타입으로 담아야 함
2. element 들은 순서가 있음
When 언제?
1. 순서가 있는 아이템
2. 아이템의 순서를 알면 유용할 때
import UIKit
// var evenNumbers: [Int] = [] // 통에 아무것도 없을 경우
var evenNumbers : [Int] = [2,4,6,8]
// var evenNumbers : Array<Int> = [2,4,6,8] // 이렇게 써도 됨
evenNumbers.append(10)
evenNumbers += [12.14.16]
evenNumbers.append(contentsOf : [18,20])
let isEmpty = evenNumbers.isEmpty // type : Boolean
evenNumbers.count // 통 안의 갯수
print(evenNumbers.first)
// 이게 Optional(2)로 나옴
// 이유는 아래에서 설명
evenNumbers = []
let firstItem = evenNumbers.first // 타입 확인하면 Int? 로 나옴
// 그래서 first 값이 있을 수도 없을 수도 있으므로 옵셔널
if let firstElement = evenNumbers.first {
print("---> first item is : \(firstElement)")
}
// 대소 비교가 가능한 경우 -> 이 경우도 있을수도 없을수도 있으므로 옵셔널
evenNumbers.min()
evenNumbers.max()
var firstItem = evenNumbers[0]
var secondItem = evenNumbers[1]
var tenthIten = evenNumbers[9]
let firstThree = evenNumbers[0...2] // 결과 : [2,4,6]
evenNumbers.contains(3) // false
evenNumbers.contains(4) // true
evenNumbers.insert(0,at: 0) // 0번째에 0삽입
evenNumbers.removeAll() // 모두 삭제
evenNumbers = [] // 모두 삭제
evenNumbers.remove(at:0) // 0번째 삭제
evenNumbers[0] = -2 // 0번째 원소를 -2로 변경
evenNumbers[0...2] = [-2,0,2] // 0~2번째 원소를 차례대로 -2,0,2로 변경
evenNumbers.swapAt(0,9) // 0번째와 9번째 원소들이 서로 swap
for num in evenNumbers {
print(num)
}
for (index,num) in evenNumbers.enumerated(){
print("idx: \(index), value : \(num) ")
}
// dropFirst는 본체에 영향을 주지 않고 제거하여 나머지 리턴(반환)
let firstThreeRemoved = evenNumbers.dropFirst(3) // 앞에서 3개를 제거한 후 리턴
let lastRemoved = evenNumbers.dropLast() // 뒤에꺼 제거한 후 리턴
// 앞에 3개만 가져오기
let firstThree = evenNumbers.prefix(3)
// 뒤에 3개만 가져오기
let lastThree = evenNumbers.suffix(3)
import UIKit
// var scoreDic : Dictionary<String,Int> = ["Jason":80,"Jay":95, "Jake":90]
var scoreDic : [String : Int] = ["Jason":80,"Jay":95, "Jake":90]
if let score = scoreDic["Jason"] {
score
} else {
// ... score 없음
}
scoreDic["Jay"]
scoreDic["Jerry"]
//scoreDic = [:] // 빈 깡통
scoreDic.isEmpty // 빈 깡통
scoreDic.count // 개수
// 기존 사용자 업데이트
scoreDic["Jason"] = 99
// 사용자 추가
scoreDic["Jack"] = 100
// 사용자 제거
scoreDic["Jack"] = nil
// For Loop
for (name,score) in scoreDic {
print("\(name), \(score)")
}
// key 출력하는 순서는 고정되지 않음 -> 딕셔너리는 순서 고정 x
for key in scoreDic.keys {
print(key)
}
// 1. 이름, 직업, 도시에 대해서 본인의 딕셔너리 만들기
var myDic : [String :String] = ["이름":"하연", "직업":"학생","도시":"안산"]
// 2. 여기서 도시를 부산으로 업데이트 하기
myDic["도시"] = "부산"
// 3. 딕셔너리를 받아서 이름과 도시 프린트하는 함수 만들기
fucn printDic(dic: [String:String]){
if let name = dic["이름"] , let city = dic["도시"]{
print(name,city)
}
else{
print("--> Cannot find")
}
}
printDic(dic : myDic)
import UIKit
var someArray : Array<Int> = [1,2,3,1]
// [1,2,3,1]
var someSet : Set<Int> = [1,2,3,1]
// [1,2,3]
someSet.isEmpty
someSet.count
someSet.contains(4) //boolean : false
someSet.insert(5)
someSet.remove(1)
import UIKit
var multiplyClosure : (Int, Int) -> In ={ (a:Int,b:Int)->Int in
return a * b
}
// 위에 꺼를 줄일 수 잇음
var multiplyClosure : (Int, Int) -> In ={ $0 * $1 }
// 하지만 너무 줄이면 의미를 모르므로 아래가 가장 적당
var multiplyClosure : (Int, Int) -> In ={ a * b in
return a * b
}
var addClosure:(Int,Int) -> Int = {a,b in
return a+b
}
let result = multiplyClosure(4,2)
func operateTwoNum(a:Int,b:Int,operation : (Int,Int)->Int) -> Int {
let result = operation(a,b)
return result
}
operateTwoNum(a:4,b:2,operation:multiplyClosure)
operateTwoNum(a:4,b:2,operation:addClosure)
operateTwoNum(a:4,b:2){ a,b in
return a/b
}
let voidClosure : () -> void = {
print("iOS 개발자 짱, 클로저 사랑해")
}
voidClosure()
// Capturing Values
var count = 0
let incrementer = {
// count가 밖에 있는데 참조되서 사용됨
count += 1
}
incrementer()
incrementer()
incrementer()
incrementer()
count
swift 공식 사이트 : docs.swift.org
협업을 할 때 관계있는 것끼리 묶어서 표현하여 "가독성"이 높아지며 "재사용성" 높아짐
관계가 있는 것들을 묶어서 표현
Object = Data + Method
Object -> Structure vs Class 동작이 다름 <- 메모리 공간 차이가 있음
-
// 문제 : 가장 가까운 편의점 찾기
// 맨처음 시작시 ... 코드
// 현재 스토어 위치들
let store1 = (x:3,y:5,name:"gs")
let store2 = (x:4,y:6,name:"seven")
let store3 = (x:1,y:7,name:"cu")
// 거리 구하는 함수
func distance(current: (x:Int,y:Int), target: (x:Int,y:Int) -> Double {
// 피타고라스..
let distanceX = Double(target.x - current.x)
let distanceY = Double(target.y - current.y)
let distance = sqrt(distanceX*distanceX + distanceY*distanceY)
return distance
}
// 가장 가까운 스토어 구해서 프린트하는 함수
func printClosestStore(currentLocation(x: Int, y: Int), store: [(x:Int,y:Int,name:String)]) {
var closestStoreName = ""
var closestStoreDistance = Double.infinity
for store in stores {
let distanceToStore = distance(current: currentLocation, target:(x:store.x, y:store.y))
closestStoreDistance = min(distanceToStore, closeStoreDistance)
if closestStoreDistance == distanceToStore {
closestStoreName = store.name
}
}
print("Closest store : \(closestStoreName)")
}
// Stores Array 세팅, 현재 내 위치 세팅
let myLocation = ( x:2, y:2 )
let stores = [store1, store2, store3]
// printClosestStore 함수이용해서 현재 가장 가까운 스토어 출력하기
printClosestStore(currentLocation: myLocation, stores: stores)
// Improve Code
// - make Location struct
// - make Store struct
// 문제 : 가장 가까운 편의점 찾기
// 맨처음 시작시 ... 코드
struct Location {
let x: Int
let y: Int
}
// 현재 스토어 위치들
let store1 = (loc: Location(x:3,y:5),name:"gs")
let store2 = (loc: Location(x:4,y:6),name:"seven")
let store3 = (loc: Location(x:1,y:7),name:"cu")
// 거리 구하는 함수
func distance(current: Location, target: Location ) -> Double {
// 피타고라스..
let distanceX = Double(target.x - current.x)
let distanceY = Double(target.y - current.y)
let distance = sqrt(distanceX*distanceX + distanceY*distanceY)
return distance
}
// 가장 가까운 스토어 구해서 프린트하는 함수
func printClosestStore(currentLocation : Location, store: [(loc:Location,name:String)]) {
var closestStoreName = ""
var closestStoreDistance = Double.infinity
for store in stores {
let distanceToStore = distance(current: currentLocation, target:store.loc)
closestStoreDistance = min(distanceToStore, closeStoreDistance)
if closestStoreDistance == distanceToStore {
closestStoreName = store.name
}
}
print("Closest store : \(closestStoreName)")
}
// Stores Array 세팅, 현재 내 위치 세팅
let myLocation = Location( x:2, y:2 )
let stores = [store1, store2, store3]
// printClosestStore 함수이용해서 현재 가장 가까운 스토어 출력하기
printClosestStore(currentLocation: myLocation, stores: stores)
// Improve Code
// - make Location struct
// - make Store struct
// 문제 : 가장 가까운 편의점 찾기
// 맨처음 시작시 ... 코드
// 거리 구하는 함수
func distance(current: Location, target: Location ) -> Double {
// 피타고라스..
let distanceX = Double(target.x - current.x)
let distanceY = Double(target.y - current.y)
let distance = sqrt(distanceX*distanceX + distanceY*distanceY)
return distance
}
struct Location {
let x: Int
let y: Int
}
struct Store {
let loc : Location
let name : String
let deliveryRange = 2.0
func isDeliverable(userLoc : Location) -> Bool {
let distanceToStore = distance(current : userLoc, target : loc)
return distanceToStore < deliveryRange
}
}
// 현재 스토어 위치들
let store1 = Store(loc: Location(x:3,y:5),name:"gs")
let store2 = Store(loc: Location(x:4,y:6),name:"seven")
let store3 = Store(loc: Location(x:1,y:7),name:"cu")
// 가장 가까운 스토어 구해서 프린트하는 함수
func printClosestStore(currentLocation : Location, store: [Store]) {
var closestStoreName = ""
var closestStoreDistance = Double.infinity
var isDeliverable = false
for store in stores {
let distanceToStore = distance(current: currentLocation, target:store.loc)
closestStoreDistance = min(distanceToStore, closeStoreDistance)
if closestStoreDistance == distanceToStore {
closestStoreName = store.name
isDeliverable = store.isDeliverable(userLoc: currentLocation)
}
}
print("Closest store : \(closestStoreName)")
}
// Stores Array 세팅, 현재 내 위치 세팅
let myLocation = Location( x:2, y:2 )
let stores = [store1, store2, store3]
// printClosestStore 함수이용해서 현재 가장 가까운 스토어 출력하기
printClosestStore(currentLocation: myLocation, stores: stores)
// Improve Code
// - make Location struct
// - make Store struct
class PersonClass {
var name : String
var age : Int
init(name : String, age: Int){
self.name = name
self.age = age
}
}
struct PersonStruct {
var name : String
var age : Int
init(name : String, age: Int){
self.name = name
self.age = age
}
}
### 동작 차이
## pClass1이랑 pClass2랑 같은 인스턴스를 가리키니까 둘 다 이름이 변경
let pClass1 = PersonClass(name:"Jason",age:5)
let pClass2 = pClass1
pClass2.name = "Hey"
pClass1.name // Hey
pClass2.name // Hey
## pStruct1, pStruct2는 서로 남남이기 때문에 2만 바뀌고 1은 그대로
ver pStruct1 = PersonStruct(name:"Jason",age:5)
ver pStruct2 = pStruct1
pStruct2.name = "Hey"
pStruct1.name // Jason
pStruct2.name // Hey
struct Lecture{
let name : String
let instructor: String
let numOfStudent : Int
}
func printLectureName(from instructor : String, lecture: [Lecture]){
var lectureName = ""
for lecture in lectures {
if instructor == lecture.instructor {
lectureName = lecture.name
}
}
// Closer 람다식
//let lectureName = lectures.first{(lec)-> Bool in retrun lec.instructor == instructor
//}?.name
print(" 아 그 강사님 강의는요 : \(lectureName)")
}
let lec1 = Lecture(name : "iOS Basic", instructor : "Jason", numOfStudent : 5)
let lec2 = Lecture(name : "iOS Advanced", instructor : "Jack", numOfStudent : 5)
let lec3 = Lecture(name : "iOS Pro", instructor : "Jim", numOfStudent : 5)
let lectures = [lec1, lec2, lec3]
printLectureName(from: "Jack",lectures: lectures)
struct Person{
var firstName : String {
// 이러한 observation 같은 경우에는 값이 셋팅이 나서 observation 할 수도 있고 값 셋팅 직전에 할 수도 있음 -> 근데 이건 didSet이 아니라 willset을 이용하여 가능
// willSet이 먼저 , didSet이 다음
willSet {
print("willSet : \(firstName) ---> \(newValue)")
}
didSet {
print("didSet : \(oldValue) ---> \(firstName)")
}
}
var lastName : String
# lazy property
lazy var isPopular : Bool = {
if fullName == "Jay Park" {
return true
}
else{
retrun false
}
}()
# 이건 Computed Property 예시 : 기존에 있던 firstNmae이랑 lastName 의 조합으로 fullName이 탄생
# 실제로 어떤 값을 저장하지 않고 있는 값 가지고 그냥 가져다가 새로 조합해서 어떠한 값을 넘겨주는 것
var fullName : String {
# firstName이랑 lastName처럼 관계가 형성이 되 있는 경우 셋팅 하면 좋지
# get{}set{} 는 둘의 관계를 셋팅 가능하게 하는 것을 도와줌
get {
return "\(firstName) \(lastName)"
}
set {
// newValue "Jay Park"
if let firstName = newValue.components(seperatedBy : " ").first{
self.firstName = firstName
}
if let lastName = newValue.components(seperatedBy: " ").last {
self.lastName = lastName
}
}
}
// 타입 프로퍼티
static let isAlien : Bool = false
}
# 이것들은 인스턴스를 만든 거
var person = Person(firstName: "Jason", lastName: "Lee")
person.firstName // Jason
person.lastName // Lee
person.firstName = "Jim"
person.lastName = "Kim"
person.firstName // Jim
person.lastName // Kim
person.fullName // "Jim Kim"
person.fullName = " Jay Park"
person.firstName // Jay
person.lastName // Park
# 여기까지 인스턴스 만든 거
# 이건 인스턴스가 아니라 타입자체에 있는 프로퍼티
# 인스턴스와 상관없음
Person.isAllen
person.isPopuler // True
어차피 결과를 똑같음
Property : 호출시 (저장된) 값을 하나 반환
Method : 호출시 어떤 작업을 한다
근데 만약에 Method가 그냥 값을 리턴하는 작업을 한다면요?
struct Person{
var firstName : String {
willSet {
print("willSet : \(firstName) ---> \(newValue)")
}
didSet {
print("didSet : \(oldValue) ---> \(firstName)")
}
}
var lastName : String
# lazy property
lazy var isPopular : Bool = {
# 프로퍼티일 경우
if fullName == "Jay Park" {
# 메소드일 경우
// if fullName() == "Jay Park" {
return true
}
else{
retrun false
}
}()
// 실습 1의 computed property보다 간략하게
// property일 경우
var fullName : String {
return "\(firstName) \(lastName)"
}
// Method fullName()
func fullName() -> String{
return "\(firstName) \(lastName)"
}
// 타입 프로퍼티
static let isAlien : Bool = false
}
# 이것들은 인스턴스를 만든 거
var person = Person(firstName: "Jason", lastName: "Lee")
# property의 경우
person.fullName
# method의 경우
person.fullName()
import UIKit
struct Lecture{
var title : String
var maxStudents: Int = 10
var numOfRegistered: Int = 0
}
var lec = Lecture(title: " iOS Basic")
func remainSeats(of lec: Lecture) -> Int {
let remainSeats = lec.maxStudents - lec.numOfRegistered
return remainSeats
}
remainSeats(of:lec)
import UIKit
struct Lecture{
var title : String
var maxStudents: Int = 10
var numOfRegistered: Int = 0
func remainSeats() -> Int {
let remainSeats = maxStudents - numOfRegistered
return remainSeats
}
// 구조체 안에서 수정이 이루어져있으므로 mutating 선언
mutating func register(){
// 등록된 학생수 증가시키기
numOfRegistered += 1
}
// 타입 프로퍼티
static let target: String = "Anybody want to learn something"
// 타입 메소드
static func 소속학원이름() -> String{
return "패캠"
}
}
var lec = Lecture(title: " iOS Basic")
lec.remainSeats() // 10
lec.register()
lec.remainSeats() // 9
Lecture.target
Lecture.소속학원이름()
struct Math{
static func abs(value: Int) -> Int {
if value > 0 {
return value
}else{
return -value
}
}
}
Math.abs(value: -20)
// 확장을 시킨다.
// Math에서 추가적으로 이런 타입들을 사용하고 싶을 때
// 제곱, 반값
extension Math{
static func sqaure(value: Int) -> Int {
return value * value
}
static func half(value: Int) -> Int {
return value / 2
}
}
Math.square(value : 5)
Math.half(value : 20)
var value: Int = 3
# Int 같은 경우는 개발자가 만들어 놓은 거기 때문에 함부로 건들지 못하고 extension을 이용하면 가능?
# 내가 원하는 기능들을 추가해서 수행가능
extension Int {
func square() -> Int {
return self * self
}
func half() -> Int {
return self/2
}
}
value.sqaure() // 9
value.half() // 1
mutating 란 : 구조체의 매서드가 구조체 내부에서 데이터 수정 할떄는 Mutating키워드를 선언 해주어야함
struct PersonStruct{
var firstName : String
var lastName : String
var fullName: String{
return "\(firstName) \(lastName)"
}
mutating func uppercaseName(){
firstName = firstName.uppercased()
lastName = lastName.uppercased()
}
}
# 위 구조체를 클래스로 변경
Class PersonClass{
var firstName : String
var lastName : String
# class 객체를 생성할 때 사용되는 생성함수 init
init(firstName : String, lastName : String){
self.firstName = firstName
self.lastName = lastName
}
var fullName: String{
return "\(firstName) \(lastName)"
}
// mutating은 class에서 사용하지 않음
func uppercaseName(){
firstName = firstName.uppercased()
lastName = lastName.uppercased()
}
}
var personStruct1 = PersonStruct(firstName: "Jason", lastName : "Lee")
var personStruct2 = personStruct1
var personClass1 = PersonClass(firstName: "Jason", lastName : "Lee")
var personClass2 = personClass1
personStruct2.firstName = "Jay"
personStruct1.firstName // Jason
personStruct2.firstName // Jay
personClass2.firstName = "Jay"
personClass1.firstName // Jay
personClass2.firstName // Jay
personClass2 = PersonClass(firstName:"Bob", lastName:"Lee")
personClass1.firstName // Jay
personClass2.firstName // Bob
personClass1 = personClass2
personClass1.firstName // Bob
personClass2.firstName // Bob
Struct vs Class 언제 무엇을 쓸까?
- Struct 사용시
- 1. 두 object를 "같다, 다르다"로 비교해야 하는 경우
- 2. Copy 된 객체들이 독릭적인 상태를 가져야 하는 경우
- 3. 코드에서 오브젝트의 데이터를 여러 스레드 걸쳐 사용할 경우 안전함
왠만한 object는 struct로 쓰자 -> 그러다 나중에 class로 바꿀 필요성이 있는 게 생기면 바꾸기
swift는 struct 좋아해
stackoverflow보단 공식문서 보자
# 1 번
let point1 = Point(x:3,y:5)
let point2 = Point(x:3,y:5)
# 2 번
var myMac = Mac(owner:"Jason")
var yourMac = myMac
yourMac.owner = "Jay"
myMac.owner
yourMac.owner
struct Grade{
var letter: Character
var points : Double
var points : Double
}
class Person {
var firstName : String
var lastName : String
init(firstName:String,lastName:String){
self.firstName = firstName
self.lastName = lastName
}
func printMyName(){
print("My name is \(firstName) \(lastName)")
}
}
## 학생은 사람이다 ( o ) -> 명제 성립시 상속
## 사람은 학생이다 ( x )
class Student : Person {
var grades : [Grade] = []
}
# 인스턴스 추가
let jay = Person(firstName: " Jay", lastName : "Lee")
let jason = Student(firstName : "Jasson", lastName: "Lee")
jay.firstName
jason.firstName
jay.printMyName()
jason.printMyName()
let math = Grade(letter:"B",points:8.5,credits:3)
let history = Grade(letter:"A",points:10.0,credits:3)
jason.grades.append(contentsOf:math)
jason.grades.append(contentsOf:history)
// jay.grades jay는 사람이지만 학생이 아니므로 접근 불가능
jason.grades.count // 2
Person : Super Class (Parent Class)
Student : SubClass ( Child Class )
struct Grade{
var letter: Character
var points : Double
var points : Double
}
class Person {
var firstName : String
var lastName : String
init(firstName:String,lastName:String){
self.firstName = firstName
self.lastName = lastName
}
func printMyName(){
print("My name is \(firstName) \(lastName)")
}
}
## 학생은 사람이다 ( o ) -> 명제 성립시 상속
## 사람은 학생이다 ( x )
class Student : Person {
var grades : [Grade] = []
}
# 인스턴스 추가
let jay = Person(firstName: " Jay", lastName : "Lee")
let jason = Student(firstName : "Jasson", lastName: "Lee")
jay.firstName
jason.firstName
jay.printMyName()
jason.printMyName()
let math = Grade(letter:"B",points:8.5,credits:3)
let history = Grade(letter:"A",points:10.0,credits:3)
jason.grades.append(contentsOf:math)
jason.grades.append(contentsOf:history)
// jay.grades jay는 사람이지만 학생이 아니므로 접근 불가능
jason.grades.count // 2
// 학생인데 운동선수
class StudentAthelete : Student {
var minimunTrainingTime : Int = 2
var trainedTime : Int = 0
func train(){
trainedTime +=1
}
}
// 운동선수인데 축구선수
class FootballPlayer : StudentAthelete {
var footballTeam = "FC Swift"
override func train(){
trainedTime += 2
}
}
// Person > Student > Athelete > Football Player
var athelete1 = StudentAthelete(firstName : "Yuna" ,lastName : "Kim")
var athelete2 = FootballPlayer(firstName : "Heung" ,lastName : "Son")
athelete1.firstName
athelete2.firstName
athelete1.grades.append(math)
athelete2.grades.append(math)
athelete1.minimumTrainingTime
athelete2.minimumTrainingTime
//athelete1.footballTeam
athelete2.footballTeam
athelete1.train()
athelete1.trainedTime
athelete2.train()
athelete2.trainedTime
athelete1 = athelete2 as StudentAthelete
athelete1.train()
athelete1.trainedTime
if let son = athelete1 as? FootballPlayer{
print("---> team : \(son.footballTeam)")
}
struct Grade{
var letter: Character
var points : Double
var points : Double
}
class Person {
var firstName : String
var lastName : String
init(firstName:String,lastName:String){
self.firstName = firstName
self.lastName = lastName
}
func printMyName(){
print("My name is \(firstName) \(lastName)")
}
}
class Student : Person {
var grades : [Grade] = []
}
// 학생인데 운동선수
class StudentAthelete : Student {
var minimunTrainingTime : Int = 2
var trainedTime : Int = 0
var sports: [String]
init(firstName: String, lastName:String, sports:[String]){
self.sports = sports
super.init(firstName:firstName,lastName:lastName)
}
func train(){
trainedTime +=1
}
}
// 운동선수인데 축구선수
class FootballPlayer : StudentAthelete {
var footballTeam = "FC Swift"
override func train(){
trainedTime += 2
}
}
let student1 = Student(firstName:"Jason",lastName:"Lee")
let student2 = StudentAthlete(firstName:"Jay",lastName:"Lee",sports:["Football"])
Initalization
Inheritance ( 상속 )
상속된 자식 클래스의 경우에도 ( 부모클래스도 마찬가지 ) 생성 시점에는 자신이 가지고 있는 property 뿐만 아니라 부모 클래스가 가지고 있는 property도 값을 세팅해줘야한다.
세팅 순서 : SubClass -> SuperClass
2-phase Initialization : 클래스 생성시 2가지 단계
- Phase1 : 모든 stored property는 이니셜라이즈 되어야 한다.
: 자식 클래스의 property부터 이니셜라이즈 되어야 함
- StudentAthlete(super.init(...),self.sports=...) -> Student -> Person
- Phase1에서 중요한 것은 phase1이 끝나기 전에는 어떤 property나 메소드를 사용 불가능
struct Grade{
var letter: Character
var points : Double
var points : Double
}
class Person {
var firstName : String
var lastName : String
init(firstName:String,lastName:String){
self.firstName = firstName
self.lastName = lastName
}
func printMyName(){
print("My name is \(firstName) \(lastName)")
}
}
class Student : Person {
var grades : [Grade] = []
override init(firstName : String, lastName : String){
super.init(firstName: firstName, lastName: lastName)
}
// 전학생의 경우 그냥 student 받으면 되잖아 -> convenience init
convenience init(student: Student){
self.init(firstName:student.firstName, lastName:student.lastName)
}
}
// 학생인데 운동선수
class StudentAthelete : Student {
var minimunTrainingTime : Int = 2
var trainedTime : Int = 0
var sports: [String]
init(firstName: String, lastName:String, sports:[String]){
# Phase 1
self.sports = sports
super.init(firstName:firstName,lastName:lastName)
# Phase 2
self.train()
}
# convenience 이니셜라이저
convenience init(name: String){
self.init(firstName : name , lastName: "",sports: [])
}
func train(){
trainedTime +=1
}
}
// 운동선수인데 축구선수
class FootballPlayer : StudentAthelete {
var footballTeam = "FC Swift"
override func train(){
trainedTime += 2
}
}
let student1 = Student(firstName:"Jason",lastName:"Lee")
// 서울 학생이 부산으로 전학갈때 그냥 그때의 정보를 넘겨주는 과정
let student1_1 = Student(student:student1)
let student2 = StudentAthlete(firstName:"Jay",lastName:"Lee",sports:["Football"])
# student2 처럼 파라미터가 너무 많아서 싫어! ( 이니셜라이저가 너무 커지는 경우 ) -> 간편하게 할 수 있음 -> convenience 이니셜라이저
let student3 = StudentAthlete(name:"Mike")
: 클래스 안에는 여러가지 이니셜라이저가 있는데 크게 주 이니셜라이저 ( DI ), 부 이니셜라이저 ( CI ) 로 구성되있다. 이때 CI는 다른 이니셜라이저를 호출하게 되어 있다. 최종적으로 CI 는 DI를 궁극에는 불러야 한다.
-> Massive View Controller
중계자에서 해야할 일이 너무 많아질 경우가 발생 ( 뷰컨트롤러의 코드가 많아짐 )
결과적으로는 기술 부채가 발생하는 일이 초래
MVC와 MVVM의 차이점
: MVVM이 MVC와 다른점은