Swift 문법 CH.6_1

김성환·2020년 8월 24일
0

swift문법

목록 보기
7/11

안녕하세요. 본 포스트에서는 Swift의 구조체와 클래스에 대해 설명하겠습니다.

구조체와 클래스부분은 양이 많아 3부로 나눠 진행하겠습니다.
※ 참고자료 : 꼼꼼한 재은 씨의 Swift:문법편, 객체지향부분은 대학교 강의를 토대로 작성

목차

  • 1. 구조체와 클래스의 기본 개념
  • 2. 객체지향

1. 구조체와 클래스의 기본 개념

구조체와 클래스란?

하나의 큰 코드 블록
코드 블록 안에 변수,상수를 넣어 값을 저장할 수도 있고, 함수를 넣어서 기능을 정의할 수도 있다.
즉, 구조체와 클래스는 하나의 데이터 타입

구조체 vs 클래스

구조체와 클래스는 공통점도 있고 차이점도 있다.

공통점

  • 프로퍼티 -> 변수,상수를 사용해 값을 저장하는 프로퍼티를 정의할 수 있다.
  • 메소드 -> 함수를 사용해 기능을 제공하는 메소드를 정의할 수 있다.
  • 초기화블록(init) -> 객체를 원하는 초기 값으로 설정해주는 초기화 블록을 정의할 수 있다.
  • 확장(extends구문) -> 확장구문을 사용할 수 있다.
  • 프로토콜 -> 프로토콜을 구현할 수 있다.
  • 서브스크립트 -> 속성값에 접근할 수 있는 방법을 제공하는 서브스크립트를 정의할 수 있다.

서브스크립트란?

위에서 나온 설명처럼 클래스,구조체와 같은 객체의 속성값에 접근할 수 있는 방법을 제공하는 문법이다.
쉽게 말해, 객체에서 내가 원하는 값을 접근하는 방법을 정의한 문법이다.
예를 들어 배열의 경우를 생각해보자.
내가 배열 a에서 0번째 인덱스 값을 접근하고 싶을 경우 a[0]이라고 입력하면 된다.
이렇게 객체의 원하는 값을 얻기위해 정의된 문법이 서브스크립트이다.

let a : [Int] = [1,2,3,4]
a[0] // 배열의 서브스크립트를 이용해 손쉽게 원하는 값을 얻음

서브스크립트 구현

서브스크립트는 subscript 라는 키워드와 뒤에서 배울 것이지만 getset을 이용해 구현한다.

subscript(index: Int) -> Int {
    get {
        // return an appropriate subscript value here
    }
    set(newValue) {
        // perform a suitable setting action here
    }
}

아래는 서브스크립트를 구현한 예시이다.

struct TimesTable { // 구조체 안에 서브스크립트를 구현함
    let multiplier: Int
    subscript(index: Int) -> Int { // 서브스크립트 구현 
        return multiplier * index // set생략됨(읽기전용이라서)
    }
}
let threeTimesTable = TimesTable(multiplier: 3)
print("six times three is \(threeTimesTable[6])") // 배열처럼 [6]을 이용해 접근

차이점 (클래스만 있는 것)

  • 상속
  • 타입 캐스팅
  • 소명화 구문
  • 참조에 의한 전달
    ※ 차이점들은 밑에서 혹은 다음장에서 설명한다.

구조체와 클래스의 선언

구조체는 struct 키워드를 사용하고, 클래스는 class 키워드를 사용해 선언한다.

struct 구조체이름 {
	구조체 내용
}
class 클래스이름{
	클래스 내용
}

인스턴스란?

구조체와 클래스는 대상(객체)의 중요한 정보들을 변수화,함수화를 시킨 것이다. 즉, 대상(객체)의 원형이라고 볼 수 있다. 원형인 구조체와 클래스를 가지고는 실질적인 대상(객체)를 사용할 수 없다.
그렇다면 실질적인 대상(객체)은 어떻게 이용할까?
답은 인스턴스이다.
인스턴스는 구조체나 클래스가 만들어 내는 변수나 상수이다. 이때 만들어지는 변수나 상수에 실질적인 대상(객체)가 들어가게 된다.
즉, 틀 역활을 하는 구조체나 클래스가 실질적으로 값을 담을 여러 개의 그릇을 만들어내고 이때 만들어진 그릇이 바로 인스턴스라는 뜻이다.

인스턴스 생성과 접근

해당 구조체, 클래스의 이름과 ()를 이용해 생성한다.

let c = A() // 상수 c에 A구조체에 대한 인스턴스 생성

인스턴스가 자신이 갖고 있는 프로퍼티(속성)에 접근 할 경우 .(점)을 이용한다.

인스턴스이름.프로퍼티이름
----------------------
c.a // 인스턴스 c가 갖는 a 프로퍼티에 접근

만약 클래스,구조체에 정의된 프로퍼티 중 서브 프로퍼티를 갖고 있을 때 이를 접근할 경우에도 .(점)을 이용한다.

class A{
	var a = 0
    var b = 1
}
class Test {
    var c = A()
}
let T = Test() // Test의 인스턴스를 생성
T.c.a // 인스턴스 T의 c 프로터티의 서브 프로퍼티인 a에 접근

즉, .(점)을 이용해 단계적으로 접근이 가능하다.

초기화구문

Swift에서는 클래스나 구조체의 모든 프로퍼티들은 적어도 인스턴스가 생성되는 시점까지는 반드시 초기화 되어야한다.
초기화 방법은 2가지인데,
1. 프로터피를 선언하면서 동시에 초기값을 지정하는 경우(명시적으로 초기화)
2. 초기화 메소드 내에서 프로퍼티의 초기값을 지정하는 경우(init 이용)
만약 클래스나 구조체의 프로퍼티들 중 하나라도 초기화가 안되어 있다면 컴파일 오류가 발생한다.
※ Swift에서는 옵셔널 타입이 있기 때문에 옵셔널 타입으로 선언된 프로퍼티는 초기화 안해도 됨(nil 자동초기화)

멤버와이즈 초기화 구문이란?

클래스와 다르게 구조체에서만 제공 되는 초기화 구문으로 사용자가 직접 구조체에 초기화 구문을 작성하지 않아도 프로퍼티들의 초기화를 해주는 구문이다. 이 초기화 구문을 멤버와이즈 초기화 구문이라고 부른다.

기본 초기화 구문 vs 멤버와이즈 초기화 구문

기본 초기화 구문은 클래스와 구조체 모두 제공되는 초기화 구문이다.

init(){ // 기본 초기화 구문
 // 아무 내용 없음 
}

기본 초기화 구문은 사용자가 클래스나 구조체에 직접 넣지 않아도 자동으로 생성(제공)(눈에 보이진 않음)되기 때문에 생략해도 오류없이 인스턴스를 생성할 수 있다.
하지만 이 경우 모든 프로퍼티의 초기화가 되어있어야 컴파일 오류를 피할 수 있다.
이때, 프로퍼티내에서 명시적으로 초기화시킨 값 대신 다른 값으로 프로퍼티를 초기화를 하고 싶은경우 어떻게 해야할까?
구조체의 경우 멤버와이즈 초기화 구문이 자동으로 제공 되기 때문에 원하는 값으로 초기화를 켜주는 초기화 구문을 따로 작성하지 않아도 자동 생성(제공)(눈에 보이진 않음) 되기 때문에 다른 값으로 초기화가 가능하다.
하지만 클래스의 경우 멤버와이즈 초기화 구문이 제공되지 않기 때문에 원하는 값으로 초기화 하기 위해서는 따로 초기화 구문을 작성해야 한다.
단, 멤버와이즈 초기화 구문 사용 시 인자값으로 모든 프로퍼티를 초기화 해야한다.(일부만 초기화 불가능, 만약 일부만 하고 싶을 경우 직접 작성)
※ 프로퍼티를 보통 멤버변수라고 부르기 때문에 멤버와이즈 초기화 구문이라고 불리는 것
아래는 예시이다.

struct A{
    var a = 0
    var b = 0
}
class B{
    var c = 0
    var d = 0
}
let T = A(a: 1 , b: 2) // 멤버와이즈 초기화 a = 1, b = 2
let t = B(c: 1, d: 2) // 오류!!
let Y = A() // 기본 초기화 a = 0, b = 0
let y = B() // 기본 초기화 c = 0, d = 0
let q = A(a: 1) // 오류!!

값 전달 방식

구조체와 클래스는 값 전달 방식이 다르다.

구조체의 값 전달 방식 : 복사에 의한 전달

전 장에 배운 것과 동일하다. 즉, 값을 전달 할때 기존의 인스턴스가 그대로 대입되는 것이 아니라 이를 복사한 새로운 값이 대입된다는 뜻이다.

struct A{
    var a = 0
    var b = 0
}
var T = A() // 인스턴스를 생성
var t = T // 상수 T에 인스턴스 t를 대입
t.a = 10 // 인스턴스 t의 프로퍼티 a에 10을 대입함
print(T.a)
// 실행결과
0

클래스의 값 전달 방식 : 참조에 의한 전달

참조란 인스턴스가 저장된 메모리 주소 정보를 이용한다는 뜻으로, 값이 전달 될 때 값의 복사가 이뤄지는 것이 아니라 인스턴스가 저장된 메모리 주소 정보가 전달 된다는 뜻이다.

class A{
    var a = 0
    var b = 0
}
var T = A() // 인스턴스를 생성
var t = T // 상수 T에 인스턴스 t를 대입
t.a = 10 // 인스턴스 t의 프로퍼티 a에 10을 대입함
print(T.a)
// 실행결과
10

왜 그런것일까?
그 이유는 아래 그림과 같다.

인스턴스는 1번 생성되었다. 인스턴스가 생성이 되었고 그 인스턴스를 변수 T가 가리킨다.
이때 변수 t에 T를 대입하였는데 변수 T는 A인스턴스를 가리키기 때문에 저런 그림이 그려진 것이다.
즉, A의 인스턴스는 고유의 메모리 주소를 갖고 있고 그걸 변수 T가 가리키고 그걸 변수 t가 또 가리킨다고 생각하면 된다.(각 변수들은 c언어에서의 포인터 변수라고 생각하면 된다.)

인스턴스 비교

자신이 참조하는 인스턴스가 상대가 참조하는 인스턴스와 같은지 비교할 경우 ===,!== 를 사용한다.

  • 동일한 인스턴스인지 비교 ===
  • 동일한 인스턴스가 아닌지 비교 !==

2. 객체지향

객체지향이란?

프로그램 설계방법론이자 개념의 일종이다.
객체지향을 이해하기 위해 실제 세상을 생각해보자. 실제 세상은 수많은 객체로 이루어져 있다. TV, 의자, 책, 집,... 모든 것이 객체인 것이다.
그렇다면 객체지향은 무엇일까?
말그대로 객체를 지향한다는 뜻이다. 즉, 세상 모든 것이 객체이므로 프로그래밍 안에서도 실세계의 객체들에 대응하는 컴퓨터 내의 객체를 지향한다는 뜻이다.

객체지향의 목표

따라서 객체지향의 목표는 실세계의 객체들에 대응하는 컴퓨터 내의 객체를 만드는 것이다.

객체지향의 특성

객체지향은 4가지 특성이 있는데 이 4가지를 모두 만족시키는 언어를 객체지향언어라고 부른다.

1. 추상화

2. 캡슐화

3. 상속

4. 다형성

이 중 1번과 2번은 지금 설명하고 3번과 4번은 뒤에서 설명하겠다.

추상화란?

추상화, 사전에서의 뜻은 대상이 가진 중요한 특징을 찾아낸 후 간단하게 표현하는 것. 이라고 쓰여있다.
따라서 객체지향에서의 추상화도 사전의 뜻과 같이 대상이 가진 중요한 특징을 찾아낸 후 간단하게 표현하는 것이다.
여기서 말하는 대상이란 객체를 의미하고, 중요한 특징이란 그 객체가 가진 속성(프로퍼티)과 기능(메서드)를 의미한다. 또한 간단하게 표현하는 것이란 그 특징들을 변수화(프로퍼티화), 함수화(메서드화) 시킨다는 것을 의미한다.
즉, 객체지향에서의 추상화란 객체가 가진 것(속성,기능)을 변수화 함수화 시킨다는 의미이다.

  • 실제 세계의 예시를 들어보자
    TV를 추상화 한다면 TV가 가진 속성(화면크기, 화면종류,...)->변수화, TV가 할 수 있는 동작(작동)(TV켜기,...)->함수화를 추상화 할 것이다.
  • 이제 프로그래밍 세계의 예시를 들어보자
    학사관리 시스템을 만든다면, 김아무개를 추상화 할때 김아무개가 가진 속성(학점,학부,...),행동을 학사관리 시스템이 필요로 하는 것만 추상화 할 것이다.

캡슐화란?

capsule, 한글로는 플라스틱용기라는 뜻을 가졌다. 일반적으로 캡슐은 밖에서 안이 안보인다. 즉 내용물을 감싸고 있다.
객체지향의 캡슐화도 위의 뜻과 같다.
즉, 추상화된 객체들의 정보,기능들을 감싼 것이라는 뜻이다.
정확하게는 추상화된 객체들의 정보,기능들을 클래스나 구조체안에 알맞게 잘 배치하는 것을 말한다.

Swift도 객체지향언어인가?

Swift는 많은 프로그래밍 패러다임 중 객체지향형, 함수형, 프로토콜 지향 프로그래밍을 모두 다룰 수 있는 언어이다.
하지만 iOS 프레임워크가 객체지향형 프로그래밍으로 구현되어 있어서, 객체지향 프로그래밍을 하도록 권장한다. 따라서 객체지향의 개념을 알아둘 필요가 있다.

profile
개발자가 되고 싶다

0개의 댓글