본문 바로가기

수업 정리

91일차 수업정리(Swift - 생성자 & 소멸자, 상속, 자료구조)

**Objective-C의 selector

    => Swift는 함수형 프로그래밍 언어이고 함수가 일급 객체라서 함수의 참조를 변수에 바로 대입, 리턴 가능

    => Objective-C는 함수가 일급 객체가 아니므로 함수단위 대입이나 리턴 불가

        - 함수단위로 작업할 수 있도록 Selector라는 개념 도입

        - 애플은 메소드나 함수를 Selector라고 표현

    => iOS프로그래밍에서 매개변수 중 Selector는 함수나 메소드를 요청하는 것

 

**생성자와 소멸자

    => Constructor : 인스턴스를 생성할 때 호출하는 메소드

        - 인스턴스가 생성될때 가장 먼저 호출되는 메소드

        - 생성자가 하는 일은 allocation(메모리 할당)과 initialize(초기화 작업)

        - Objective-C는 생성자 호출시 alloc + init

        - 모든 객체 지향 언어에서는 클래스 생성시 매개변수가 없는 생성자를 제공

        - 이 생성자는 개발자가 생성자를 만들면 자동적으로 소멸

        - 생성자의 첫줄에는 보이지 않는 상위클래스 생성자 호출 코드가 포함되어있음(매개변수가 없는 생성자)

        - 생성자를 만드는 목적 : 초기화 작업을 위해

    => Destructor : 인스턴스가 파괴될때 호출되는 메소드

        - 매개변수를 가질수 없으며 Overloading도 안됨

        - 사용을 한 외부 자원에 대한 release 작업 수행

    => swift에서는 생성자를 init라고 정의

        - 소멸자는 deinit

    => swift의 메모리 정리

        - swift, Objective-C, kotlin 와 python은 참조 카운팅이라는 개념을 이용해서 메모리 정리

        - 처음 메모리 할당을 받으면 참조 카운트는 1로 설정

        - 이 메모리 영역을 다른 변수가 참조하면 참조 카운트가 1증가

        - 변수가 소멸되거나 nil을 대입하면 참조 카운트가 1감소

        - 참조 카운트가 0가 되면 Garbage Collection이 메모리를 회수

        - 게임이나 오랜시간 동안 사용하는 애플리케이션은 메모리 정리가 중요

 

**swift의 상속

1. 상속 방법

class 클래스명 : 상위 클래스명{
	=> 상위클래스의 멤버 사용 가능
}

 

2. Overriding(메소드 재정의)

    => 상위 클래스의 메소드를 하위 클래스에서 다시 정의하는 것

    => 목적은 상위 클래스에서 제공해주는 메소드의기능이 부족하여 기능 확장을 위해 수행

        - 상위 클래스의 메소드를 호출하고 필요한 기능을 추가로 정의

    => swift에서는 overriding을 할 때 반드시 func 앞에 override를 붙여야 함

    => 프로퍼티도 오버라이딩 가능

    => init의 오버라이딩(생성자 오버라이딩) : 상위 클래스에 매개변수가 없는 생성자(Default Constructor)가 없는 경우

        - View를 커스터마이징 할 때 필요

 

3. 상속관계에서의 대입

    => 상위 클래스 타입으로 선언된 변수에 하위 클래스 타입으로 만들어진 인스턴스의 참조를 바로 대입

    => 하위 클래스 타입으로 선언된 변수에 상위 클래스 타입으로 만들어진 변수의 참조는 강제 형변환을 해야한 대입 가능

        - 이때 책임은 개발자가 져야 함

        - 상위 클래스 타입의 변수에 저장된 인스턴스의 참조가 하위 클래스 타입으로 만들어진 경우만 가능

 

4. 인스턴스 참조 변수의 메소드 호출

    => 인스턴스 참조 변수는 기본적으로는 선언되었을 때 사용한 클래스의 멤버만 호출 할 수 있는데 예외적으로 오버라이딩 된 메소드는 선언되었을 때 사용한 클래스 타입이 아니고 대입된 인스턴스의 자료형의 메소드를 호출

 

**enum

    => 나열형 상수

    => 여러개의 상수를 하나로 묶어둔 것

    => 옵션(선택제한)을 만들때 사용

enum 이름 : 자료형{
	case 항목명 = 값,
    case 항목명 = 값...
}

    => 사용시 이름.항목명으로 사용

    => iOS에서는 만드는 것보다 사용하는 것이 더 중요

    => iOS에서는 변수의 자료형이 결정되어 있다면 이름을 생략하고 .항목명 만으로 대입 가능

    => iOS SDK의 최근 버전의 가장 큰 변화 2가지는 Swift UI의 도입과 항목명을 소문자로 사용하는 것

        - 이전에는 대문자로 사용

        - 2019년 이전에 나온 책들의 소스에러의 대부분은 이부분

//열거형 상수 정의
enum Comm : Int{
    case SK = 1
    case LG = 9
}

var x : Comm = Comm.SK
print(x)
x = .LG
print(x)
//Apple에서 열거형 상수는 전부 내부 클래스형태
//iOS Framework를 사용하다가 매개변수가 ?.?로 되어있으면 이건 전부 열거형 상수

 

**protocol

    => 자바의 인터페이스와 유사한 개념

        - 자바의 인터페이스가 Protocol을 가져온 개념

    => 공통으로 구현해야 할 기능 목록을 가진것

    => 메소드와 속성, init의 선언만 포함할 수 있음

1. 속성의 경우

    - var 속성명 : 자료형{get, set}

 

2. 메소드의 경우

    - func 메소드명(매개변수)

 

3. init

    - init(매개변수)

 

4. 클래스에서 conform

Class 클래스명 : 프로토콜명 나열{

}

    => 여러개를 나열하고자 하는 경우 ,로 구분

    => 프로토콜의 모든 요소를 전부 구현해야 함

 

5. 선택적 구현

    => 메소드나 프로퍼티 앞에 @objc optional 추가해주면 됨

        - 이렇게 만들어진 프로토콜을 confirm하는 클래스는 클래 앞에 @objc를 추가하거나 Objective-C의 클래스로부터 상속 받아야 함

//프로토콜
@objc protocol MediaPlayer{
    //필수 구현 메소드
    func play()
    func stop()
    //선택적 구현 메소드
    @objc optional func pause()
}
//프로토콜을 구현한 클래스
//이 클래스는 NSObject로 상속받아서 @objc를 생략
class VideoMediaPlayer : MediaPlayer{
    func play() {
        print("재생")
    }
    func stop() {
        print("중지")
    }
}

 

6. iOS에서는 프로토콜의 이름을 공통된 방법으로 사용

    - 클래스명 DataSource : 데이터 출력을 위한 메소드를 소유한 프로토콜(필수 메소드 존재)

    - 클래스명 Delegate : 이벤트 처리를 위한 메소드를 소유한 프로토콜(전부 선택적 구현)

 

**Extension

    => 클래스의 기능을 확장하는 개념

    => 이전에는 Category라고 함

extension 기존클래스명{
	속성
    메소드
}

    => 기존 클래스에 속성과 메소드가 추가(현재 프로젝트에서만 적용)

    => 하나의 프로젝트에서 추가를 했더라도 다른 프로젝트에서는 영향이 없음

    => protocol을 conform 할때 클래스에 직접 메소드를 구현하기 보다는 extension을 이용하여 구현하는 경우가 많음

    => protocol의 메소드를 클래스에 직접 구현시, 이 클래스에서 만들어진 것인지 protocol에 있는 메소드를 conform한 것인지 구별이 되

        지 않아 extension을 이용하여 구현

 

**Swift에서 제공하는 자료구조 클래스

1. 종류

    => Array : 배열, 리스트의 개념으로 동작, Double Linked List 구조

    => Set : 중복되지 않도록 해싱하여 데이터를 저장하는 자료구조

    => Dictionary : Key와 Value를 쌍으로 저장하는 자료구조

    => Tuple : 데이터의 모임 - DTO의 성격

    => String : Character의 모임

    => Tuple을 제외하고는 동일한 자료형의 모임

        - 여러 자료형을 저장하고자 하면 Any, AnyObject를 이용

    => Objective-C에는 Tuple을 제외한 자료형의 클래스가 존재

        - NSArray, NSSet, NSDictionaray, NSString : 변경이 불가능한 자료형

        - NSMutableArray, NSMutableSet, NSMutableDictionary, NSMutableString : 변경이 가능한 자료형

 

2. String

    => String은 구조체 - 값의 모임

    => =로 대입하면 데이터를 복제하여 대입

    => +와 +=이 재정의 되어있어 다른 문자열과 결합 가능

        - append 메소드를 이용하여 이어붙이기 가능

    => 데이터의 모임이므로 for~in을 이용하여 하나의 문자 단위로 접근 가능

    => 문자열 템플릿(보간) 기능을 소유 : 다른 변수의 값을 문자열 상수 안에 삽입하여 하나의 문자열을 만드는 것이 가능

    => ”\u{유니코드}”를 이용해서 문자열 생성하는 것이 가능

    => count 속성으로 문자열 개수 파악 가능 : swift4에서 제공되는 문법

    => 문자열 크기 비교를 >, < 로 가능

//문자열 변수 생성
var str : String = "Swift String"
//문자열을 추가
str += "\u{1F496}"
print(str)

//문자열 크기 비교를 연산자를 이용해서 가능
var str1 : String = "ABCD"
var str2 : String = "abcd"
print(str1 > str2)

//struct 는 값의 형태이고 class는 참조의 형태
var str3 = str1
//값을 복사했기 때문에 복사본에서 작업을 수행해도 원본에는
//영향이 없습니다.
str3 = "EFGH"
//Swift에서는 String을 Character의 모임으로 보기 때문에
//이터레이터를 접근이 가능
for imsi in str1{
    print(imsi)
}

 

3. Array

    => 배열, 동적인 배열이라서 Double Linked List 구조로 동작

  1) 배열의 생성

    => 정적 생성 : var or let 배열명 : [자료형] = [데이터 나열]

    => 동적 생성 : var or let 배열명 = [자료형]()

 

  2) 배열에 데이터를 추가

    => 마지막에 데이터를 추가 : append(데이터)

    => 중간에 추가 : insert(데이터, at: 위치)

    => +연산자를 이용하여 다른 배열 추가 가능

 

  3) 배열의 데이터를 순서대로 순회

    => 빠른 열거(이터레이터)이용

for 임시변수 in 배열명{
	임시변수를 이용한 데이터의 순차적인 접근
}

 

    => 직접 순서대로 접근

        - count 속성을 이용하면 데이터의 개수를 알수 있음

        - [인덱스]를 이용시 특정 인덱스에 해당하는 데이터에 접근 가능, 인덱스는 0부터 count-1까지

var idx : Int = 0
while(idx < 배열.count){
	배열[idx]
    idx = idx+1
}

 

  4) 배열의 특정번째 데이터를 가져오는 것

    => 배열[idx]

    => 배열[시작인덱스...종료인덱스] : 범위내의 데이터를 가져오기 - slicing

 

  5) 배열의 데이터를 정렬

    => Array.sorted()를 호출시 오름차순 정렬 가능 : 배열의 각 요소가 되는 데이터가 >가 사용가능해야 함

    => >가 없는 경우 함수를 생성하여 대입 : 이 함수는 2개의 매개변수를 가지고 Bool을 리턴해야 함

 

  6) 배열의 전체 데이터를 확인

    => 배열명을 print 메소드에 대입하면 description이라는 속성을 호출하여 각 요소의 description을 []로 묶어서 출력

    => Java에서는 toString을 이용했지만 swift에서는 description이라는 속성 사용

    => Swift에서 toString을 사용하고자 하면 description이라는 프로퍼티를 오버라이딩 하면 됨

//배열 생성
//기존 데이터를 가지고 배열을 생성
var names:[String] = ["을지문덕", "척준경", "남이"]

//기존 데이터가 없는 경우
var songs:[String] = [String]()
songs.append("혼자가 아닌 나") //마지막에 데이터를 추가
songs.insert("나의 20년", at: 0) //첫번째에 데이터를 추가

//배열의 데이터 확인
print(names)

//배열의 데이터 정렬
names.sort() // sort는 자신의 데이터를 정렬
//sorted()는 정렬한 결과를 리턴
print(names)

//sort 함수의 by라는 매개변수에 2개의 매개변수를 가지고
//Bool을 리턴하는 함수를 대입하면 함수를 가지고 비교해서
//데이터를 정렬해줍니다.

//함수를 생성해서 대입
/*
func mycompare(str1:String, str2:String) -> Bool{
    return str1 > str2
}
names.sort(by:mycompare)
 */

//클로저를 이용한 정렬
/*
names.sort(by:{(str1:String, str2:String) -> Bool in return str1 > str2})
*/

//트레일링 클로저를 이용한 정렬
//함수가 마지막 매개변수인 경우 함수를 호출하는 구문 외부에
//클로저를 생성 - iOS의 샘플 코드가 대부분 이방식
names.sort(){(str1:String, str2:String) -> Bool in
    return str1 > str2}
print(names)

 

  7) 배열에 Map - Reduce Programming을 위한 함수

    => map: 하나의 매개변수와 리턴 타입을 갖는 함수를 대입

        - 배열의 각 요소를 대입받아서 리턴하는 값의 배열로 리턴해주는 함수

        - 데이터를 변환해주는 역할을 수행하는 함수

    => filter: 하나의 매개변수와 Bool 리턴 타입을 갖는 함수를 대입

        - 배열의 각 요소를 대입받아서 true를 리턴하는 요소들의 배열로 리턴해주는 함수

        - 데이터를 필터필해주는 역할을 수행하는 함수

    => reduce: 2개의 매개변수와 하나의 값을 리턴 타입으로 갖는 함수를 대입

        - 첫번째 매개변수는 중간 결과이고 두번째 매개변수는 배열의 각 요소가 되서 집계를 수행해서 리턴하는 함수

 

4. Set

    => 데이터를 중복없이 저장하는 자료구조

    => 해싱을 이용해서 데이터를 저장

    => 터치를 처리하는 메소드에서 터치의 값을 가져오기 위한 정도로만 사용

    => 정적으로 만들 때 배열과 방법은 같은데 [자료형] 대신에 Set<자료형>

 

5.Tuple

    => 여러가지 종류의 데이터를 하나로 묶을 수 있는 자료형

    => 한 번 묶이면 수정이 불가능

    => 자료형 만들기

        - (자료형, 자료형, …)

    => 데이터 만들기

        - (값, 값, …)

    => 데이터 접근

        - 튜플.인덱스

    => 데이터 앞에 이름을 부여하면 인덱스 대신에 이름으로도 접근 가능

    => 스위프트에서는 DTO별도로 잘 안만들고 튜플을 사용하는 것을 권장

//트레일링 클로저를 이용한 정렬
//함수가 마지막 매개변수인 경우 함수를 호출하는 구문 외부에
//클로저를 생성 - iOS의 샘플 코드가 대부분 이방식
names.sort(){(str1:String, str2:String) -> Bool in
    return str1 > str2}
print(names)


//문자열 1개와 정수 1개를 저장하는 튜플을 생성
var user01 : (String, Int) = ("아이린", 31)
//전체 출력
print(user01)
//부분 출력
print(user01.0)

//튜플을 만들 때 각 항목에 이름을 부여해서 생성
//마치 DTO 클래스를 만들어서 사용하는 효과
var user02 : (name:String, age:Int) = (name:"배수지", age:27)
print(user02)
print(user02.name)
print(user02.age)

 

6. Dictionary

    => Key 와 Value를 쌍으로 저장하는 자료구조

  1) 생성

    - var 또는 let 변수명:[key의 자료형 : value의 자료형] = [key:value, key:value…]

    - var 또는 let 변수명:Dictionary<key의 자료형 : value의 자료형> = [:]

    => key의 자료형은 모든 자료형이 가능하지만 특별한 경우를 제외하고는 String

  2) 데이터 개수는 count를 이용해서 찾아옴

  3) 접근

    => 데이터 추가 및 갱신

        - 디셔너리이름[키] = 값  //존재하는 키면 수정이고 존재하지 않는 키면 삽입 - upsert

    => 데이터를 리턴받을 때는 디셔너리이름[키]

        - swift에서는 디셔너리로 데이터를 가져올 때는 Optional로 가져옴

        - 사용을 할 때는 !를 이용해서 Optional을 해제하고 사용

    => 삭제는 nil을 대입해도 되고 removeValueForKey(키이름)

  4) 모든 데이터 접근

    => Dictionary를 for-in을 이용해서 접근하면 모든 데이터를 튜플로 하나씩 리턴

    => keys 속성을 호출하면 모든 key의 값을 리턴

 

**예외처리

do{
	try{
			예외가 발생할 가능성이 있는 코드
	}
	catch 예외이름{
		예외가 발생했을 때 사용할 코드
	}
	catch 예외이름{
		예외가 발생했을 때 사용할 코드
	}
..
}

    => 이전 API에서 예외처리를 강제하는 경우에는 예외처리 구문을 사용해야 하는데 try! 을 앞에 붙이면 예외처리를 하지 않아도 됨

 

**defer

    => defer{내용} 을 사용하면 위치에 상관없이 블럭이 끝나면 호출

 

**Thread의 우선순위 설정

    => 1~10까지만 사용할 수 있도록 하고 싶음

    => 우선 순위를 int로 priority로 만들게 되면 1~10이외의 값을 설정한 경우 어떻게 할지

    => 자바

class Thread{
	final static int ONE = 1;
    final static int TEN = 10;
}

    => priority에는 final 상수를 대입하는 것을 권장

        - setPriority(Thread.TEN) : 다른 정수를 대입할 수 있으므로 예외 발생 가능성이 있음

enum ThreadPriority : Int{
	case one = 1,
    cases TEN = 10
}

        - ThreadPriority priority 이렇게 선언시 priority에는 ThreadPriority안에 있는 값만 대입가능(다른 값 대입하면 에러)

        - priority = .ONE