2017-05-20 4 views
2

옵션 프로토콜을 확장하여 기본값을 제공 할 수 있도록 기능을 추가하여 Swift에서 프로토콜 및 프로토콜 확장을 유용하게 사용하는 또 다른 방법을 찾았습니다. 스위프트 속성이 구현되었는지 확인하기위한 조건

나는 여기에 대한 블로그 포스트를 작성했습니다 : https://janthielemann.de/random-stuff/providing-default-values-optional-string-empty-optional-string-swift-3-1/

게시물의 요점은 내가 존재하지 않거나 비어있는 선택적 문자열에 대한 기본값을 제공하기 위해 깨끗하고 쉬운 방법을 필요로한다는 것이다.

protocol Emptyable { 
    var isEmpty: Bool { get } 
} 

extension Optional where Wrapped: Emptyable { 
    func orWhenNilOrEmpty<T: Emptyable>(_ defaultValue: T) -> T { 
     switch(self) { 
     case .none: 
      return defaultValue 
     case .some(let value) where value.isEmpty: 
      return defaultValue 
     case .some(let value): 
      return value as! T 
     } 
    } 
} 

extension String: Emptyable {} 

이제 문제는이다 : 나는 Emptyable 프로토콜을 제거 할 수있는 방법이 있나요 대신 조건부 확인 여부가이 작업을 수행하려면, 나는 Emptyable 프로토콜 끝이 선택 의정서과 같이 확장 생성 또는 속성이나 함수가 제네릭 형식으로 구현되지 않아서 isEmpty이있는 모든 형식에 대해 orWhenNilOrEmpty()가 자동으로 얻어 지도록하려면?

UPDATE

파울로에 의해 제안으로, T 일반적인 실제로 필요하지 않습니다와 나는 (적어도 난 그렇게 생각합니다., I를 정정 해줘 부담도 빠르게 액세스하고 더 편리한 사용을위한 연산자를 생성 항상 새로운 것을 배우고 자신을 향상시키는 것이 행복합니다.)

나는 그것을 "비어있는 nil coalescing"연산자라고 부른다 (누가 더 나은 이름을 내놓을 수 있는가? 나는 이름 짓기에 빨려 든다 : /). 희망이 언젠가는 도움이 사람 :

protocol Emptyable { 
    var isEmpty: Bool { get } 
} 

infix operator ???: NilCoalescingPrecedence 

extension Optional where Wrapped: Emptyable { 
    func orWhenNilOrEmpty(_ defaultValue: Wrapped) -> Wrapped { 
     switch(self) { 
     case .none: 
      return defaultValue 
     case .some(let value) where value.isEmpty: 
      return defaultValue 
     case .some(let value): 
      return value 
     } 
    } 

    static func ???(left: Wrapped?, right: Wrapped) -> Wrapped { 
     return left.orWhenNilOrEmpty(right) 
    } 
} 

extension String: Emptyable {} 

extension Array: Emptyable {} 

extension MyStruct: Emptyable { 
    let text: String 
    let number: Int 
    var isEmpty: Bool { return text.isEmpty && number == 0 } 
    init(text: String, number: Int) { 
     self.text = text 
     self.number = number 
    } 
} 

let mandatoryNotEmptyString = optionalOrEmptyString ??? "Default Value" 
let mandatoryNotEmptyStruct = optionalOrEmptyStruct ??? MyStruct(name: "Hello World", number: 1) 
+0

'orWhenNilOrEmpty' 함수가 실제로 generic 일 필요가 있습니까? 'T'를'Wrapped'로 대체 할 수 없습니까? 또는 임의로 입력 된 기본값을 지원하도록 API가 설계 되었습니까? (마지막 행의 강제 캐스팅이 그렇다면 항상 성공할 수 있습니다)? –

+0

당신 말이 맞아요. T는 실제로 전혀 필요하지 않습니다. 힌트를 가져 주셔서 감사합니다! – xxtesaxx

답변

1

개체 또는 값이 프로토콜을 사용하지 않고 확장에 제약 조건으로 특정 재산이있는 경우 아니, 당신은 쿼리 할 수 ​​없습니다. 이는 Swift에서 현재 구현되지 않은 방식으로 반영해야합니다. 또한 isEmpty 속성은 유형마다 다른 의미를 가질 수 있으므로 프로토콜 대신 메서드 나 속성이 있는지 테스트하면 예기치 않은 동작이 발생할 수 있습니다.

당신은

if let unwrappedString = optionalString, !unwrappedString.isEmpty { 
    // Do stuff 
} else { 
    // Use default value 
} 

없음 프로토콜 또는 필요한 확장 매우 읽을 작성할 수 있습니다.

올해 가을에 출시 될 Swift 4에서 String will conform to BidirectionalCollectionCollection에서 상속됩니다. 당신의 확장,

extension Optional where Wrapped: Collection { 
    // ... 
} 

하지만 그렇다하더라도 당신이 첫번째 장소에 저장할 때 무기 호에 빈 문자열을 설정하는 것이 좋습니다 수 있도록 Collection 프로토콜은 isEmpty 속성을 제공합니다 당신은 지금이 상태 (전무와 빈을 가지고 있기 때문에) 똑같은 것을 나타내는 것처럼 보입니다.

+0

미러를 확장에 대한 제약 조건으로 사용할 수 없습니다. 랩핑 된 유형에 관계없이 모든 선택적 값에 대해 메소드를 제공하는 것은 정말 나쁩니다. – Palle

+0

물론, 당신 말이 맞아요! 어쨌든, 고맙습니다;) –

+2

"let x = y,! x.isEmpty ..."는 내가 제거하고 싶었던 것입니다.:) 어쨌든, 나는 이미 그것을 확인해 주셔서 감사합니다. 그건 그렇고, 지금은 한 걸음 더 나아가 내 기능을 ???라고 부르는 연산자로 만들었습니다. 어쩌면 정상에 조금 못 미치 겠지만 실제 클라이언트 프로젝트에서 사용하는 것보다 나를 배우는 것이 더 중요합니다. 글쎄, 내 자신의 개인적인 프로젝트에서 나는 아마 그것을 사용합니다 : D 조 – xxtesaxx