본문 바로가기

Swift/기본34

타입 추론, 타입 어노테이션 스위프트의 변수, 상수 선언 아래와 같이 쓸 경우에는 어떤 자료형인 줄 알 수가 없다. 따라서 변수, 상수를 선언할 때는 컴파일러가 알 수 있게 Type을 명시해줘야 한다. let namevar age 자료형을 명시하는 방법에는 2가지가 있다.  타입 추론 (Type Inference)아래와 같이 변수를 선언하는 경우가 바로 "타입 추론" 이다.컴파일러가 초기화된 값을 보고 타입을 추론하는 것을 말한다.  name에 jerry 라는 값을 보고 String 타입이라는 걸 알 수 있다. let name = "jerry" ✅ 이렇게 사용하면 코드가 간결해진다는 것이다. ✅ 단, 이렇게 쓸 경우에는 초기값을 보고 자료형을 유추할 때, 애매할 경우에는 자료형이 더 큰 범위를 지정해버린다. (Character 보단.. 2024. 4. 27.
타입 중첩 타입 내부에 타입을 정의하고 구현할 수 있다. 타입 내부에 새로운 타입을 선언하는 것을 중첩 타입이라고 한다.   중첩된 타입의 동작 (Nested Types in Action)BlackjackCard 라는 구조체 정의한다. 해당 구조체에는 Suit 와 Rank 라는 2개의 중첩된 열거형을 포함한다.  ✔ 블랙잭에서 에이스 카드의 값은 1 또는 11이다. 해당 내용은 Rank 열거형 내에 중첩된 Values 라는 구조체로 나타낸다.  Suit 열거형은 기호를 나타내는 원시 Character 값과 함께 4개의 일반적인 카드 모양을 나타낸다.enum Suit: Character { case spades = "♠", hearts = "♡", diamonds = "♢", clubs = "♣"}  Rank .. 2024. 4. 26.
ARC 3편 (클로저에서의 강한 참조 순환) 클로저에서의 강한 참조 순환 (Strong Reference Cycles for Closures) 클로저에서는 self를 캡쳐하기 때문에 강한 참조 순환이 발생할 수 있다. 이를 해결하기 위해서 클로저 캡처 리스트를 사용한다.  HTMLElement 클래스의 클로저 asHTML은 입력값을 받지 않고, 반환 값이 String인 () -> String 클로저를 사용한다.이 클로저 안에서 self.text와 self.name과 같이 self를 캡쳐한다.  ✅ asHTML 클로저는 lazy로 선언되었다. name과 text가 준비되고 나서 HTML이 필요하고, lazy 프로퍼티 이기 때문에 프로퍼티 안에서 self를 참조할 수 있다.  class HTMLElement { let name: String .. 2024. 4. 26.
DispatchQueue.main과 DispatchQueue.global DispatchQueue(GCD)의 종류 1. main queue : Serial 2. global queue : Concurrent / QoS 설정 3. private queue : 디폴트 Serial (Concurrent로 변경 가능) / QoS 추론 Main Queue DispatchQueue.main - 한개만 존재 => Main Thread에서 동작 - Serial (직렬) - UI 처리를 담당 * 쓰레드 없이 날것의 코드를 실행하는 것은 Main Queue에서 sync로 실행하겠다는 것과 같은 의미이다. * 하지만 DispatchQueue.main.sync는 코드로 사용할 수 없다. (에러) DispatchQueue.main.sync { ... } // 사용 불가! --ERROR-- Dispa.. 2024. 4. 20.
ARC 2편 - 강한 참조 순환 클래스 인스턴스간 강한 참조 순환 (Strong Reference Cycles Between Class Instances) 클래스의 인스턴스 간 강하게 상호 참조를 하고 있는 경우에는 ARC에서 자동으로 메모리 해제를 못하는 경우도 있다. Person 클래스와 Apartment 클래스가 있다. Person 클래스 내의 apartment 저장 프로퍼티 경우는 Apartment 클래스 타입을 따르고 있고, Apartment 클래스 내의 tenant 저장 프로퍼티 경우는 Person 클래스 타입을 따르고 있다. class Person { let name: String init(name: String) { self.name = name } var apartment: Apartment? deinit { print.. 2024. 4. 19.
ARC 1편 - ARC 란? ⭐ 참조타입은 메모리 해제가 중요한 문제이다. 왜냐하면? 인스턴스가 적절한 시점에 메모리에서 해제되지 않으면 메모리 자원 낭비 + 성능 저하로 이어지기 때문이다. 이를 해결하고자 스위프트에서는 메모리 관리 기법인 ARC를 사용한다. ✔ RC: Reference Counting 으로 참조 횟수 계산을 뜻한다. (구조체, 열거형은 값 타입으로 적용이 안된다.) ARC 사용 Person 클래스를 선언하고, init(), deinit을 통해 인스턴스 생성과 해제에 따른 print()문을 실행한다. class Person { let name: String init(name: String) { self.name = name print("\(name) is being initialized") } deinit { pr.. 2024. 4. 19.
메모리 구조 (Code, Data, Stack, Heap) 메모리 구조 프로그램이 실행되면, 운영체제는 메모리(RAM)에 프로그램을 위한 공간을 할당한다. 이 공간은 총 4가지로 Code, Data, Heap, Stack으로 구성되어 있다. ✅ 코드 영역 우리가 작성한 소스 코드가 기계어 형태로 저장된다. 컴파일 타임에 결정되고, 중간에 코드가 변경되지 않도록 Read - Only 형태로 저장된다. 기계어란, 컴퓨터가 읽을 수 있는 가장 밑단의 언어로 0, 1로 이루어진 언어이다. ✅ 데이터 영역 전역변수, static 변수가 저장된다. 프로그램 시작과 동시에 종료 되어야 메모리가 해제된다. 실행 도중 변수 값이 변경될 수 있으니 Read - Write로 지정된다. struct Korean { static let country = "Korea" // 스태틱 변수.. 2024. 4. 18.
접근 제어자 (Access Control) 코드에서 상호작용을 할 때 소스 파일 간 또는 모듈 간 접근을 제한할 수 있는 기능을 말한다. ⭐특정 코드의 세부적인 구현을 숨기거나, 허용된 기능만 사용하는 인터페이스를 제공할 수 있다.⭐ ✅ 모듈: 배포할 코드의 묶음 단위로 "import" 를 통해 불러오는 것을 말한다. ✅ 소스파일: Swift 코드 파일 1개를 의미한다. ✅ 파일 간 또는 모듈 간에 접근 제한하는 목적은 "은닉화"에 있다. 접근 레벨의 종류 open - 개방 접근수준 가장 넓은 범위 지정된 요소는 어디서든 사용 가능하다. Open은 클래스에만 사용 가능하다. Open에서만 클래스가 정의된 모듈 외부에서도 subclassing할 수 있다. Open에서만 클래스가 정의된 모듈 외부에서 override 할 수 있다. public - 공.. 2024. 4. 17.
서브스크립트 클래스, 구조체, 열거형에서 시퀀스의 멤버 요소에 접근하기 위한 바로가기 첨자로, 단일 타입에 여러 서브스크립트를 정의할 때 사용한다. 배열을 사용하면서 배열 내의 element에 접근할 때 사용한다. let nums: [Int] = [1, 2, 3, 4] nums[0] // 1 nums[1] // 2 " [ ] " 대괄호 안에 index를 통해 배열 내의 element에 접근하는데 이게 바로 서브스크립트이다. 서브스크립트 정의문법 서브스크립트 정의 문법은 연산 프로퍼티와 비슷하다. getter / setter 모두 구현 가능하고, get only는 되지만, set only는 불가능하다. subscript(index: Int) -> Int { get { } set(newValue) { } } String.. 2024. 4. 16.
제네릭 (제네릭 제약, 제네릭 확장, 제네릭 함수와 오버로딩) 타입 제약 제네릭 함수와 타입을 사용할 때, 특정 클래스의 하위 클래스나 특정 프로토콜을 준수하는 타입만 받을 수 있게 제약할 수 있다. 프로토콜 제약 두 개의 값을 파라미터로 받을 때, 값이 같으면 true 또는 값이 다르면 false를 반환하는 함수를 제네릭으로 선언한다면? func isSameValues(_ a: T, _ b: T) -> Bool { return a == b // Binary operator '==' cannot be applied to two 'T' operands } 에러가 발생한다. 이유는, " == " 이라는 연산자는 a와 b의 타입이 Equatable 이라는 프로토콜을 준수할 경우에만 사용할 수 있기 때문이다. 따라서 아래와 같이 타입 파라미터가 " Equatable " 프.. 2024. 4. 16.
제네릭 타입에 의존하지 않는 범용 코드를 작성할 떄 사용한다. ⭐제네릭을 사용하면 중복을 피하고, 코드를 유연하게 작성할 수 있다. 두 Int 타입의 값을 변환하는 함수를 만든다면? func swapTwoInts(_ a: inout Int, _ b: inout Int) { let tempA = a a = b b = tempA } 위의 함수는 Int 타입 말고, Double 이나 String 일 경우에는 사용할 수 없다. 이 때 사용하는 것이 바로 제네릭이다. func swapTwoValues(_ a: inout T, _ b: inout T) { let tempA = a a = b b = tempA } "" 를 이용해서 안에 타입처럼 사용할 이름 (T)를 선언해주면 그 뒤로 해당 이름(T)를 타입처럼 사용할.. 2024. 4. 15.
고차함수 다른 함수를 전달인자로 받거나 함수실행의 결과를 함수로 변환하는 함수이다. 스위프트에서 함수(클로저)는 일급 시민이기 때문에 함수의 전달인자로 전달할 수 있고, 함수의 결과값으로 반환할 수 있다. map 컨테이너 내부의 기존 데이터를 변형하여 새로운 컨테이너를 생성한다. 1️⃣ 변형하고자 하는 numbers / 변형 결과를 받을 doubledNumbers, strings let numbers: [Int] = [0, 1, 2, 3, 4] var doubledNumbers: [Int] = [] var strings: [String] = [] 2️⃣ 기존의 for 구문 사용 for number in numbers { doubledNumbers.append(number * 2) strings.append("\(.. 2024. 4. 15.