programing

Swift에서 하나 이상의 프로토콜을 준수하는 특정 유형의 변수를 선언하려면 어떻게 해야 합니까?

jooyons 2023. 8. 18. 22:30
반응형

Swift에서 하나 이상의 프로토콜을 준수하는 특정 유형의 변수를 선언하려면 어떻게 해야 합니까?

Swift에서 변수 유형을 다음과 같이 선언하여 명시적으로 설정할 수 있습니다.

var object: TYPE_NAME

더 에 맞는 를 선언하고 만약우리한단더여나계프준러을콜로수토는, 을 사용하면 됩니다.protocol선언적:

var object: protocol<ProtocolOne,ProtocolTwo>//etc

하나 이상의 프로토콜을 준수하고 특정 기본 클래스 유형의 개체를 선언하려면 어떻게 해야 합니까?목표-C 등가물은 다음과 같습니다.

NSSomething<ABCProtocolOne,ABCProtocolTwo> * object = ...;

Swift에서는 다음과 같이 보일 것으로 예상합니다.

var object: TYPE_NAME,ProtocolOne//etc

이를 통해 프로토콜에 정의된 추가 인터페이스뿐만 아니라 기본 유형의 구현을 유연하게 처리할 수 있습니다.

제가 빠질 수 있는 또 다른 확실한 방법이 있나요?

예를 들어, 제가 가지고 있다고 가정해 보세요.UITableViewCell프로토콜에 적합한 세포를 반환하는 책임이 있는 공장.프로토콜에 적합한 셀을 반환하는 일반 함수를 쉽게 설정할 수 있습니다.

class CellFactory {
    class func createCellForItem<T: UITableViewCell where T:MyProtocol >(item: SpecialItem,tableView: UITableView) -> T {
        //etc
    }
}

나중에 나는 유형과 프로토콜을 모두 활용하면서 이 셀들을 해독하고 싶습니다.

var cell: MyProtocol = CellFactory.createCellForItem(somethingAtIndexPath) as UITableViewCell

테이블 보기 셀이 프로토콜을 준수하지 않기 때문에 오류를 반환합니다...

저는 셀이 다음과 같이 지정할 수 있기를 바랍니다.UITableViewCell그리고 그것을 준수합니다.MyProtocol변수 선언에서?

정당성

공장 패턴에 익숙한 경우 특정 인터페이스를 구현하는 특정 클래스의 개체를 반환할 수 있다는 점에서 의미가 있습니다.

제 예와 마찬가지로, 우리는 때때로 특정 객체에 적용할 때 의미가 있는 인터페이스를 정의하는 것을 좋아합니다.테이블 뷰 셀에 대한 나의 예는 그러한 정당성 중 하나입니다.

제공된 유형이 언급된 인터페이스와 정확하게 일치하지 않지만 공장에서 반환하는 개체가 수행되므로 기본 클래스 유형과 선언된 프로토콜 인터페이스 모두와 상호 작용할 수 있는 유연성을 원합니다.

Swift 4에서는 이제 유형의 하위 클래스이며 동시에 하나 이상의 프로토콜을 구현하는 변수를 선언할 수 있습니다.

var myVariable: MyClass & MyProtocol & MySecondProtocol

선택적 변수를 수행하는 방법

var myVariable: (MyClass & MyProtocol & MySecondProtocol)?

또는 메소드의 매개 변수로 사용됩니다.

func shakeEm(controls: [UIControl & Shakeable]) {}

Apple은 세션 402에서 WWDC 2017에서 이를 발표했습니다: Swift의 새로운 기능

둘째, 작곡 수업과 프로토콜에 대해 이야기하고 싶습니다.그래서 저는 약간의 흔들림 효과를 줄 수 있는 UI 요소에 대한 흔들림 없는 프로토콜을 소개했습니다.저는 이 셰이크 기능을 제공하기 위해 UIKit 클래스를 확장했습니다.이제 저는 단순해 보이는 것을 쓰고 싶습니다.저는 그저 흔들릴 수 있는 많은 제어장치들을 가지고 그들에게 관심을 끌 수 있는 것들을 흔드는 기능을 만들고 싶습니다.이 배열에는 어떤 유형을 쓸 수 있습니까?사실은 답답하고 까다롭습니다.그래서 UI 컨트롤을 사용해 볼 수 있었습니다.하지만 이 게임에서 모든 UI 컨트롤이 흔들리는 것은 아닙니다.셰이블을 시도해 볼 수 있지만 모든 셰이블이 UI 컨트롤인 것은 아닙니다.Swift 3에서 이것을 표현할 수 있는 좋은 방법은 없습니다.Swift 4는 임의의 수의 프로토콜로 클래스를 구성하는 개념을 도입합니다.

다음과 같은 변수를 선언할 수 없습니다.

var object:Base,protocol<ProtocolOne,ProtocolTwo> = ...

다음과 같이 함수 반환 유형을 선언하지 않음

func someFunc() -> Base,protocol<MyProtocol,Protocol2> { ... }

이렇게 함수 매개변수로 선언할 수 있지만 기본적으로 업캐스팅입니다.

func someFunc<T:Base where T:protocol<MyProtocol1,MyProtocol2>>(val:T) {
    // here, `val` is guaranteed to be `Base` and conforms `MyProtocol` and `MyProtocol2`
}

class SubClass:BaseClass, MyProtocol1, MyProtocol2 {
   //...
}

let val = SubClass()
someFunc(val)

현재로서는 다음과 같은 방법밖에 없습니다.

class CellFactory {
    class func createCellForItem(item: SpecialItem) -> UITableViewCell {
        return ... // any UITableViewCell subclass
    }
}

let cell = CellFactory.createCellForItem(special)
if let asProtocol = cell as? protocol<MyProtocol1,MyProtocol2> {
    asProtocol.protocolMethod()
    cell.cellMethod()
}

해서 말하면 이으로, 기으로적.cell는 와동합다니와 동일합니다.asProtocol.

하지만, 컴파일러에 관해서는,cell의 인터페이스가 있습니다.UITableViewCell 만다에, 면반에.asProtocol프로토콜 인터페이스만 있습니다.그래서, 당신이 전화하고 싶을 때.UITableViewCell은 의메드사합야니다용해는소를 cellcall method는 protocols method합니다.asProtocol변수.

이 셀이 은 셀프로콜준는것이확됩사않다니아이를 하지 않아도 됩니다.if let ... as? ... {} 예:

let cell = CellFactory.createCellForItem(special)
let asProtocol = cell as protocol<MyProtocol1,MyProtocol2>

안타깝게도 Swift는 개체 수준 프로토콜 준수를 지원하지 않습니다.그러나 사용자의 목적에 적합할 수 있는 다소 어색한 해결 방법이 있습니다.

struct VCWithSomeProtocol {
    let protocol: SomeProtocol
    let viewController: UIViewController

    init<T: UIViewController>(vc: T) where T: SomeProtocol {
        self.protocol = vc
        self.viewController = vc
    }
}

그런 다음, UIViewController가 가지고 있는 모든 작업을 수행해야 하는 경우 구조의 .viewController 측면과 프로토콜 측면에 액세스하여 .protocol을 참조할 수 있습니다.

예:

class SomeClass {
   let mySpecialViewController: VCWithSomeProtocol

   init<T: UIViewController>(injectedViewController: T) where T: SomeProtocol {
       self.mySpecialViewController = VCWithSomeProtocol(vc: injectedViewController)
   }
}

이제 UIViewController와 관련된 작업을 수행하기 위해 SpecialViewController가 필요할 때마다 SpecialViewController.viewController를 참조하고 프로토콜 기능을 수행하기 위해 필요할 때마다 SpecialViewController.protocol을 참조합니다.

향후 Swift 4를 통해 프로토콜이 부착된 개체를 선언할 수 있기를 바랍니다.하지만 지금은 효과가 있습니다.

이것이 도움이 되길 바랍니다!

에디트: 제가 잘못 생각했습니다만, 저처럼 다른 누군가가 이 오해를 읽는다면, 저는 이 대답을 밖에 남깁니다.OP는 주어진 하위 클래스의 객체에 대한 프로토콜 적합성 확인에 대해 물었고, 그것은 수용된 답변이 보여주는 다른 이야기입니다.이 답변은 기본 클래스에 대한 프로토콜 준수에 대해 설명합니다.

제가 잘못 알고 있는 것일 수도 있지만, 프로토콜 준수를 추가하는 것에 대해 말씀하시는 것은 아닙니다.UITableCellView클래스? 이 경우 프로토콜은 개체가 아닌 기본 클래스로 확장됩니다.다음과 같은 확장 프로토콜 채택 선언에 대한 Apple 문서를 참조하십시오.

extension UITableCellView : ProtocolOne {}

// Or alternatively if you need to add a method, protocolMethod()
extension UITableCellView : ProcotolTwo {
   func protocolTwoMethod() -> String {
     return "Compliant method"
   }
}

이미 참조된 Swift 설명서 외에도 다른 예제와 호환되지 않는 유형에 대한 Nate Cooks 문서 일반 함수도 참조하십시오.

이를 통해 프로토콜에 정의된 추가 인터페이스뿐만 아니라 기본 유형의 구현을 유연하게 처리할 수 있습니다.

제가 빠질 수 있는 또 다른 확실한 방법이 있나요?

Protocol Adoption(프로토콜 채택)은 이를 수행하여 개체가 지정된 프로토콜을 준수하도록 합니다.그러나 주어진 프로토콜 유형의 변수는 프로토콜 외부에 대해 아무것도 알지 못한다는 단점을 인식해야 합니다.그러나 필요한 모든 방법/변수/...를 포함하는 프로토콜을 정의하면 이 문제를 피할 수 있습니다.

제공된 유형이 언급된 인터페이스와 정확하게 일치하지 않지만 공장에서 반환하는 개체가 수행되므로 기본 클래스 유형과 선언된 프로토콜 인터페이스 모두와 상호 작용할 수 있는 유연성을 원합니다.

일반 메서드, 변수가 프로토콜 및 기본 클래스 유형을 모두 준수하도록 하려면 운이 없을 수 있습니다.그러나 필요한 적합성 방법을 가질 수 있을 정도로 프로토콜을 광범위하게 정의하는 동시에 너무 많은 작업 없이 기본 클래스에 채택할 수 있는 옵션을 가질 수 있을 정도로 좁게 정의해야 합니다(즉, 클래스가 프로토콜을 준수한다고 선언하는 것).

저는 Storyboards에서 일반적인 인터렉터 연결을 연결하려고 할 때 비슷한 상황을 겪은 적이 있습니다. (IB는 단순히 기본 클래스 공용 ivar를 개인 계산 속성으로 마스킹하여 사용했습니다.)이렇게 하면 다른 사용자가 잘못된 할당을 하는 것 자체를 방지할 수는 없지만 런타임에 부적합 인스턴스와의 원하지 않는 상호 작용을 안전하게 방지할 수 있는 편리한 방법을 제공합니다.(즉, 프로토콜을 준수하지 않는 개체에 위임 메서드를 호출하지 못하도록 합니다.)

예:

@objc protocol SomeInteractorInputProtocol {
    func getSomeString()
}

@objc protocol SomeInteractorOutputProtocol {
    optional func receiveSomeString(value:String)
}

@objc class SomeInteractor: NSObject, SomeInteractorInputProtocol {

    @IBOutlet var outputReceiver : AnyObject? = nil

    private var protocolOutputReceiver : SomeInteractorOutputProtocol? {
        get { return self.outputReceiver as? SomeInteractorOutputProtocol }
    }

    func getSomeString() {
        let aString = "This is some string."
        self.protocolOutputReceiver?.receiveSomeString?(aString)
    }
}

"outputReceiver"는 개인 "protocolOutputReceiver"와 마찬가지로 선택 사항으로 선언됩니다.항상 후자(계산된 속성)를 통해 outputReceiver(대리인)에 액세스함으로써 프로토콜을 준수하지 않는 개체를 효과적으로 필터링합니다.이제 옵션 체인을 사용하여 프로토콜 구현 여부나 존재 여부에 관계없이 위임 개체를 안전하게 호출할 수 있습니다.

이를 상황에 적용하려면 "YourBaseClass?"(AnyObject와 반대로) 유형의 공용 ivar를 사용하고 개인 계산 속성을 사용하여 프로토콜 준수를 적용할 수 있습니다.FWIW.

언급URL : https://stackoverflow.com/questions/26401778/in-swift-how-can-i-declare-a-variable-of-a-specific-type-that-conforms-to-one-o

반응형