어떤 이유로 Swift의 각 델리게이트에 대해 별도의 클래스 확장을 사용 하시겠습니까?


13

Ray Wenderlich 튜토리얼을 진행하면서 저자가 클래스 확장을 사용하여 델리게이트 콜백을 클래스 자체에서 처리하지 않고 델리게이트 콜백을 유지하는 것으로 나타났습니다.

클래스 확장 내에서 콜백 위임 :

extension LogsViewController : UIPopoverPresentationControllerDelegate {
    func adaptivePresentationStyleForPresentationController(controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
        ...
    }
}

클래스 내에 포함시키는 것과는 대조적으로 :

클래스 내 콜백 위임 :

class LogsViewController : UITableViewController, UIPopoverPresentationControllerDelegate {
    func adaptivePresentationStyleForPresentationController(controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
        ...
    }
}

나는이 이상하고 흥미로운 동시에 발견했다. 그는 "LogsViewControllerExtension.swift"라는 LogsViewController 클래스의 확장자 전용 파일을 가지고 있으며 각 델리게이트 프로토콜에 대해 UITableViewDataSource, UISplitViewDelegate 등의 확장자가 다릅니다.

자체 파일 내에서 델리게이트 콜백이있는 여러 클래스 확장 :

extension LogsViewController: UISplitViewControllerDelegate {
    ... callbacks
}

extension LogsViewController : UIPopoverPresentationControllerDelegate {
    ... callbacks
}

왜?

이를 수행하면 어떤 이점이 있습니까? 이것을 분리하는 것이 조금 더 읽기 쉬운 위치를 알 수 있지만 동시에 간접적 인 수준입니다. 이를 지원하거나 반대하는 OO 원칙이 있습니까?


1
OO 원칙에 의해 기본적으로 지원되지만 여전히 과도한 엔지니어링에 유죄가되는 많은 구조를 작성할 수 있습니다.
Robert Harvey

1
@RobertHarvey 사실이지만, 여기에 표시된 예제 코드가 오버 엔지니어링의 형태라는 것을 암시합니까? 위임은 iOS 개발에서 일반적인 패턴입니다. 또한 클래스 확장을 사용하든 아니든 코드 내에서 코드를 변경하지 않으므로 re (/ over)
엔지니어링

1
동일한 파일에 많은 확장명을 던지는이 패턴을보고 있으며 이것이 어디에서 왔는지 모르겠습니다. 일부 사람들은 이미 그것을 남용하고 있으며 임의의 작은 코드를 동일한 파일 내의 확장명으로 임의로 던지는 것 같습니다. 나는 때때로 이것을하는 좋은 이유가 있다고 확신하지만, 일부 프로그래머가 이유를 이해하지 않고 그냥하고 있다는 인상을 얻습니다. 나는 MARK를 사용하는 것보다 이것의 이점을 계속 찾고 있습니다.-왜 이런 식으로 확장을 사용해야하는지에 대한 확실한 소스를 찾고 싶습니다.
David Lari

답변:


15

왜 이것이 간접적 인 수준을 추가한다고 말했는지 모르겠습니다. 어쩌면 전통적인 의미와 다른 의미를 가질 수도 있습니다. 왜냐하면이 작업을 통해 생성 된 추가 간접 지시가 없기 때문입니다. 그러나 왜 그렇습니까?

더 모듈식이 기 때문에 나는 그것을합니다. 인터페이스에 필요한 모든 코드는 단일 위치 (실제 속성 제외)로 그룹화됩니다. 나중에 해당 프로토콜을 구현하기 위해 별도의 클래스를 만들도록 선택하면 (실제로 간접적 인 수준의 간접 참조) 필요한 경우 확장 기능을 자체 클래스로 변경하고 (init 함수를 통해 필요한 속성을 전달) ViewController에서 객체를 인스턴스화 할 속성을 만듭니다.

또한 해당 프로토콜의 기능에 의해서만 사용되는 개인 기능을 확장에 넣습니다. 나는 확장을 위해 완전히 별도의 파일을 만들려고하지 않았지만 그렇게하면 개인 기능이 해당 프로토콜에만 해당된다는 것이 분명해집니다.

어쨌든 사람들은 종종 팻 뷰 컨트롤러에 대해 불평하고 뷰 컨트롤러를 이런 식으로 분해하면 실제로 뷰 컨트롤러를 더 얇게 만들지 않아도 더 잘 정리할 수 있습니다.


나는 당신이 모듈성에 의해 무엇을 의미하는지 안다. 내가 무슨 일이 일어나고 있는지 이해하면 문제를 깨끗하게 분리하는 것처럼 보였습니다. 내가 생각하는 간접적 인 수준은 새로운 눈을위한 것입니다 (그리고 Obj-c 방식에서 비롯됩니다). 코드가 참조되는 하위 클래스를 만들 때 기본 클래스의 다른 곳에 정의되어 있고 찾기가 좀 더 어려울 때와 동일한 수준의 간접 성을 느낍니다. 나는 조직적으로는 (약간의 간접 비용으로) 혜택을 추가 동의
morbidhawk

나는 이것이 Obj-C의 클래스 범주로 전에 이루어 졌다고 생각합니다. 나는 그 사람들의 팬이 아니었지만 별도의 파일이 필요하다고 생각합니다. 이제 Swift에서 확장명을 같은 파일에 보관할 수 있습니다. 파일을 그렇게하기로 결정한 경우 아마도 그렇게 할 것입니다.
morbidhawk

2

다니엘이 간접 지정에 관해 말했듯이, 그것의 수준은 없습니다.
동의하고 최근에 알고있는 프로토콜 확장 기능을 더욱 강력하게 추가하고 싶습니다.

didCopyText예를 들어 프로토콜이 있다고 가정하십시오 . 이를 다음과 같이 구현합니다.

protocol didCopyText {
  var charachtersCount: Int {get}
  func addToClipboardWith(text: String)
}

Swift에서 속성과 메소드는 프로토콜 선언에서 구현되지 않습니다. 모든 클래스에 구현을 작성하고 싶을 didCopyText때 동일한 구현 으로이 프로토콜을 준수하는 증가하는 수의 클래스를 사용하면 결국 지저분한 것입니다. 반복되는 코드. 프로토콜 확장이 유용한 곳입니다.

protocol didCopyText {
var charachtersCount: Int {
    get {
     // implementation
    }
}
func addToClipboardWith(text: String) {
      // implementation
 }
}

프로토콜의 속성 및 메소드 구현 이제 모든 클래스가이 프로토콜을 준수하며 동일한 구현을 사용합니다.


이것을 공유해 주셔서 감사합니다. 이 질문을 할 당시 OO 상속의 몇 가지 단점에 대해 알지 못했으며 여기에 설명하는 것은 해당 인터페이스를 준수하는 모든 구현 클래스에서 동일한 기능을 재사용 할 수있는 좋은 방법입니다. 객체에서 모든 것을 상속받습니다. 또한 인터페이스 분리 원칙을 따르는 경우 구현 클래스가 필요하지 않은 인터페이스에서 속성 / 방법을 갖지 않도록 프로토콜을 필요에 따라 분리 할 수 ​​있습니다.
morbidhawk

1

클래스가 세 개의 프로토콜을 지원하므로 세 개의 함수 세트를 추가해야한다고 가정 해 봅시다. 이 기능의 유일한 목적은 프로토콜을 지원하는 것이므로 문서가 필요합니다.

그러나 각 프로토콜에 대한 확장을 추가하고 각 확장에서 해당 프로토콜에 필요한 기능을 정확하게 구현하면 코드를 더 읽기 쉽게 만들 수 있습니다.

이 확장명이 실제로 크지 않으면 별도의 파일에 넣지 않을 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.