development

Swift 프로토콜에서 선택적 방법을 정의하는 방법은 무엇입니까?

big-blog 2020. 3. 3. 23:03
반응형

Swift 프로토콜에서 선택적 방법을 정의하는 방법은 무엇입니까?


스위프트에서 가능합니까? 그렇지 않은 경우 해결 방법이 있습니까?


1. 기본 구현 사용 (권장).

protocol MyProtocol {
    func doSomething()
}

extension MyProtocol {
    func doSomething() {
        /* return a default value or just leave empty */
    }
}

struct MyStruct: MyProtocol {
    /* no compile error */
}

장점

  • Objective-C 런타임이 필요하지 않습니다 (적어도 명시 적으로는 아님). 즉, 구조체, 열거 형 및 비 NSObject클래스를 준수 할 수 있습니다 . 또한 강력한 제네릭 시스템을 활용할 수 있습니다.

  • 이러한 프로토콜을 준수하는 유형을 만날항상 모든 요구 사항이 충족되는지 확인할 수 있습니다 . 항상 구체적인 구현이거나 기본 구현입니다. "인터페이스"또는 "계약"이 다른 언어로 작동하는 방식입니다.

단점

  • Void요구 사항이 아닌 경우 적절한 기본값을 가져야 하지만 항상 가능하지는 않습니다. 그러나이 문제점이 발생하면 해당 요구 사항에 실제로 기본 구현이 없거나 API 설계 중에 실수를 한 것입니다.

  • 적어도 특별한 반환 값으로 그 문제를 해결하지 않고 는 기본 구현과 구현하지 않음을 구별 할 수 없습니다 . 다음 예제를 고려하십시오.

    protocol SomeParserDelegate {
        func validate(value: Any) -> Bool
    }
    

    방금 반환하는 기본 구현을 제공하면 true언뜻보기에 괜찮습니다. 이제 다음 의사 코드를 고려하십시오.

    final class SomeParser {
        func parse(data: Data) -> [Any] {
            if /* delegate.validate(value:) is not implemented */ {
                /* parse very fast without validating */
            } else {
                /* parse and validate every value */
            }
        }
    }
    

    이러한 최적화를 구현할 수있는 방법은 없습니다. 대리인이 메소드를 구현하는지 여부를 알 수 없습니다.

    이 문제를 극복 할 수있는 여러 가지 방법이 있지만 (선택적 클로저, 서로 다른 작업에 대한 다른 대리자 개체를 사용하여) 몇 가지 방법으로 문제를 명확하게 보여줍니다.


사용 @objc optional.

@objc protocol MyProtocol {
    @objc optional func doSomething()
}

class MyClass: NSObject, MyProtocol {
    /* no compile error */
}

장점

  • 기본 구현이 필요하지 않습니다. 선택적인 메소드 나 변수를 선언하면 준비가 완료됩니다.

단점

  • 모든 준수 유형이 Objective-C와 호환되도록 요구 하여 프로토콜의 기능심각하게 제한합니다 . 즉, 상속받은 클래스 만 NSObject이러한 프로토콜을 준수 할 수 있습니다. 구조체, 열거 형, 관련 형식이 없습니다.

  • 선택적으로 적합한 유형을 구현하는지 여부를 선택적으로 호출하거나 확인 하여 선택적 방법이 구현되었는지 항상 확인해야 합니다. 선택적 메소드를 자주 호출하는 경우 많은 상용구가 발생할 수 있습니다.


Swift 2 이상에서는 프로토콜의 기본 구현을 추가 할 수 있습니다. 이것은 프로토콜에서 새로운 선택적인 방법을 만듭니다.

protocol MyProtocol {
    func doSomethingNonOptionalMethod()
    func doSomethingOptionalMethod()
}

extension MyProtocol {
    func doSomethingOptionalMethod(){ 
        // leaving this empty 
    }
}

선택적 프로토콜 메소드를 작성하는 것은 좋은 방법은 아니지만 프로토콜 콜백에서 구조체를 사용할 수 있습니다.

나는 여기에 작은 요약을 썼다 : https://www.avanderlee.com/swift-2-0/optional-protocol-methods/


선택적 수정 자@objc 속성 을 사용하여 선택적 요구 사항 프로토콜을 정의 하는 방법에 대한 답변 이 있으므로 프로토콜 확장을 사용하여 선택적 프로토콜을 정의하는 방법에 대한 샘플을 제공합니다.

아래 코드는 Swift 3. *입니다.

/// Protocol has empty default implementation of the following methods making them optional to implement:
/// `cancel()`
protocol Cancelable {

    /// default implementation is empty.
    func cancel()
}

extension Cancelable {

    func cancel() {}
}

class Plane: Cancelable {
  //Since cancel() have default implementation, that is optional to class Plane
}

let plane = Plane()
plane.cancel()
// Print out *United Airlines can't cancelable*

프로토콜 확장 메소드는 Objective-C 코드로 호출 할 수 없으며 Swift 팀은이를 수정하지 않습니다. https://bugs.swift.org/browse/SR-492


다음은 위임 패턴이있는 구체적인 예입니다.

프로토콜 설정 :

@objc protocol MyProtocol:class
{
    func requiredMethod()
    optional func optionalMethod()
}

class MyClass: NSObject
{
    weak var delegate:MyProtocol?

    func callDelegate()
    {
        delegate?.requiredMethod()
        delegate?.optionalMethod?()
    }
}

델리게이트를 클래스로 설정하고 프로토콜을 구현하십시오. 선택적 메소드를 구현할 필요가 없음을 참조하십시오.

class AnotherClass: NSObject, MyProtocol
{
    init()
    {
        super.init()

        let myInstance = MyClass()
        myInstance.delegate = self
    }

    func requiredMethod()
    {
    }
}

한 가지 중요한 점은 선택적 방법이 선택적이며 "?"가 필요하다는 것입니다. 전화 할 때. 두 번째 물음표를 언급하십시오.

delegate?.optionalMethod?()

신속한 특정 유형을 사용하는 경우 프로토콜을 "@objc"로 표시하는 것과 관련된 다른 답변은 작동하지 않습니다.

struct Info {
    var height: Int
    var weight: Int
} 

@objc protocol Health {
    func isInfoHealthy(info: Info) -> Bool
} 
//Error "Method cannot be marked @objc because the type of the parameter cannot be represented in Objective-C"

신속하게 작동하는 선택적 프로토콜을 선언하려면 함수를 func 대신 변수로 선언하십시오.

protocol Health {
    var isInfoHealthy: (Info) -> (Bool)? { get set }
}

그런 다음 다음과 같이 프로토콜을 구현하십시오.

class Human: Health {
    var isInfoHealthy: (Info) -> (Bool)? = { info in
        if info.weight < 200 && info.height > 72 {
            return true
        }
        return false
    }
    //Or leave out the implementation and declare it as:  
    //var isInfoHealthy: (Info) -> (Bool)?
}

그런 다음 "?"를 사용할 수 있습니다. 기능 구현 여부 확인

func returnEntity() -> Health {
    return Human()
}

var anEntity: Health = returnEntity()

var isHealthy = anEntity.isInfoHealthy(Info(height: 75, weight: 150))? 
//"isHealthy" is true

에서 스위프트 3.0

@objc protocol CounterDataSource {
    @objc optional func increment(forCount count: Int) -> Int
    @objc optional var fixedIncrement: Int { get }
}

시간을 절약 할 수 있습니다.


  • optional각 방법 전에 키워드 를 추가해야합니다 .
  • 그러나 이것이 작동 하려면 프로토콜에 @objc 속성이 표시되어 있어야합니다.
  • 이것은이 프로토콜이 클래스에는 적용 가능하지만 구조에는 적용되지 않음을 의미합니다.

Antoine의 답변의 메커니즘을 설명하려면 :

protocol SomeProtocol {
    func aMethod()
}

extension SomeProtocol {
    func aMethod() {
        print("extensionImplementation")
    }
}

class protocolImplementingObject: SomeProtocol {

}

class protocolImplementingMethodOverridingObject: SomeProtocol {
    func aMethod() {
        print("classImplementation")
    }
}

let noOverride = protocolImplementingObject()
let override = protocolImplementingMethodOverridingObject()

noOverride.aMethod() //prints "extensionImplementation"
override.aMethod() //prints "classImplementation"

프로토콜 상속을 통한 순수한 Swift 접근 방식 :

//Required methods
protocol MyProtocol {
    func foo()
}

//Optional methods
protocol MyExtendedProtocol: MyProtocol {
    func bar()
}

class MyClass {
    var delegate: MyProtocol
    func myMethod() {
        (delegate as? MyExtendedProtocol).bar()
    }
}

선택적 프로토콜 메소드를 구현할 수있는 방법묻기 전에 구현해야하는지 묻어 야한다고 생각합니다.

우리가 빠른 프로토콜을 고전적인 객체 지향 프로그래밍에서 인터페이스 로 생각한다면 , 선택적 메소드는 그다지 의미가 없으며 아마도 기본 구현을 만들거나 프로토콜을 프로토콜 세트로 분리하는 것이 더 나은 해결책 일 것입니다 (아마도 상속 관계가있는 경우) 프로토콜에서 가능한 방법 조합을 나타냅니다.

자세한 내용은 https://useyourloaf.com/blog/swift-optional-protocol-methods/를 참조 하십시오 .이 문제에 대한 훌륭한 개요를 제공합니다.


원래 질문에서 약간 벗어난 주제이지만 Antoine의 아이디어를 바탕으로 누군가에게 도움이 될 것이라고 생각했습니다.

프로토콜 확장이있는 구조체에 대해 계산 된 속성을 선택적으로 만들 수도 있습니다.

프로토콜의 속성을 선택적으로 만들 수 있습니다

protocol SomeProtocol {
    var required: String { get }
    var optional: String? { get }
}

프로토콜 확장에서 더미 계산 속성 구현

extension SomeProtocol {
    var optional: String? { return nil }
}

그리고 이제 선택적 속성이 구현되었거나 구현되지 않은 구조체를 사용할 수 있습니다

struct ConformsWithoutOptional {
    let required: String
}

struct ConformsWithOptional {
    let required: String
    let optional: String?
}

또한 내 블로그의 Swift 프로토콜에서 선택적 속성 을 수행하는 방법을 작성했습니다 . Swift 2 릴리스를 통해 변경 사항이있는 경우 계속 업데이트하겠습니다.


선택적이고 필요한 델리게이트 메소드를 작성하는 방법

@objc protocol InterViewDelegate:class {

    @objc optional func optfunc()  //    This is optional
    func requiredfunc()//     This is required 

}

다음은 신속한 클래스에만 해당하는 간단한 예제이며 구조 또는 열거 형에는 해당되지 않습니다. 선택적인 프로토콜 방법에는 두 가지 수준의 옵션 연결이 있습니다. 또한 프로토콜을 채택한 클래스는 선언에 @objc 속성이 필요합니다.

@objc protocol CollectionOfDataDelegate{
   optional func indexDidChange(index: Int)
}


@objc class RootView: CollectionOfDataDelegate{

    var data = CollectionOfData()

   init(){
      data.delegate = self
      data.indexIsNow()
   }

  func indexDidChange(index: Int) {
      println("The index is currently: \(index)")
  }

}

class CollectionOfData{
    var index : Int?
    weak var delegate : CollectionOfDataDelegate?

   func indexIsNow(){
      index = 23
      delegate?.indexDidChange?(index!)
    }

 }

순식간에 신속하게하고 싶다면 가장 좋은 방법은 Swift 유형의 구조체같은 Swift 유형을 반환하는 경우 기본 구현 particullary를 제공하는 것입니다

예 :

struct magicDatas {
    var damagePoints : Int?
    var manaPoints : Int?
}

protocol magicCastDelegate {
    func castFire() -> magicDatas
    func castIce() -> magicDatas
}

extension magicCastDelegate {
    func castFire() -> magicDatas {
        return magicDatas()
    }

    func castIce() -> magicDatas {
        return magicDatas()
    }
}

모든 기능 을 정의하지 않고 프로토콜을 구현할 수 있습니다.


하나의 옵션은 옵션 함수 변수로 저장하는 것입니다.

struct MyAwesomeStruct {
    var myWonderfulFunction : Optional<(Int) -> Int> = nil
}

let squareCalculator =
    MyAwesomeStruct(myWonderfulFunction: { input in return input * input })
let thisShouldBeFour = squareCalculator.myWonderfulFunction!(2)

Optional Protocol신속하게 정의하려면 해당 프로토콜 내에서 선언 및 / 선언 @objc전에 키워드 를 사용해야 합니다. 다음은 프로토콜의 선택적 속성 샘플입니다.Protocolattributemethod

@objc protocol Protocol {

  @objc optional var name:String?

}

class MyClass: Protocol {

   // No error

}

프로토콜에서 함수를 정의하고 해당 프로토콜의 확장을 만든 다음 선택적으로 사용할 함수에 대해 빈 구현을 만듭니다.


@optional메서드 나 속성 앞에을 넣습니다 .

참고 URL : https://stackoverflow.com/questions/24032754/how-to-define-optional-methods-in-swift-protocol



반응형