클로저 복습
let mod = { (num1: Int, num2: Int) -> Int in
return num1 % num2
}
print(mod(16, 6))
print(type(of: mod))
/* 실행 결과
4
(Int, Int) -> Int
*/
클로저를 사용하여 저장한 변수나 상수를 호출할 때는 argument label을 사용하지 않는다. 콜론 사용 X
후행 클로저(trailing closure)
후행 클로저란 클로저가 함수의 마지막 argument라면 마지막 매개변수 명을 생략하고 함수 소괄호 외부에 클로저를 작성하는 것이다. 1급 객체의 특성을 이용해 매개변수로 함수를 넣는 경우, argument label을 생략하고 바깥에 중괄호를 사용하여 표현할 수 있다.
func modFunc(num1: Int, num2: Int, fun1: (Int, Int) -> Int) -> Int { // 일반 함수
return fun1(num1, num2)
}
let mod = { (num1: Int, num2: Int, fun1: (Int, Int) -> Int) -> Int in // 클로저
return fun1(num1, num2)
}
// 일반 함수 argument로 클로저 사용
var result = modFunc(num1: 6, num2: 5, fun1: {(n1 : Int, n2 : Int) -> Int in return n1 % n2})
print(result)
result = mod(6, 5, { (n1 : Int, n2 : Int) -> Int in return n1 % n2 }) // 클로저로 argument
print(result)
result = mod(6, 5) { (n1 : Int, n2 : Int) -> Int in // 후행 클로저
return n1 % n2
}
print(result)
/* 실행 결과
1
1
1
*/
첫 번째 result에 있는 함수 호출은 일반 함수인 modFunc()에 argument로 클로저를 사용해서 표현하였다.
두 번째는 argument로 클로저를 사용하고, 해당 함수 안에서 modFunc() 함수를 받아온 매개변수를 이용해 호출한다.
세 번째는 후행 클로저를 이용하여 마지막 argument인 함수를 표현하였다.



func toStr(_ strNum : Int, to num : Int, numFunc : (Int) -> Int) {
print(String(strNum, radix: numFunc(num), uppercase: true))
}
toStr(123, to: 2, numFunc: { (num : Int) in return num }) // 리턴 자료형 생략
/* 실행 결과
1111011
*/
클로저에서는 리턴형을 생략할 수도 있다.
func toStr(_ strNum : Int, to num : Int, numFunc : (Int) -> Int) {
print(String(strNum, radix: numFunc(num), uppercase: true))
}
toStr(123, to: 2, numFunc: { return $0 }) // 매개변수와 in 생략
/* 실행 결과
1111011
*/
그리고 in과 매개변수를 모두 생략하고 $0, $1 이런식으로 단축 인자(shorthand argument name)를 사용할 수 있다.
func toStr(_ strNum : Int, to num : Int, numFunc : (Int) -> Int) {
print(String(strNum, radix: numFunc(num), uppercase: true))
}
toStr(123, to: 2, numFunc: { $0 }) // return 생략
/* 실행 결과
1111011
*/
마지막으로 return문까지 없앨 수도 있다.
클래스
Class (computer programming) - Wikipedia
Class (computer programming) - Wikipedia
From Wikipedia, the free encyclopedia Definition in programming that specifies how an object works In object-oriented programming, a class is an extensible program-code-template for creating objects, providing initial values for state (member variables) an
en.wikipedia.org
클래스의 생성자로부터 만들어진 객체를 인스턴스라고 한다. 우리가 객체를 생성할 때 호출하는 것이 생성자이다.
다른 언어에서 필드, 멤버 변수라고 부르는 것이 스위프트에서는 프로퍼티(Property)라고 하고, 멤버함수, 메소드가 스위프트에서는 그대로 메소드(Method)라고 한다.
메서드 (Methods) - Swift (gitbook.io)
메서드 (Methods) - Swift
메서드 (Methods) 는 특정 타입과 연관된 함수입니다. 클래스, 구조체, 그리고 열거형은 주어진 타입의 인스턴스 동작을 위한 특정 작업과 기능을 캡슐화하는 인스턴스 메서드를 정의할 수 있습니
bbiguduk.gitbook.io
구조체와 클래스 (Structures and Classes) - Swift (gitbook.io)
구조체와 클래스 (Structures and Classes) - Swift
실제로 값 타입에 대해 이전 챕터에서 광범위하게 다뤘습니다. 실제로 Swift에서 정수, 부동 소수점, 부울, 문자열, 배열 그리고 딕셔너리와 같은 기본 타입의 모두는 값 타입이고 구조체로 구현
bbiguduk.gitbook.io
프로퍼티
프로퍼티는 두 가지 종류가 있다. 저장 프로퍼티(stored property)와 계산 프로퍼티(computed proprty)가 있다.
다음은 저장 프로퍼티의 예이다.
class Node {
var x : Int // 초기 값 없음
var y : Int // 초기 값 없음
}
/*실행 결과
main.swift:1:7: error: class 'Node' has no initializers
class Node {
*/
ㄴ 프로퍼티의 초기 값이 없어서 오류가 발생한다.
클래스의 프로퍼티는 다음 조건 중 하나라도 만족해야한다.
1. 초기값이 있다.
2. init을 이용해서 초기화한다.
3. 옵셔널 변수(상수)로 선언(자동으로 nil로 초기화)
class Node {
var x : Int = 0 // 0으로 초기화
var y : Int? // Optional로 지정
}
/*실행 결과
*/
초기화를 직접 해주거나 옵셔널 변수로 선언 했더니 초기화를 직접 해주지 않아도 작동 된다. 사실 Optional이 자동으로 nil로 초기화 해주기 때문이다.
메서드
메서드의 타입은 두 가지가 있다. 인스턴스(instance) 메서드와 클래스(class) 또는 타입 (type) 메서드이다.
class Node {
var x : Int = 0
var y : Int = 0
func setXY(num1 : Int, num2 : Int) {
x = num1
y = num2
print("(\(x), \(y))")
}
}
var myNode : Node = Node()
myNode.setXY(num1: 3, num2: 7)
/* 실행 결과
(3, 7)
*/
인스턴스를 만들고 싶으면 ex) var 인스턴스명 : 클래스명 = 클래스명() 이런식으로 사용하면 된다. 뒤에 붙는 클래스명()이 생성자이다. () 그대로 사용하면 default initializer를 호출한다.
class Node {
var x : Int = 0
var y : Int = 0
func getXY(num1 : Int, num2 : Int) { // 인스턴스 메서드
print("(\(num1), \(num2))")
}
}
var myNode : Node = Node()
print(myNode.x) // 프로퍼티 접근
print(myNode.y) // 프로퍼티 접근
/* 실행 결과
0
0
*/


class Node {
var x : Int = 0
var y : Int = 0
func setXY(num1 : Int, num2 : Int) {
x = num1
y = num2
print("(\(x), \(y))")
}
}
var myNode : Node = Node.init() // init() 생성자 호출
myNode.setXY(num1: 3, num2: 7)
/* 실행 결과
(3, 7)
*/
Node.init()으로 직접 클래스의 기본 생성자를 호출해보았다.
class Node {
var x : Int = 0
var y : Int = 0
func setXY(num1 : Int, num2 : Int) {
x = num1
y = num2
print("(\(x), \(y))")
}
}
var myNode = Node() // : Node 생략함
myNode.setXY(num1: 3, num2: 7)
/* 실행 결과
(3, 7)
*/
다른 기본 자료형을 사용할 때 초기값을 주면 자료형을 생략해도 되는 것처럼 인스턴스를 생성할 때도 클래스 타입을 생략할 수 있다. 물론 클래스 내부의 x와 y의 초기화는 해주어야 정상 동작한다.
class Node {
var x : Int = 6
var y : Int = 12
func setXY(num1 : Int, num2 : Int) { // 인스턴스 메서드
x = num1
y = num2
print("(\(x), \(y))")
}
class func cl() {
print("클래스 메서드")
}
static func cls() {
print("클래스 메서드(static)")
}
}
var myNode = Node() // : Node 생략함
myNode.setXY(num1: 3, num2: 7)
Node.cl()
Node.cls()
/* 실행 결과
(3, 7)
클래스 메서드
클래스 메서드(static)
*/
class와 static 메서드는 인스턴스에서 호출하는 것이 아닌 클래스 타입으로 호출하는 메서드를 말한다. 다른 언어에서는 인스턴스 변수에서도 클래스 메서드를 호출할 수 있는 경우가 있는데 스위프트에서는 클래스 메서드는 클래스 타입으로만 호출해야 한다. 또한 인스턴스 멤버인 x, y 프로퍼티도 클래스 메서드에서는 사용하지 못한다.
class Node {
var x : Int = 6
var y : Int = 12
func setXY(num1 : Int, num2 : Int) { // 인스턴스 메서드
x = num1
y = num2
print("(\(x), \(y))")
}
class func cl() {
print("클래스 메서드")
}
static func cls() {
print("클래스 메서드(static)")
}
}
var myNode = Node() // : Node 생략함
myNode.cl() // 클래스 메서드를 인스턴스에서 사용하려고 함
myNode.cls() // 클래스 메서드를 인스턴스에서 사용하려고 함
/* 실행 결과
main.swift:22:1: error: static member 'cl' cannot be used on instance of type 'Node'
myNode.cl()
^~~~~~
Node
main.swift:23:1: error: static member 'cls' cannot be used on instance of type 'Node'
myNode.cls()
^~~~~~
Node
*/
이렇게 인스턴스에서 클래스 메서드를 호출하면 오류가 발생한다.
class Node {
var x : Int = 6
var y : Int = 12
func setXY(num1 : Int, num2 : Int) { // 인스턴스 메서드
x = num1
y = num2
print("(\(x), \(y))")
}
init(num1: Int, num2: Int) { // init() 생성자
x = num1
y = num2
}
}
이렇게 init() 생성자를 직접 만들어 사용할 수 있다. 일반 메서드와 다른 점은 func를 적지 않는다는 점이 있다.
모든 프로퍼티를 초기화 시키는 생성자를 designated initializer라고 한다.
class Node {
var x : Int = 6
var y : Int = 12
func setXY(num1 : Int, num2 : Int) { // 인스턴스 메서드
x = num1
y = num2
print("(\(x), \(y))")
}
// designated initializer
init(num1: Int, num2: Int) { // init(num1:num2:) 생성자
x = num1
y = num2
}
}
var myNode = Node(num1: 24, num2: 64) // 생성자에 값 할당
print(myNode.x)
print(myNode.y)
/* 실행 결과
24
64
*/
생성자는 인스턴스가 만들어지면서 자동으로 호출된다. 그리고 init(~)를 임의로 작성하면 그 뒤로는 기본으로 실행되던 init() 메서드는 더이상 작동하지 않는다.
class Node {
var x : Int = 6
var y : Int = 12
func setXY(num1 : Int, num2 : Int) { // 인스턴스 메서드
x = num1
y = num2
print("(\(x), \(y))")
}
init(x: Int, y: Int) { // init() 생성자
x = x // 오류 발생
y = y // 오류 발생
}
}
var myNode = Node(num1: 24, num2: 64)
print(myNode.x)
print(myNode.y)
/* 실행 결과
main.swift:17:18: error: incorrect argument labels in call (have 'num1:num2:', expected 'x:y:')
var myNode = Node(num1: 24, num2: 64)
^~~~~ ~~~~
x y
main.swift:12:9: error: cannot assign to value: 'x' is a 'let' constant
x = x
^
main.swift:12:9: note: add explicit 'self.' to refer to mutable property of 'Node'
x = x
^
self.
main.swift:13:9: error: cannot assign to value: 'y' is a 'let' constant
y = y
^
main.swift:13:9: note: add explicit 'self.' to refer to mutable property of 'Node'
y = y
^
self.
*/
생성자 안에서 프로퍼티를 초기화할 때 argument label과 같은 이름을 사용해서는 안 된다. 이렇게 사용하고 싶으면 프로퍼티 부분에 self.를 붙여주면 되는데 이는 자바나 C#의 this와 같은 의미이다.
class Node {
var x : Int = 6
var y : Int = 12
func setXY(num1 : Int, num2 : Int) { // 인스턴스 메서드
x = num1
y = num2
print("(\(x), \(y))")
}
init(x: Int, y: Int) { // init() 생성자
self.x = x // self
self.y = y // self
}
}
var myNode = Node(x: 24, y: 64)
print(myNode.x)
print(myNode.y)
/* 실행 결과
24
64
*/'공부 > Swift' 카테고리의 다른 글
| [Swift][10주차] 9주차 마무리 및 앱 만들기 (0) | 2023.11.06 |
|---|---|
| [Swift][9주차] Xcode 및 Mac 사용 (0) | 2023.10.30 |
| [Swift][5주차] 함수(메서드), guard, 일급객체 및 클로저 (0) | 2023.10.02 |
| [Swift][4주차] 제어문 및 함수와 메서드 (0) | 2023.09.25 |
| [Swift][3주차] 연산자와 Optional (0) | 2023.09.18 |