아직 집중력이 다 돌아오지 않았다. 원하는 만큼 공부하기는 어려웠다. 코어타임을 바꿔보았음!
뽀모도로 없이도 집중이 가능했으나 사실상 롱타임으로는 뽀모도로 만큼의 유지력이 있었음(체력 및 집중력이슈)
그래도 독서와 좋은 글을 많이 봐서 좋았다.
생각해보니 중간에 BlackjackCard 공식문서 예시와 self Self 예시를 코드로 복습하면서 조금 더 시간이 걸렸다. 하지만 굿 !
(자세한 내용은 보안 및 저작권이슈로 적지 않을 예정, 평소에도 주의하는 부분이고 오늘은 특히 더 주의할 예정이다. 사실 친절하게 적지않기 때문에 나의 글을 찾아볼 분들은 없을거라고 예상하지만 어쨌든 누군가는 보는 공간이니)
오늘 프로토콜을 마무리하고, 메서드 디스패치(아기다리고기다리던) 중첩타입(약간 아주 알짜만 빼고는 개념만 남아서 흐려졌는데 오늘 다시 복기한 느낌) self 키워드를 복습했다.
생각보다 self 키워드가 그 당시에 이해를 좀 덜했던 건지 어렵진 않았지만 필기할때 오래걸렸음
프로토콜은 잘 만들었다. 그리고 가벼워서 좋다 라는 생각을 하게 해주었고, 중첩타입은 애플 공식문서 예제가 너무너무 좋은 것 같다. 여러번 볼필요!
self 키워드는 잘 알아두면 (물론 쓰다보면 알게되겠지만) 좋겠다는 생각. 메서드 디스패치는 여러번 봐도 재밌고, 오히려 이해가 잘 가서 좋았다.
내용이 길어서 알짜+내가 헷갈렸던 부분 위주로 복기해 볼 예정이다
프로토콜의 탄생원리 처럼 다중상속이 가능하다는 장점이 있다.
Any가 타입인것과 대조되게, AnyObject 키워드는 정확히는 프로토콜을 의미한다. 클래스 전용 프로토콜로 제한(?)할때 쓸 수 있다
프로토콜을 합성해서 사용하면(Named&Aged) 임시타입으로 활용이 가능하다(두가지 프로토콜을 전부 채택한 타입을 명시해줌)
어트리뷰트 키워드 @objc 프로토콜 (내부 요구사항앞에는 @objc optional) 를 사용해 프로토콜의 요구사항을 선택적으로 구현하도록 열어줄 수 있다. > 이때 채택한 타입에서 구현한 메서드를 접근시에는 ?가 붙는다 swift.isProtocol?() 처럼
프로토콜은 확장도 가능하다!(정말 클래스의 대체품 같기도 한 / 구조체는 다른용도라면 프로토콜은 클래스의 단점을 보완하는 느낌이다) 확장형내에서 요구사항을 기본구현해서 전달 가능하다. (다만 이때 확장형에서 기존 프로토콜 본체에 있었던 메서드(witness Table) 외의 추가메서드는 direct Dispatch 방식으로 적용된다)
이때 헷갈리면 안되는 부분은 확장형에서도 요구사항을 기본구현했고, 채택한 타입에서도 요구사항을 구현했다면 타입의 내용이 우선이다(이 내용을 똑같이 (함수 명령어 메모리 주소를) 프로토콜은 자신의 witness Table에도 넣는다. 즉 프로토콜의 witness Table과 클래스의 Virtual Table의 내용이 이경우에는 달라질 일이 없다) / 하지만 확장형에서 추가로 구현해준 메서드가 있다면 이는 클래스에서 구현을 따로 해줬다고 했을때 인스턴스가 어떤타입으로 인식하는지(지정되는지)에 따라 클래스의 Virtual Table을 보거나, Direct Dispatch를 보게 되므로 내용이 바뀌게 된다.
프로토콜의 위의 내용은 머릿속으로 그림을 그릴수 있다면 좋다(클래스와 구조체의 차이처럼)
즉 프로토콜은 우선순위를 따져서, 자신의 witness Table에 넣는다
번외로 구조체는 Direct Dispatch 를 ,확장을 하게되면 구조체, 클래스, 프로토콜 모두 Direct Dispatch 하게 되는데 이때 @objc dynamic 키워드 사용시 클래스의 경우 재정의가 가능해진다(원래는 재정의가 안되니까 상속고려 안해도 되는 효과가 나서 Direct 할수있었던 건데..라고 생각하면 쉽다)
구조체의 인스턴스는 프로토콜 채택한 경우 크기에 따라 힙 혹은 스택에 저장가능성 있다
Dynamic 동적 디스패치는 어떤식으로 동작하는지 고민해보면 이름의 의미를 더 잘 알수있다.
Message Dispatch 는 object C 에서 사용하던 방법으로 다이나믹 디스패치와는 다른 방식으로 부모/자식 관계에서의 메서드 구조가 이뤄진다. (흥미진진)
당연히 재정의 하면 다른 함수이므로 다른 코드를 가르킨다(주소다름)
함수는 명령어의 묶음이라는 걸 늘 인지할것
타입내부에 관련있는 (주로 이렇게 쓰기위해 중첩타입을 쓴다. 연관성과 구조고려) 타입을 쓰는경우
타입을 반드시 명시하거나 생성자쪽에서 정확히 생성자를 풀네임으로 명시해야한다(생각해보면 당연하다. 축약해서 사용하면 이름만으로는 이게 내부의 정확히 어디인지 알수가 없을 가능성이 크다)
공식문서 예제가 매우 재밌으니 여러번 보자!이런 구현도 되는구나 싶어서 흥미로웠다. 특히 열거형 내부에서 또 구조체를 중첩하고 해당 구조체 내부 저장속성을 self로 열거형 자기자신을 불러와서 case별로 바꿔주는 계산속성을 열거형내부에 다시 멤버로 정의하는 것 등등 재미있다.
strunct BlackjackCard {
enum Suit: Character {
case spades="",hearts="",diamonds="",clubs=""
}
enum Rank: Int {
case two = 2, three, four, five, six, seven, eight, nine, ten
case jack, queen, king, ace
struct Values {
let first: Int, second: Int?
}
var values: Values {
switch self {
case .ace:
return Values(first: 1, second: 11)
case .jack, .queen, .king:
return Values(first:10, second: nil)
default:
return Values(first: self.rawValue, second: nil)
}
}
let rand: Rank, suit: Suit
var description: String {
var output = "\(suit.rawValue)세트,"
output += "숫자 \(rank.values,first)"
if let second = rank.values.second {
output += "또는 \(second)"
}
return output
}
}
많은 애플이 구현해놓은 것들이 중첩을 썼는데 그럴수밖에 없다는 생각이 든다(정리를 잘해놨다고 해야하나)
다양하게 활용가능
(이부분도 보안상 간략히 적겠다)
소문자 self는 인스턴스, 대문자 Self는 타입
소문자에서 세번째, 네번째 경우를 잘 이해해보자 (이름은 타입으로 같지만 가르키는건 전혀다르다는 것을 예전필기만 보고서는 순간 헷갈릴뻔했더랬다)
만약 static func 가 아닌 func 라면 내부에서 어떻게 타입멤버를 불러올 수 있을지 생각해보자
대문자 Self는 만약 소문자 self로 썼다면 어떤 의미를 가지게 될지 예제를 떠올리며 생각해보자
프로토콜에서 Self 사용시 매우매우 편리해진다! (일종의 타입확장)
정리해보니 어제보다 많지는 않은 것 같다.
내일은 재밌지만 아찔할 것 같은 클로저. 화이팅!
스위프트에게 샤라웃