[ios] 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”로 표시하는 것과 관련된 다른 답변은 작동하지 않습니다.

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


답변

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

프로토콜 설정 :

@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?()


답변

에서 스위프트 3.0

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

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


답변

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