호댕의 iOS 개발

[TIL] 21. 10. 24 Today I Learned 본문

Software Engineering/TIL

[TIL] 21. 10. 24 Today I Learned

호르댕댕댕 2021. 10. 24. 20:03

이번 주는 MVC, NotificationCenter, Instance, Type 등에 대해 중점적으로 배웠다. Instance와 Type, Property, Method의 경우 충분히 이해가 됐지만 MVC와 NotificationCenter는 아직 어떻게 사용하면 좋을지 정확히는 모르겠다. 

이 부분은 계속 프로젝트에 접목시켜 보면서 이해할 수 있도록 해야겠다. 

 

# 이번 주 한 일 

  • Properties 공식문서 보기 (Stored Prpperties까지)
  • Initialization 공식문서 보기 (Default Initializers까지)
  • Properties 공식문서 보기
  • Structures and Classes 공식문서 보기 
  • Access Control 공식문서 보기
  • Choosing Between Structures and Classes 공식문서 보기
  • 야곰아카데미 활동학습 (월, 목)
  • 페어프로그래밍 규칙 정하기 
  • 프로젝트 Step 1 진행
  • NotificationCenter 활동학습 영상 복습
  • 야곰닷넷 왕초보 앱 만들기 강의 다시 보기 → Step 2에 적용할 부분 찾아보기
  • Swift Playgrounds 유형 관련 설명 보기 (계속 돌려보자~)
  • 피드백 내용 수정
  • 프로젝트 Read Me 작성하기
  • Singleton 공부 

 

# 새롭게 안 내용

# 왜 타입을 쪼개는 것일까?

분명 하나의 타입에 모든 코드를 작성할 수도 있다. 그렇다면 왜 타입을 쪼개는 것일까?
실생활에서도 치킨 가게를 한다고 가정해보자.
이 때 대부분의 가게에선 점원들이 분업화해서 업무를 하고 있다. (닭 튀기는 사람, 서빙, 포장, 배달, 계산 등등…)
이렇게 하면 만약 서빙을 하는 사람이 못 나오게 되더라도 서빙을 할 수 있는 사람만 구하면 충분히 가게 운영이 가능하다.
하지만 분업이 안되어 있고 한 사람이 위의 모든 일을 한다면 어떻게 될까?
이 사람이 일을 못하게 되면 아예 가게 운영이 되지 않는다.

코드에서도 마찬가지이다. 책임을 쪼개서 대체할 수 있도록 하기 위함이다. 함수 또한 하나의 단위로 쪼갰을 때 하는 일도 명확해지고(이름도 짓기 쉬워짐) 고장나도 보수를 하기 좋아진다.

# convenience init

convenience init은 추가적인 이니셜라이저를 만들어줘서 인스턴스를 새롭게 생성할 때 초기화의 선택지를 주는 것이다.

class Person {
    let name: String
    let hobby: String
    let age: Int
    
    init(name: String, hobby: String, age: Int) {
        self.name = name
        self.hobby = hobby
        self.age = age
    }
    
    convenience init(name: String, hobby: String) {
        self.init(name: name, hobby: hobby, age: 25)
    }
}

위 예시에서 보면 init에서 `name`, `hobby`, `age`를 전부 각각 받아주고 있다. 

여기서 추가로 `convenience init`을 사용하면 age에는 기본값을 설정하고 `name`과 `hobby`만 받을 수도 있다. 

Person이란 클래스를 초기화할 때 Person(name: , hobby: , age: )라고 초기화를 할 수도 있고, Person(name: , hobby: )이렇게만 초기화를 할 수 있는 것이다. 

 

즉, 코드를 보다 유연하게 사용할 수 있게 된다. 

 

# NotificationCenter

코드에서 서로 종속되는 관계가 많아지는 것은 좋지 않다. 따라서 Notification은 직접 호출하지 않고 이벤트를 알려주게 된다. Event Driven Programming에도 적합한 방법이다.

이에 대해 예시 코드를 만들어 보았다…

 

let startedBroadcast: Notification.Name = Notification.Name("방송 시작")
let notificationCenter: NotificationCenter = .default 

class BroadcastStation {
    var viewerCount: Int
    
    @objc
    func recievedinformation() {
        viewerCount = viewerCount + 1
    }
    
    func checkViewerNumber() {
        print("현재 시청자 수는 \(viewerCount)입니다.")
    }
    
    init(number: Int) {
        self.viewerCount = number
        print("현재 시청자 수는 \(number)명 입니다.")
        
        notificationCenter.addObserver(self, selector: #selector(recievedinformation), name: startedBroadcast, object: nil)
    }
}

class Viewer {
    let name: String
    
    init(name: String) {
        self.name = name
        print("나는 시청자 \(name)")
    }
    
    func watchBroadcast() {
        notificationCenter.post(name: startedBroadcast, object: nil)
        print("방송 보는 중")
    }
}

let tvn = BroadcastStation(number: 0)
let hojoon: Viewer = Viewer(name: "hojoon")

hojoon.watchBroadcast()
tvn.checkViewerNumber()

위 예시에선 먼저 notificationCenter를 만들어줬다. 여기서 NotificationCenter = .default라고 설정해주면 전역적으로 방송?을 해주게 된다.

또한 Viewer는 방송을 보고 있다는 것을 보내준다.

그러면 BroadcastStation은 이걸 받아서 시청자 수를 1 늘려주게 된다.

 

# error: failed to push some refs to ‘주소’

프로젝트를 진행하고 원격저장소에 push를 하는 과정에서 이와 같은 오류가 떴다.
분명 commit도 잘했는데 발생한 오류라 왜 이런 오류가 생겼는지 당황스러웠다… 코드도 간단하게 수정했었는데…

위 오류는 원격 저장소와 로컬 저장소의 상태가 달라서 발생하는 오류이다.
즉, Pull하는 것을 잊어버리고 push를 해서 오류가 발생한 것이었다… 코드를 작성할 때 잊지말고 pull을 하자

 

# Optional

스위프트 optional의 선언을 보면 다음 코드와 같이 열거형으로 선언되어 있다.

enum Optional<Wrapped> {
  case none // nil
  case some(Wrapped) // optional value
}
Comments