본문 바로가기

Programming

SWIFT UI study #2 기초 문법

이번 포스팅은 야곰님의 swift 기초문법강좌 정리입니다.
저의 개인공부를 위한 간단한 내용 위주의 정리이니 자세한 설명이 필요하신 분들은 아래의 링크를 참조해주세요.
https://www.youtube.com/watch?v=2n-fSlW-jts&list=PLz8NH7YHUj_ZmlgcSETF51Z9GSSU6Uioy


14. 값 타입과 참조 타입
값(value): 데이터를 전달할 때 값을 복사하여 전달
참조(reference) : 데이터를 전달할 때 값의 메모리 위치를 전달
Class: 전통적인 OOP관점에서의 클래스, 참조타입, Apple 프레임워크의 대부분 큰 뼈대는 모두 클래스로 구성.
Struct: 상속 불가, 값 타입, SWIFT의 큰 뼈대는 대부분 Struct로 구성.
Enum: 열거형 자체가 하나의 데이터 타입이며, case 하나하나가 유의미한 값으로 취급.
구조체는 언제 사용하나? 참조가 아닌 복사를 원할 때, 상속이 필요가 없을 때

SWIFT loves Struct! 

15. 클로저 (closure)
코드의 블럭,
함수는 이름이 있는 클로저라고 보면 됨.
{ (매개변수 목록) -> 반환타입 in 
실행코드
}

var sum: (Int, Int) -> Int = { (a: Int, b: Int) -> Int in 
  return a + b
}
var sumResult: Int 
sumResult = sum(1,2)

sum 변수에는 함수도 할당할 수 있음. 
함수의 전달인자로 자주 활용됨.

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: sum)

후행클로저: 클로저가 함수의 마지막 전달인자라면 마지막 매개변수의 이름을 생략한 후 함수의 소괄호 외부에 클로저를 구현할 수 있음

calculated = calculate(a: 10, b:10, method: sum) //는 아래와 같은 표현
calculated = calculate(a: 10, b: 10) { (left:Int, right:Int) -> Int in 
 return left+right
} // 후행클로저
calculated = calculate(a: 10, b: 10, method: {(left:Int, right:Int) in 
 return left+right
}) // 반환타입 생략 가능
calculated = calculate(a: 10, b: 10) { (left:Int, right:Int) in 
 return left+right
} // 후행클로저에서도 반환타입 생략 가능
calculated = calculate(a: 10, b:10, method: {
 return $0 + $1
}) // 매개변수 생략 후 단축인자 사용 가능, 매개변수의 순서대로 $를 붙여 표현
calculated = calculate(a: 10, b:10) {
 return $0 + $1
} // 후행클로저에서의 단축인자 활용
calculated = calculate(a: 10, b:10) {
 $0 + $1
} // 암시적 반환
calculated = calculate(a: 10, b:10) { $0 + $1 } // 간결하게 한 줄로 표현 가능

 

16. 프로퍼티 Property
프로퍼티는 구조체, 클래스, 열거형 내부에 구현할 수 있으며, 
열거형 내부에는 연산 프로퍼티만 구현할 수 있음.
연산 프로퍼티는 var로만 선언할 수 있음.

저장 프로퍼티: 값들을 저장하기 위한 프로퍼티
연산 프로퍼티: 값을 연산을 해서 저장하는 프로퍼티 (get or set)
타입 저장 프로퍼티
읽기전용 연산 프로퍼티 (get 함수만 구현)
읽기전용 타입 연산 프로퍼티

17. 프로퍼티 감시자 Property Observer
willSet: 값이 바뀌기 직전 호출
didSet: 값이 바뀐 직후 호출

18. 상속
class 이름: 상속받을 클래스 이름 {
 // implementation
}
final func: 자식클래스에서 재정의 불가능
static func: 자식클래스에서 재정의 불가능
class func: 자식클래스에서 재정의 가능
final class func: static과 같은 동작
override func: 부모의 메서드 재정의

19. 인스턴스의 생성과 소멸
스위프트의 모든 인스턴스는 초기화 시 모든 프로퍼티에 값이 할당되어야 함.
기본값 할당 혹은 이니셜라이저(init) 활용
초기값이 필요없을 시에는 옵셔널을 활용
! 옵셔널 (암시적 옵셔널)의 경우 이니셜라이즈 이후 반드시 설정해줘야함
init? 을 통해서 이니셜라이즈 실패 시 nil이 반환되게 할 수 있음.
deinit을 통해서 메모리에서 인스턴스가 해제되는 시점에 해야할 일 구현 가능. 

20. 옵셔널 체인징과 nil 병합 연산자
옵셔널 체이닝은 옵셔널 연속 내부의 프로퍼티로 또 다른 옵셔널이 연속적으로 연결되는 경우 활용.
if let guardJob = owner?.home?.guard?.job { print("경비원의 직업은 \(guardJob}입니다") }
nil 병합 연산자 ??: 결과가 nil이라면 값을 넣어준다.
e.g., guardJob = owner?.home?.guard?.job ?? "슈퍼맨" 

21. 타입캐스팅
인스턴스의 타입을 확인하는 용도: is, as를 활용.
e.g., Person, Student이라는 클래스가 있고 yagom이라는 instance가 있다면
yagom is Person // true
yagom is Student // false
업캐스팅
as를 이용하여 부모의 인스턴스로 활용할 수 있음.
var Mike: Person = Student() as Person
다운캐스팅
var optionalCasted: Student?
optionalCasted = mike as? Student // Student로 정의가 되었었기 때문에 호출가능. 만약 Person으로 정의되었다면 불가능 
optionalCasted = mike as! Student // 강제 다운캐스팅. 

22. assert와 guard
assert: 조건의 검증, 디버깅 모드에서만 동작함.
assert( someInt == 0, "someInt != 0") // 조건이 아닐 때 에러를 내고 출력됨.
guard를 사용하면 잘못된 값 전달 시 에러이전에 특정 실행구문을 빠르게 종료해줌.
guard let unwrappedAge = age else { return }

23. 프로토콜 protocol
특정 역할을 수행하기 위한 메서드 프로퍼티 이니셜라이저 등의 요구사항을 정의.
프로토콜의 요구사항을 충족시키려면 프로토콜이 제시하는 기능을 모두 구현해야 함.
protocol 프로토콜 이름 {
  //프로토콜 정의
  var topic: String {get set}
  func talk()
  init(topic: String)
}
채택하는 방법
struct Person: 프로토콜 이름 {
  var topic: String {
   get { return self.topic } 
   set { self.topic = newValue }
  }
  funk talk() {구현 }
  init(topic: String) { 구현 }
}
프로토콜은 다중 상속이 가능함.
protocol 이름: 프로토콜 이름1, 프로토콜 이름 2 { 구현 }
클래스에서 상속 시, 클래스 먼저 상속 후 프로토콜 적어주기.
프로토콜 이름을 준수하는 지 확인: is or as
e.g., 이름 is 프로토콜 이름 // true of false 

24. 익스텐션 
다양한 타입에 새로운 기능을 추가할 수 있는 기능.
기존 기능 재정의는 불가함
extension 확장할 타입 {
  타입에 추가될 기능 구현
}
e.g.,
extension Int {
  var isEven: Bool { return self %2 == 0 }
}

25. 오류처리
Error 프로토콜과 enum을 통해서 오류를 표현함.
enum 오류종류이름: Error {
  case 종류1
  case 종류2
}
throw 오류종류이름.종류1 으로 오류를 던짐.
오류발생의 여지가 있는 throws함수 호출 시에는 반드시 try를 사용함.
do-catch문을 활용함
do {
  try throw여지가 있는 함수
} catch 종류1 {
  실행문
} catch 종류2 {
  실행문
}
혹은 간략하게 표현하고자하면
do {
  try throw여지가 있는 함수
} catch {
  실행
}
더 간단하게는?
try? 함수 // 오류 발생시 nil 반환

26. 고차함수
전달인자로 함수를 전달받거나 함수실행결과를 함수로 반환하는 함수
map, filter, reduce
map: 기존데이터를 변형하여 새로운 컨테이너 생성
doubledNumbers = numbers.map({ (number: Int) -> Int in return number*2 })
doubledNumbers = numbers.map { $0 * 2 }
filteredNumbers = numbers.filter { $0 % 2 != 0 }
reducedNumbers = numbers.reduce(0) {$0 + $1 }