20211026 TIL 구조체와 클래스의 차이 / 싱글턴, 노티피케이션 센터

jane·2021년 11월 1일
0

TIL

목록 보기
2/3

학습 내용

  • 구조체와 클래스의 차이: 값, 참조타입(스택, 힙 메모리)
  • ==와 ===
  • 싱글턴
  • 노티피케이션 센터

구조체와 클래스

값타입 - 값을 복사
참조타입 - 주소값을 전달

  • 선택의 기준?
    어디서나 원본을 수정할 수 있어야 하는가? → 클래스
    어디서 수정해도 원본은 영향을 받지 않게 해야하는가? → 구조체

  • let으로 선언시
    참조타입은 인스턴스를 let으로 선언해도 속성을 바꿀 수 있다. (왜? 값을 가리키고있는 주소를 전달해서 값은 바꾸기 가능)
    값타입은 인스턴스를 let으로 선언하면 속성을 바꿀 수 없다. (왜? 값 자체를 전달해서 값을 못바꿈)

== 와 ===

구조체

== 만 가능

struct Point: Equatable { // 구조체는 Equatable 프로토콜 구체적구현은 안해줘도됨(자동)
    var x: Int
    var y: Int
}

var myHome: Point = Point(x: 50, y: 50)

var codaHome = myHome
codaHome.y = 150

print(myHome == codaHome) //false: 값을 복사해서 할당해서 codaHome에서 속성변경시 myHome과 값이 달라짐

클래스

== 와 === 둘다 가능

class Person: Equatable {
    var name: String
    var weight: Int
    init(name: String, weight: Int) {
        self.name = name
        self.weight = weight
    }
    
    static func == (lhs: Person, rhs: Person) -> Bool {
        return lhs.name == rhs.name && lhs.weight == rhs.weight
				//여기서 정의하기 나름으로 값 비교 가능
				//이름만 같은가? 비교해볼수도 있음 그럼 몸무게 달라도 true 나오겠지..
    }
}

let yagom: Person = Person(name: "yagom", weight: 75)
let coda = yagom

let minime: Person = Person(name: "yagom", weight: 75)

print(coda === yagom) //true: 인스턴스의 주소값을 할당해서 coda나 yagom 이나 동일 인스턴스 가리킴
print(coda == yagom) //true: coda 와 yagom 에게 할당된 값을 비교해봐도 당연히 같음 (같은 주소에 있는 인스턴스의 값을 가져서)

print(minime == yagom) //true: 인스턴스의 주소는 다르지만, 단순히 값은 동일함
print(minime === yagom) //false: 값은 동일하나 다른 인스턴스임

싱글턴?

→ 이걸 이해하기 위해서는 값타입 / 참조타입을 이해해야함

  • private init()? → 새로운 인스턴스를 못만들게 막아놓은거
  • static let? → 유일한 인스턴스를 생성해서 타입 프로퍼티에 할당해 어디서든 접근가능하게

프로젝트 모듈 안에서 딱 하나만 존재해야할 필요가 있는 경우

디자인패턴중 하나

이 타입으로부터 단 하나의 인스턴스만 존재해야할 때 싱글턴을 사용해라

ex) 앱을 사용하고 있는 사용자정보

  • 싱글턴은 클래스(참조타입)로 만들어야함

: 왜 구조체는 안돼?

이 앱에 하나만 존재해야하는데 값타입이라면 다른곳에서 복사를 해갈 수 있으니

class AccountInfo {
		//인스턴스 프로퍼티
    var id: String = ""
    var password: String = ""
    
		//타입 프로퍼티
    static let shared: AccountInfo = AccountInfo() //본인의 인스턴스를 하나 만들어서 그것의 주소값을 담고있음 -> 이렇게 잘 사용하진 않음 
    
    private init() {}
}

//shared는 타입 프로퍼티라 AccountInfo().shared 가 아니라 
let sharedAccountInfo = AccountInfo.shared //만들어놓은 단 하나의 인스턴스를 불러온거임 

shared 의 기본값은 AccountInfo 의 주소값을 들고 있는거고, let이기 때문에 값이 변하지 않음

몇번을 호출해도 같은 값일 것이다.

싱글턴 적용 : 프로젝트 내 하나의 클래스 인스턴스만 사용할 경우 클래스를 싱글턴으로 만들어 사용할 수 있다.

- 싱글턴은 앱 생명주기 내 **한번이라도 호출** 되어야 **인스턴스를 생성**한다.
- 호출 == 뷰컨트롤러 안에서 호출되어야함
class RegistrantManager {
    static let shared = RegistrantManager()

    init() {
        notificationCenter.addObserver(self, selector: #selector(addResistrant), name: didRegistrantInfo, object: nil)
    }
}

노티피케이션 센터 적용하기

  1. 노티피케이션 센터 .default선언
  2. 노티피케이션 이름 설정 (노티 종류 선언)
  3. post: 노티피케이션 센터에게 노티요청
  4. 함수 앞에 @objc 키워드 붙여서 방송 들으면 실행할 함수 선언
  5. addObserver 로 노티피케이션 센터 구독신청하기
import UIKit

//1st 어떤 방송을 때릴지
let didPressButton: Notification.Name = Notification.Name("버튼누름")
let notificationCenter: NotificationCenter = .default

// Model
// 정보가 바뀌지 않으니 구조체가 나음 (클래스보다)
struct Registrant {
    let name: String
    let phoneNumber: String
    
    
}

class ViewController: UIViewController {
    
    @IBOutlet weak var nameTextField: UITextField!
    @IBOutlet weak var phoneNumberTextField: UITextField!
    
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var phoneNumberLabel: UILabel!
    

    // Model
    var registrantList: [Registrant] = []
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        //구독신청 4???
        notificationCenter.addObserver(self,
                                        selector: #selector(showInfo), //[name]방송을 들으면 [selector]를 실행하겠다!
                                        name: didPressButton,
                                        object: nil)
    }
    
    //controller
    @IBAction func hitRegisterButton(_ sender: Any) {
        register()
        
        //view
        nameTextField.text = ""
        phoneNumberTextField.text = ""
    }
    
    @IBAction func hitCheckButton(_ sender: Any) {
    
    }
    
    @objc
    func showInfo() {
        //방송을 듣고나서 해야할 일 3
        let currentIndex = registrantList.count - 1
        nameLabel.text = registrantList[currentIndex].name
        phoneNumberLabel.text = registrantList[currentIndex].phoneNumber
    }
    
    
    
    func register() {
        guard let nameText = nameTextField.text else {
            return
        }
        
        guard let phoneNumberText = phoneNumberTextField.text else {
            return
        }
        
        let personalInfo = Registrant(name: nameText, phoneNumber: phoneNumberText)
        registrantList.append(personalInfo)
        
        // 배열에 연락처 추가한 후에 방송해달라고 방송국에게 요청 2
        notificationCenter.post(name: didPressButton, object: nil)
    }
}
profile
제가 나중에 다시 보려고 기록합니다 ✏️

0개의 댓글