모바일/SwiftUI ios 공부

클래스와 구조체 Class, Struct 만들고 사용하기, init, deinit/ Xcode SwiftUI Playground 공부

yy_dd2 2021. 11. 27. 19:49
반응형

클래스와 구조체

코드를 추상화 하기 위해서 사용

구조체와 클래스는 프로퍼티, 메소드(함수)를 사용해서 구조화된 데이터의 기능을 사용할 수 있음

새 사용자 정의 데이터 타입을 만드는 것

// 클래스
class 클래스이름 {
 프로퍼티, 메서드
}

// 구조체
struct 구조체이름 {
 프로퍼티, 메서드
}

 

클래스 구조체 공통점

1. 프로퍼티 선언 할 수 있다 (값을 저장하는 프로퍼티 선언)

2. 함수적 기능 메서드 선언 할 수 있다.

3. 내부 값에 .을 사용히여 접근할 수 있다.

4. 생성자를 사용해 초기 상태를 설정할 수 있다.

5. extension을 사용하여 기능을 확장할 수 있다.

6. 프로토콜(Protocol)을 채택하여 기능을 설정할 수 있다.

더보기

- 프로퍼티, 메소드를 사용해 구조화된 데이터 기능 가짐

- 새로운 사용자 정의 타입 만들기

- 초기화(기본값)을 정의해 초기 상태 설정 가능

- 확장 가능

- 프로토콜 사용 가능 (?)

- 특정 값에 접근할 수 있는 서브스크립트 문법 사용

- 프로퍼티 값에 접근하고자하면 structName.valuename / className.valuename( 로 사용하요 접근가능)

 

클래스 구조체 차이점

클래스(값을 참조함) 구조체(값을 복사함)
- 참조타입
- ARC로 메모리를 관리
- 상속이 가능
- 타입 캐스팅을 통해 런타임에서 ㄴ클래스 인스턴스의 타입을 확인할 수 있음
- deinit을 사용해 클래스 인스턴스 메모리 할당을해제할 수 있음
- 같은 클래스 인스턴스를 여러 개의 변수에 할당한 뒤 값을 변경 시키면 모든 변수에 영향을 줌 (메모리에 복사 됨)

- 값 타입
- 구조체 변수를 새로운 변수에 할당할 떄마다 새로운 구조체가 할당된다
- 즉, 같은 구조체를 여러 개의 변수에 할당한 뒤 값을 변경시키더라도 다른 변수에 영향을 주지 않음 (값 자체를 복사)
// 클래스와 구조체의 공통점, 차이점
// 차이점

class SomeClass {
    var count: Int = 0
}

//같은 클래스 인스턴스를 여러 개의 변수에 할당한 뒤 값을 변경 시키면 모든 변수에 영향을 줌 (메모리에 복사 됨)
var class1 = SomeClass()
var class2 = class1
var class3 = class1

class3.count = 2
class1.count		// 2

struct SomeStruct {
    var count: Int = 0
}

// 같은 구조체를 여러 개의 변수에 할당한 뒤 값을 변경시키더라도 다른 변수에 영향을 주지 않음 (값 자체를 복사)
var struct1 = SomeStruct()
var struct2 = struct1
var struct3 = struct1
struct2.count = 3
struct3.count = 5

struct1.count		// 0
struct2.count		// 3
struct3.count		// 5
더보기

클래스  (값을 참조함)

- 참조 타입(Referece Type) 참조타입은 값을 할당하거나 전달할 때 그 값을 복사하는게 아니라 참조하는 의미

   --> 변수나 상수에 값을 할당하거나 함수에 인자로 전달될 때

- call by reference : 할당, 전달 시 객체를 가리키는 메모리 주소 값 복사됨

- 속도가 느림 (Heap Memory영역에 할당)

- 런타임 시에 직접 할당(allocate)을 함, 참조계수(referece counting)를 통해 할당값을 해제(deallocate)  해야함

- 상속가능

- 런타임에 타입캐스팅으로 클래스 인스턴스에 따라 여러 동작

- 초기화 기능 (deinitializer)

 

구조체 (값을 복사함)

- 값 타입 : 값 타입은 함수에서 상수나 변수로 전달될 떄 그 값이 복사되어 전달된다.

- call by value : 할당 또는 파라미터 전달할 때 값을 복사함 (value copy)

- 멀티 스레드 환경에서 공유 변수로 인한 문제가 발생할 가능성이 적음

- Stack Memory 메모리에 쌓기 때문에 속도가 빠름

- Scope Based lifetime (수명주기) : 메모리 할당 해제 시기를 정확히 알고있음

- 상속 불가능

- AnyObject 타입 캐스팅 불가능

 

구조체 사용하는 것이 유리한 경우

- 연관 값을 캡슐화(하나로 묶는)하는 것이 목적인 경우

- 캡슐화 한 값을 참조보다 복사 할 때

- 다른 타입으로 상속하거나 상속받지 않아도 될때 (상속이 필요없을때)

- JSON 필드와 1:1 Mapping 되는 간단한 모델이 필요할때

 

 

구조체 생성

// 구조체 만들기
struct User  {
    var nicname: String
    var age: Int
}

구조체 인스턴스화

// 인스턴스화 하기
var user = User(nicname: "영희", age: 17)

user.nicname
user.nicname = "철수"
user.nicname

구조체 선언 / 사용하기

// 구조체 안에 함수(메서드) 선언하고 사용하기
struct User2 {
    var nicname2: String
    var age2: Int
    
    func information() {
        print("\(nicname2), \(age2) 함수출력")
    }
}
var user2 = User2(nicname2: "영희2", age2: 17-2)

user2.information()

 

클래스 생성

// 강아지 정보 구성 클래스
class Dog {
    var dogName: String = ""
    var dogAge: Int = 0
    
    // 생성자 정의  생성자를 통해 초기화도 가능
    init(){
        
    }
    
    //메서드 정의
    func introduce() {
        print("name \(dogName) age \(dogAge)")
    }

}

클래스 인스턴스화, 프로퍼티 값 설정, 사용하기

// dog 클래스의 인스턴스 생성 프로퍼티 값 설정
var dog  = Dog()
dog.dogName = "아롱이"
dog.dogAge = 11

dog.dogName
dog.dogAge

// doc 클래스 안에 메서드 불러오기
dog.introduce()

init 초기화 구문 사용하기

 초기화 구문을 사용하여 초기화하면 인스턴스 생성 후 바로 값 저장 가능

- 클래스, 구조체, 열거형 인스턴스 사용을 위한 준비작업

- 프로퍼티의 초기 값 설정

- init() 형태로 초기화 값 사용

- deinit() : 인스턴스의 할당이 해제될 때 메모리 관리 작업을 수행하기 위해 사용

 init(매개변수:타입, ...){
    // 프로퍼티 초기화
    // 인스턴스 생성시 필요한 설정을 해주는 코드 작성
 }

// 초기화 구문을 사용하여 초기화하면 인스턴스 생성 후 바로 값 저장 가능

 

클래스 User 생성해서 init 이용 초기화, 초기화 값 저장 사용

// 클래스 User 생성 -> init 이용 초기화
class User {
    var nickname: String
    var age: Int
    // 기본사용
    init(nickname: String, age: Int) {
        self.nickname = nickname
        self.age = age
    }
    
}
// 인스턴스 생성, 프로퍼티 값 저장
var user = User(nickname: "JSON", age: 17)
// 프로퍼티 값 사용하기
user.nickname
user.age

 

사용자 정의 생성자를 이용한 생성자 정의하기

매개변수 전달 없이 프로퍼티 값에 대입하여 초기화 하기

// 클래스 User 생성 -> init 이용 초기화
class User {
    var nickname: String
    var age: Int
    
    // 사용자 정의 생성자를 이용한 생성자 정의하기
    // 매개변수로 전달받지 않고 프로퍼티 값에 대입하여 초기화 하기
    init(age:Int) {
        self.nickname = "ablert"
        self.age = age
    }

}

// 사용자 정의 생성자를 이용한 생성자 정의하기
var user2 = User(age: 27)
user2.nickname
user2.age

 

deinit 사용하기

초기화와 반대의 개념

스위프트는 인스턴스가 더 이상 필요가 없다고 판단되면 자동으로 소멸 시킨다.

deinit은 인스턴스의 할당이 해제되면 메모리 관리 작업을 수행하기 위해 'deinit()'함수를 제공한다.

// 클래스 User 생성 -> init 이용 초기화
class User {
    var nickname: String
    var age: Int

    // deinit
    deinit {
        print("deinit user")
    }
}

// deinit 확인햅호기
// 옵셔널타입으로 타입 선언 -> nill : nill을
// 스위프트는 인스턴스가 더이상 필요가 없으면 자동으로 소멸시킴
var user3 : User? = User(age: 23)
user3 = nil

 


 

 

프로퍼티

구조체와 클래스 프로퍼티에는

저장 프로퍼티, 지연프로퍼티, 계산된 프로퍼티가 있다.

 

 

저장 프로퍼티

구조체

// 구조체안에 프로퍼티는 변수,상수 의미 그대로 적용됨 (구조체 : 값타입 함수로 함수에서 상수나 변수로 전달될 때 그 값이 복사되서 전달됨)

// 변경을 하면 안될 때 사용

struct Dog {
    var name: String
    let number: String
}
var dog = Dog(name: "아롱이", number: "0112")
print(dog)

// dog.name = "돼지"
// dog.number = 1113
// 구조체 struct의 dog.number 은 상수로 값이 변경될 수 없음 (name은 변경되지만 뒤에 number 때문에 같이 오류가 남)

 

클래스

// 클래스안에 프로퍼티는 변수,상수 의미가 참조되어 전달되기 때문에 인스턴스 생성 후 변수나 상수를 만들어 선언하면 참조되어 변경이 가능하다.
// 변경이 가능할 때 사용


class Cat {
    var name: String
    let number: String
    
    init(name: String, number: String){
        self.name = name
        self.number = number
    }
}

let cat = Cat(name: "아롱이", number: "1113")
cat.name = "돼지"
print(cat.name, cat.number)

 

계산(연산) 프로퍼티

// 계산 (연산) 프로퍼티
struct Stock {
    // 평균가격
    var averagePrice: Int
    // 수량
    var quantity: Int
    // 계산형 프로퍼티
    // 매입가격
    var purchasePrice: Int {
        get {
            return averagePrice * quantity
        }
        // newPrice = 변경된 총 매입가에 저장
        set (newPrice) {
            averagePrice = newPrice / quantity
        }
    }
}

var stock = Stock(averagePrice: 2300, quantity: 3 )
print(stock)
// get 실행
stock.purchasePrice

// set 실행
// purchasePrice 값을 받게 되면서 다시 변경된 값의 변경이 되면서 set이 실행이 됨
stock.purchasePrice = 3000
stock.averagePrice


- 읽기 전용 프로퍼티

연산 프로퍼티에서 get 만 사용하여 읽기전용 프로퍼티를 사용해서 값을 변경할 수 없게도 사용할 수 있음

- set 사용 시 매개변수를 적지 않고 newValue 로 사용가능
set을 사용할때 매개변수의 값(여기서 newPrice)를 선언하지 않으면 newValue로 사용할 수 있다.

        // newPrice = 변경된 총 매입가에 저장
        set {
            averagePrice = newValue / quantity
        }

 

 

class를 이용한 연산 프로퍼티 사용법

// 클래스로 계산된 프로퍼티 사용하기
// 넓이와 길이 계산
class Sample2 {
    var no1 = 0.0, no2 = 0.0
    var length = 300.0, breadth = 150.0
    
    // 계산된 프로퍼티
    var middle:(Double, Double) {
        get{
            return(length / 2, breadth / 2)
        }
    // class 에서도 매개변수이름 없이 newValue 사용 가능
    /*
        set{
            no1 = newValue.0 - (length / 2)
            no2 = newValue.1 - (breadth / 2)
        }
    */
        set(axis){
            no1 = axis.0 - (length / 2)
            no2 = axis.1 - (breadth / 2)
        }
    }
}
var sample2 = Sample2()
print(sample2.middle) // (150.0, 75.0)
sample2.middle = (0.0, 10.0)

print(sample2.no1) // -150.0
print(sample2.no2) // -65.0

 


프로퍼티 옵저버

(저장 프로퍼티, 오버라이딩이 된 저장 계산된 프로퍼티에서만 사용가능)

 

 ● 프로퍼티에는 새로운 값이 설정될 때마다 이러한 이벤트를 감지할 수 있는 프로퍼티 옵저버를 제공합니다.

 ● 프로퍼티 옵저버는 새 값이 이전 값과 동일하더라도 항상 호출될 수 있습니다.

 ● 프로퍼티 옵저버는 지연 저장 프로퍼티에는 사용할 수 없습니다.

 ● 계산된프로퍼티는setter에서값의변화를감지할수있기때문에옵저버를따로정의할필요

 가 없습니다.

 ● 프로퍼티 옵저버는 두 가지 종류가 있습니다.

// 저장 프로퍼티의 사용 확인
// 잔액을 표시하는 저장형 프로퍼티
class Account {
    var credit: Int = 0 {
        // 소괄호 이름 지정
        //willSet:값을저장하기전에호출됩니다. 새로운값의파라미터이름을따로지정하지않으면,기본값 으로 “newValue” 라는 이름을 사용할 수 있습니다.
        willSet{
            print("잔액이 \(credit)원에서 \(newValue)원으로 변경될 예정입니다.")
        }
        //didSet:새로운값이저장되고난이후에호출됩니다. 바뀌기전값의파라미터이름을따로지정하지 않으면, 기본 값으로 “oldValue” 라는 이름을 사용할 수 있습니다.
        didSet{
            print("잔액이 \(oldValue)원에서 \(credit)원으로 변경되었습니다.")
        }
    }
} // Acoount end

var account = Account()
account.credit = 1000

 

타입 프로퍼티

(저장 프로퍼티, 연산프로퍼티에서만 사용가능)

(인스턴스 생성없이 객체 내에 프로퍼티에 접근을 가능하도록 하는 것 = 프로퍼티 타입 자체와 연결하는 것을 말함)

 ● 타입 프로퍼티는 특정 인스턴스에 속한 프로퍼티를 말합니다.

 ● 값 유형에 대한 타입 프로퍼티를 선언하기 위해서는 ‘static’ 키워드를 사용합니다.

 ● 클래스 유형에 대한 타입 프로퍼티를 선언하기 위해서는 ‘static’와 ‘class’ 키워드를 사용할 수 있

 습니다.

 ● 타입 프로퍼티도 ‘.’을 이용해 프로퍼티의 값을 가져오고 할당할 수 있습니다.

struct SomeStructuer {
    // 스토어
    static var storedTypePeroperty = "Some value."
    // 컴퓨디드
    static var computedTypeProperty : Int {
     return 1
    }
}

SomeStructuer.computedTypeProperty
SomeStructuer.storedTypePeroperty
SomeStructuer.storedTypePeroperty = "hello"
SomeStructuer.storedTypePeroperty

// 인스턴스 생성 없이도 static 을 사용하면 그냥 변경도 가능하다.

// 인스턴스 생성 없이도 static 을 사용하면 그냥 변경도 가능하다.

 

 

반응형