Protocol oriented Programming
- 스위프트의 핵심 패러다임 중 하나
예전에 옵젝씨에서
- 단지기능의 청사진 역할
- 주로 Delegate, DataSource
현재
- protocol extension이 가능해졌다.
특정타입이 할일을 명시해주는 동시에 역할을 해주는 것까지 가능해짐
// MARK: 프로토콜 기본구현
protocol LayoutDrawable {
func drawsomeLayout()
}
class MyView: UIVuew, LayoutDrawable {
}
extension LayoutDrawable {
func drawsomeLayout() {
//...
}
}
이게무슨장점이있는지 ??
저 기본구현을 어떤 클래스나 구조체 열거형이라도 프로토콜을 명시해주면 프로토콜에 있던 기능을 모두 쓸수 있따는게 장점입니다.
왜프로토콜이 탄생했나 ?
- 상속의 한계
- 서로다른 클래스에서 상속받은 클래스는 동일한 기능을 구현하기 위해 중복코드 발생
- 카테고리의 한계 및 부작용
- 프로퍼티 추가 불가
- 오직 클래스에만 적용가능
- 기존 메서드를(자신도 모르게) 오버라이드 가능
- 참조타입의 한계
- 동적 할당과 참조 카운팅에 많은 자원소모(의도치않게 값이 변경되며 할당과 해제 그리고 reference Counting함에 있어서 메모리자원을 많이 소모할 수 있다라는 아이디어에서 출발을 한것)
----protocol-----
class Person: Runable, Talkable, Swimable {}
class Bird: Flyable {}
struct Frog: Runable, Swimable {}
struct Turtle: Swimable {}
struct Fish: Swimable {}
이런 기능을 사용할 수 있다라는걸 명시해주는거지 원래는 내부에 구현을 해줘야하는데 이걸 extension으로 구현해줄 수 있는것이다.
그래서 이걸 어떻게 써먹으라고 ?
POP & Value in Protject
Social Media
기획자: (뚜벅뚜벅 걸어오는발걸음 소리) “테이블 뷰 형식의 타임라인이 필요해요!”
쿼카: ㅇㅋ 뭐…고정정도야뭐… 뚞딲만들어드림 ㄱㄷ
만국박람회처럼 하나의 이미지와 label이 cell담겨 주루루룩 스크롤이가능한
화면이고 하나의 TimeLine을 누르면 DetailView로 넘어가는 구조이다.
class TimeLineTableViewCell: UITableViewCell {
var mediaImageView: UIImageView
var note: UILabel
var content: NSDictionary
}
class DetailViewController: UIViewController {
var mediaImageView: UIImageView
var note: UIlabel
var content: NSDictionary
}
class TimelineTableViewController: UITableViewController {
var contents: [NSDictionary]
}
기획자: “쿼카! 정말 간단한 기능이 더필요해요! 사진첩처럼 볼 수 있는 모드로 추가할 수 있어여 ??”
쿼카: “(음…한번에 말씀합시다요…한번만 봐줌) 예”
무엇부터 건드리져 >?
- Content Model
class Content {
var URLString: String
var note: String
}
음… 근데 class는 메모리를 마이 잡아먹을 수 잇으니 구조체로 하는게 좋을것같음
struct Content {
var URLString: String
var note: String
}
- Model Propetry
class TimelineTableViewController: UITableViewController, ContainContents {}
class TimelineCollectionViewController: UITableViewController, ContainContents {}
protocol ContainContents {
var contents: [Content] { get }
}
class TimelineContentObject {
static let shared = TimelineContentObject()
var contents: [Content] = [Content]()
}
extension ContainContents {
var contents: [Content] {
return TimelineContentObject.shared.contents
}
}
두개의 VC이 같은 데이터를 가질 수 있게 Sington object를 만들어 shared할 수 있게 해줌

그래서 위 사진과같이 두 뷰컨이 하나의 모델의 데이터를 사용하는 구조임
- View
[After]
protocol MediaContainer: class {
var content: Content? { get set }
var media: UIImageView { get }
var note: UILabel { get set }
func contentChanged()
}
extension MediaContainer {
func contentChanged() {
//
}
}
class TimelineTableViewCell: UITableViewCell, MediaContainer {
var media: UIImageView
var note: UILabel
var content: Content? {
didSet {
contentChanged()
}
}
}
class TimelineCollectionViewCell: UICollectionViewCell, MediaContainer {
var media: UIImageView
var note: UILabel
var content: Content? {
didSet {
contentChanged()
}
}
}
class DetailViewController: UIViewController, MediaContainter {
var media: UIImageView
var note: UILabel
var conetnt: Content? {
didSet {
contentChnaged()
}
}
}
TableViewCell, CollectionViewCell, detailViewController, 같은 기능 같은 역할을 수행할 수 있도록 될 수 있다.
- Contoller
TableVC, CollectionVC는 다음 화면으로 넘어가는 기능을 가지고 있다.
이를 protocol로 extension으로 기본구현을 만들어주면 어떨까 ?
protocol CanCHowDetailView {
func showDetailView(withContent content: Content)
var navigationController: UINavigationController? { get }
}
extension CanShowDetailView {
func showDetailView(withContent content: Content) {
//..
}
}
push를 통해 다음화면으로 넘어가기위한 NavigationController property를 가지고 있어야하고 넘어갔을때 화면에 뷰를 띄어줘야하기때문에 showDetailView를 가지는 protocol을 정의한다.
class TimelineTableViewController: UITableViewController, ContainContents, CanShowDetailView {
...
}
class TimelineControllerViewController: UITableViewController, ContainContents, CanShowDetailView {
..
}
프로토콜을 만든것을 적용 시켜주는것이다!!
휴… 드디어끝낸것같다… 좀 쉬어볼까…
.
.
.
기획자: (뚜벅뚜벅뚜벅 걸어오는소리) “쿼카씨! 이거 진짜 간단한건데요! 사진말고 영상도 보여줄 수 없을까요 ??? __”
쿼카: (예? 명치한데 쳐달라구요?) 예?
- 기존에 TableViewCell, ScrollView의 ImageView가 Image와 Video둘다 가능해야하게 만들어야한다…
- protocol
protocol ContnetPresentable: class, Layout {
var frame: CGRect { get set }
var canPresentContent: Bool { set }
}
extension ContentPresentable {
var canPresentContent: Bool {
return true
}
}
extension UIImageView: ContentPresentable {}
extension AVPlayerLayer: ContentPresentable {}
- Protocol/Model
[Before]
struct Content {
var URLString: String
var note: String
}
protocol MediaContainer: class {
var content: Content? { get set }
var media: UIImageView { get }
var note: UILabel { get set }
func contentChanged()
}
extension MediaContainer {
func contentChanged() {
//
}
}
[After]
struct Content {
*enum MediaType {
case image, video
}
var type: Content.MediaType*
var URLString: String
var note: String
}
protocol MediaContainer: class {
var content: Content? { get set }
var media: *ContentPresentblae { get }*
var note: UILabel { get set }
*var videoLayer: AVPlayerLayer { get }
var mediaImageView: UIImageView { get }*
func contentChanged()
}
extension MediaContainer {
func contentChanged() {
//
}
*var media: ContentPresentable {
switch content!.type {
case .image:
return mediaImageView
case .video:
return videoLayer
}
}*
}
=> 영상을 누르면 영상이, 이미지를 누르면 이미지가 나오게된다.
모델 protocol과 struct를 바꿔주는것만으로도 기능을 추가할 수 있었따.
그렇다면 어떤 이점을 얻었나 ??
- 범용적인 사용
- 클래스, 구조체, 열거형 등등 모든 타입에 적용 가능
- 제네릭과 결합하면 더욱 파급적인 효과(=원하는 타입만 들어올 수 있게 해준다고 정해주려면 제네릭을 사용하면된다.)
(Type safe & Flexible code)
- 상속의 한계 극복
- 특정 상속 체계에 중속되지않음
- 프레임워크에 종속적이지않게 재활용 가능
- 적은 시스템 비용
- Reference type cost > Value type cost
- 용이한 테스트
- GUI코드 없이도 수월한 테스트
그렇다면 한계점은 어떤게 있나 ??
- Objective-C Protocol 코드에 Swift Extension 을 붙이게되면 기본 구현부를 작성할 수 가없다.
- 고로 자주 사용되는 Delegate, DataSource 등 프레임워크 프로토콜에 기본 구현 불가
(코코아 터치 코코아 프레임워크는 아직 옵젝씨 DataDelegate, DataSource, TableViewDataSource, TextFiledDelegate등등)
extension UITextFieldDelegate {
func textFieldShouldREturn(textField: UItextField) -> Bool {
textField.endEditing(true)
return true
}
}
extension UITableViewDelegate {
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPAth(indexPath, anumated: true)
}
}
향후 이런 단점을 애플이 보안해준다면 정말 좋을 것…
정리
- Value Type을 사용하여 성능상의 이득을 취하자
- Protocol + Extension + Generic은 환상의 조합이다.
- 이제 상속을 통한 수직 확장이 아닌 Protocol과 Extension을 통한 수평확장과 기능추가를 고민해볼때!..
Reference
- https://youtu.be/9gkzHUsQiUc
- POP in swift WWDC15 408
- Building Better Apps with Value Types in Swift WWDC15 414
- Protocol and Value Oriented Programming in UIkit Apps WWDC16, 419
- Let.Swift Session
- 스위프트 Internals 김정님
- 스위프트 퍼포먼스 이해하기 유용하님
'면접질문정리 > Swift문법' 카테고리의 다른 글
[ing] Closure 값 캡쳐를 사용하는 이유(ex async와 sync) (0) | 2022.05.04 |
---|---|
[Swift] 메서드명을 지을때 get을 지향하라는 말은 출처가 어딜까 ? (0) | 2022.04.29 |
class의 성능을 향상 시킬수 있는 방법들을 나열해보시오. (0) | 2022.01.28 |
COW(Copy On Write)는 어떤 방식으로 동작하는지 설명하시오. (0) | 2022.01.27 |
struct와 class와 enum의 차이를 설명하시오. (0) | 2022.01.24 |