[Swift] Swift / 언어

2022. 8. 16. 12:35🍏/Swift

Swift

Swift 언어가 갖는 구조적 특징
1. 빠름(LLVM compiler)
 -> python의 약 4배

2. 설계수준에서의 안전성 구현
 -> 변수, 상수 선언후 사용 강제. 타입추론 기능으로 초기값 타입 정의 데이터 입력의 안전성
  배열과 정수는 오버플로우 대비 확인, Array bounds check기능 추가
  포인터에 직접 접근하는 시도를 차단, 클래스를 통해 간접적으로만 레퍼런스를 참조할 수 있도록 제한.

3. 옵셔널, 제네릭, 클로져, 튜플등과 같은 현대 프로그래밍 언어의 특성을 갖고있음.

4. 상호반응(interactive)
 -> 플레이그라운드 편집기

5. 완전한 플랫폼
-> 코코아 프레임워크, 코코아 터치 프레임워크의 모든 api를 스위프트로 호출 가능.

6. 통합(unified)
 -> 객체지향 이면서도 자료형과 흐름제어, 연산자 같은 저수준 언어의 기본 요소들도 모두 포함.

 

 

? > Delegate

? > defer
1. defer 블록은 작성된 위치와 순서에 상관없이 함수가 종료되기 직전에 실행
2. defer 블록을 읽기 전에 함수의 실행이 종료될 경우 defer 블록은 실행되지 않는다.
3. 하나의 함수나 메소드 내에서 defer 블록 을 여러번 사용할 수 있다. 이때는 가장 마지막에 작성된 defer 블록부터 역순 실행.
4. defer 블록을 중첩해서 사용할 수 있다. 이때는 바깥쪽 defer 블록부터 실행되며 가장 안쪽에 있는 defer 블록은 가장 마지막에 실행.

 

일급객체로서의 함수
일급 객체 (First-Class Object)
- 프로그램 언어 안에서 특정 종류의 객체가 일급의 지위를 가지는가에 대한 의미.
특성 >
1. 객체가 런타임에도 생성이 가능해야한다.
2. 인자값으로 객체를 전달할 수 있어야한다.
3. 반환값으로 객체를 사용할 수 있어야한다.
4. 변수나 데이터 구조 안에 저장할 수 있어야 한다.
5. 할당에 사용된 이름과 관계없이 고유한 구별이 가능해야 한다.

일급 함수 특성 (1) - 변수나 상수에 함수 대입가능 

func foo(base: Int) -> String {
	return "\(base) !!"
}

let f = foo(base: 55)
// "55 !!"

함수에 대입하면 타입이 함수 타입이 된다. 
함수타입은 일반적으로 함수의 형태를 축약한 형태로 사용하는데, 이때 함수는 이름이나 실행 내용 등은 함수 타입에서는 아무런 의미가 없으므로 생략이 가능하다. 함수 타입에서 필요한 것은 단지 어떤 값을 입력받는지와 어떤 값을 변환하는지 뿐임. 

func boo(i: Int) -> String {
	return "\(i)"
}
(Int) -> String // 형태의 함수 타입

let fn: (Int) -> String = boo // 상수의 타입 어노테이션을 포함한 할당 구문

func boo(i: Int, s: String) -> String {
	return "\(i) \(s)"
}
(Int, String) -> String // 형태의 함수 타입

let fn00 = boo // 어느 함수가 할당될지 몰라서 오류발생.

func poo(a: Int, b: String) -> String {
	return "\(a) \(b)"
}

let s01: (Int, String) -> String = boo // 타입 어노테이션을 통해 입력받을 함수 타입 지정
let s02 = boo(i:s:) // 함수의 식별값을 통해 입력받을 정확한 함수 지정

// 만약 같은 함수타입의 함수를 특정하기 어렵다면 부정확성에 따라 컴파일러는 오류를 발생 시킵니다.
// 그러므로 함수의 식별값을 통해 정확하게 구분해 주어야 합니다.

let s04 = poo(a:b:)

// 함수 타입을 표시할 때 반환값이 없는 경우에는 빈 괄호 대신 'Void'를 사용하여 명시적으로 '값 없음'
// 을 표시하기도 합니다. Void는 빈 튜플을 나타냄. 타입알리어스로 정의된 단어. 클래스나 구조체 등의
// 객체가 아닌 키워드임에 주의해야 한다.

public typealias Void = () // void 키워드를 선언하는 스위프트 내부 코드.

Int -> () == (Int) -> Void
() -> () == () -> Void

 

일급 함수 특성 (2) - 함수의 반환 타입으로 함수를 사용할 수 있음

func desc() -> String {
	return "desc"
}

func pass() -> () -> String {
	return desc
}

let p = pass()
p() // "desc"

func plus(a: Int, b: Int) -> Int {
	return a + b
}

func minus(a: Int, b: Int) -> Int {
	return a - b
}

func times(a: Int, b: Int) -> Int {
	return a * b
}

func divide(a: Int, b: Int) -> Int {
	guard b != 0 else {
    	return 0
    }
	return a / b
}

func calc(_ oper: String) -> (Int, Int) -> Int {
	switch oper {
    case "+" :
    	return plus
    case "-" :
    	return minus
    case "*" :
    	return times
    case "/" :
    	return divide
    default :
    	return plus
    }
}

let c = calc("+")
c(3,4) // plus(3,4) = 7
calc("+")(3,4)

 

일급 함수 특성 (3) - 함수의 인자값으로 함수를 사용할 수 있음

 콜백 함수(Callback Function)
// 특정 구문의 실행이 끝나면 시스템이 호출하도록 처리된 함수. Ajax 통신을 위한 구문을 작성 할 때 
// 콜백함수를 등록. 콜백 함수 등록이란, 실행하고자 하는 구문을 담은 함수를 인자값으로 넣는다는 것을 의미.
// 이때 사용 되는 개념이 일급 함수의 특성인 함수를 인자값으로 사용할 수 있다.
// 그렇게 사용되는 인자값들은 보통 브로커(Broker)라고 한다.
// 함수를 인자로 사용하면 실행 전까지 어떤 구문이 수행될지 컴파일러가 미리 알 수 없으므로 컴파일 시점에서
// 디버깅할 수 없는 단점이 있다. 하지만 잘 활용하면 동적으로 정의되는 훌륭한 함수를 만들 수 있다.
// 그래서 Magic Code 라고 부르는 마법 같은 코드를 작성할 때 자주 응용된다.

 매직 코드(은어)
수 줄 또는 수십 줄의 구문을 작성해야 처리할 수 있는 로직을 불과 한 두 줄의 짧은 구문만으로 구현하는 것

 

함수의 생명주기는 참조 카운트와 관련이 있다. 함수는 참조 카운트가 0에서 1이 되는 순간 생성되어 1이상인 동안 유지 되다가, 0이 되면 소멸하는 과정을 반복. 내부 함수의 생명주기는 전적으로 외부 함수에 의존. 외부 함수가 실행되면서 내부 함수에 대한 참조가 발생하면 생성되고, 외부 함수가 종료되면서 내부 함수에 대한 참조도 종료되면 내부 함수는 소멸한다.

func basic(param: Int) -> (Int)->Int {
	let value = param + 20
	
	func append(add: Int) -> Int {
		return value + add
	}
	return append
}

let result = basic(param: 10) // result는 value값을 30으로 갖고있는 append함수.
print(result(10)) // 40
/// append 함수가 클로저를 갖는다.
/// 1. 클로저는 두 가지로 이루어진 객체. 하나는 내부 함수이며, 또 다른 하나는 내부 함수가 만들어진 주변 환경.
/// 2. 클로저는 외부 함수 내에서 내부 함수를 반환하고, 내부 함수가 외부 함의 지역 변수나 상수를 참조할 때 만들어짐.
/// 클로저란 내부 함수와 내부 함수에 영향을 미치는 주변 환경(Context)을 모두 포함한 객체.
/// 주변 환경이라는 것은 내부 함수에서 참조하는 모든 외부 변수나 상수의 값, 그리고 내부 함수에서 참조하는 다른 객체들 까지를 일컫음. 이를 문맥(Context)라고 한다.
/// 참조가 유지되고 있는 상태라면 클로저에 의해 내부 함수 주변의 지역 변수나 상수도 함께 저장.
/// 정확히는 지역변수의 값이 "저장" 이를 "값이 캡처(Capture)되었다" 라고 표현.