스위프트 : nil에 대한 옵션 테스트


137

Xcode 6 Beta 4를 사용하고 있습니다. 옵션을 적절히 테스트하는 방법을 알 수없는 이상한 상황이 있습니다.

선택적 xyz가있는 경우 올바른 테스트 방법입니다.

if (xyz) // Do something

또는

if (xyz != nil) // Do something

문서는 첫 번째 방법으로 수행한다고 말하지만 때로는 두 번째 방법이 필요하며 컴파일러 오류를 생성하지 않지만 두 번째 방법은 컴파일러 오류를 생성한다는 것을 알았습니다.

내 구체적인 예는 신속하게 연결된 GData XML 파서를 사용하는 것입니다.

let xml = GDataXMLDocument(
    XMLString: responseBody,
    options: 0,
    error: &xmlError);

if (xmlError != nil)

내가 방금 한 경우 여기 :

if xmlError

항상 true를 반환합니다. 그러나 내가 할 경우 :

if (xmlError != nil)

그런 다음 (Objective-C에서 작동하는 방식으로) 작동합니다.

GData XML과 누락 된 옵션을 처리하는 방식이 있습니까?


4
예기치 않은 사례와 오류 사례에 대한 전체 예를 볼 수 있습니까? (그리고 그것은 어렵다는 것을 알고 있지만 조건부 주위에 괄호를 잃기 시작하십시오!)
Matt Gibson

1
이것은 Xcode 6 베타 5에서 변경되었습니다
newacct


방금 예기치 않은 경우로 질문을 업데이트했습니다.
tng

아직 베타 5로 업데이트되지 않았습니다. 나는 곧 그렇게 할 것이다. 만나서 반가워 ?? 스위프트에서 더욱 일관된 선택적 동작.
tng

답변:


172

Xcode Beta 5에서는 더 이상 할 수 없습니다.

var xyz : NSString?

if xyz {
  // Do something using `xyz`.
}

오류가 발생합니다.

프로토콜 'BooleanType.Protocol'을 준수하지 않습니다

다음 형식 중 하나를 사용해야합니다.

if xyz != nil {
   // Do something using `xyz`.
}

if let xy = xyz {
   // Do something using `xy`.
}

5
누군가 xyz == nil이 작동하지 않는 이유를 자세히 설명 할 수 있습니까?
Christoph

두 번째 예는 다음과 같습니다. // xy를 사용하여 작업 수행 (두 변형의 사용 사례에서 가장 큰 차이)
Alper

@Christoph : 오류 메시지는 초기화하기 전에 상수 'xyz'가 사용되었다는 것입니다. xyz 선언 줄 끝에 '= nil'을 추가해야한다고 생각합니다.
user3207158

나처럼 빨리 익숙하지 않은 사람들을 위해 : if 블록 안에서 xyz를 풀어야합니다. 그래도 랩을 강제로 해제하더라도 안전합니다
Omar

@Omar 두 번째 형태의 아름다움입니다. 블록을 풀지 않고도 xy를 블록 안에 사용합니다.
Erik Doernenburg

24

if조건 내에서 다른 이름의 변수를 할당하는 대신 다른 답변에 추가하려면 다음을 수행하십시오 .

var a: Int? = 5

if let b = a {
   // do something
}

다음과 같은 변수 이름을 재사용 할 수 있습니다.

var a: Int? = 5

if let a = a {
    // do something
}

이렇게하면 소재 변수 이름이 부족 해지는 것을 피할 수 있습니다 ...

이것은 Swift에서 지원되는 가변 그림자 를 활용 합니다.


18

옵션을 사용하는 가장 직접적인 방법 중 하나는 다음과 같습니다.

예를 들어 xyz, 선택 유형 이라고 가정하십시오 Int?.

if let possXYZ = xyz {
    // do something with possXYZ (the unwrapped value of xyz)
} else {
    // do something now that we know xyz is .None
}

이 방법 xyz으로 값 이 포함되어 있는지 테스트 하고 있으면 해당 값으로 즉시 작업 할 수 있습니다.

컴파일러 오류와 관련하여 유형 UInt8은 선택 사항이 아니므로 ( 'no'는 아님) 주로 변환 할 수 없습니다 nil. 작업하는 변수가 선택 사항인지 확인한 후 변수로 취급하십시오.


1
불필요하게 새로운 변수 (일정한)를 생성하기 때문에이 방법이 나쁘다는 것을 알았습니다. 대부분의 시간은 이전보다 최악의 새 이름을 만들어야했습니다. 글을 쓰고 독자에게 더 많은 시간이 걸립니다.
Lombas

3
선택적 변수를 풀기위한 표준 방법 및 권장 방법입니다. " '하자"는 매우 강력합니다.
gnasher729

@ gnasher729 그러나 else 부분 만 사용하려면 어떻게해야합니까
Brad Thomas

15

스위프트 3.0, 4.0

nil에 대한 선택 사항을 확인하는 방법은 주로 두 가지가 있습니다. 다음은 이들을 비교 한 예입니다.

1.하자면

if letnil에 대한 선택적을 확인하는 가장 기본적인 방법입니다. 다른 조건은이 nil 확인에 쉼표로 구분하여 추가 할 수 있습니다. 다음 조건으로 이동하려면 변수가 0이 아니어야합니다. 무 검사 만 필요한 경우 다음 코드에서 추가 조건을 제거하십시오.

그 외에는, xnil이 아닌 경우 if 클로저가 실행되어 x_val내부에서 사용 가능합니다. 그렇지 않으면 else 클로저가 트리거됩니다.

if let x_val = x, x_val > 5 {
    //x_val available on this scope
} else {

}

2. 경비하자

guard let비슷한 일을 할 수 있습니다. 주요 목적은 논리적으로 합리적으로 만드는 것입니다. 그것은 말처럼 반드시 변수가 전무, 그렇지 않으면 기능이 정지되지 않았는지 확인을 . guard let추가 조건 검사를 할 수도 있습니다if let .

차이점은 guard let아래 설명과 같이 래핑되지 않은 값을와 동일한 범위에서 사용할 수 있다는 것 입니다. 이것은 또한에 의해, 다른 폐쇄에, 프로그램은 현재 범위를 종료해야한다는 점에 이르게 return, break

guard let x_val = x, x_val > 5 else {
    return
}
//x_val available on this scope

11

신속한 프로그래밍 가이드에서

명령문 및 강제 언 래핑

if 문을 사용하여 선택적에 값이 포함되어 있는지 확인할 수 있습니다. 선택 사항에 값이 있으면 true로 평가됩니다. 값이 전혀 없으면 false로 평가됩니다.

가장 좋은 방법은

// swift > 3
if xyz != nil {}

xyzin if 문을 사용하는 경우 xyz상수 변수에서 if 문을 줄 바꿈 할 수 있으므로 if 문 xyz이 사용되는 곳에서 모든 위치를 줄 바꿈 할 필요가 없습니다 .

if let yourConstant = xyz{
      //use youtConstant you do not need to unwrap `xyz`
}

이 컨벤션이 제안 apple하고 개발자들에게 이어질 것입니다.


2
스위프트 3에서는해야 if xyz != nil {...}합니다.
psmythirl

Swift 3에서는 옵션을 부울로 사용할 수 없습니다. 첫째는 C-ism이기 때문에 처음에는 언어로 사용되어서는 안되며, 둘째는 선택적인 Bool과 완전히 혼동되기 때문입니다.
gnasher729

9

선택적을 명시 적으로 비교 nil하거나 선택적 바인딩을 사용하여 값을 추가로 추출 해야하지만 (예를 들어 선택적이 부울 값으로 암시 적으로 변환되지 않음) Swift 2는 운명피라미드를 피하기 위해 guard명령문 을 추가했음을 주목할 가치가 있습니다. 작업 할 때 여러 개의 선택적 값이 있습니다.

다시 말해, 옵션에는 다음을 명시 적으로 확인하는 것이 포함됩니다 nil.

if xyz != nil {
    // Do something with xyz
}

선택적 바인딩 :

if let xyz = xyz {
    // Do something with xyz
    // (Note that we can reuse the same variable name)
}

그리고 guard진술 :

guard let xyz = xyz else {
    // Handle failure and then exit this code block
    // e.g. by calling return, break, continue, or throw
    return
}

// Do something with xyz, which is now guaranteed to be non-nil

두 개 이상의 선택적 값이있을 때 일반적인 선택적 바인딩이 어떻게 들여 쓰기가 커질 수 있는지 확인하십시오.

if let abc = abc {
    if let xyz = xyz {
        // Do something with abc and xyz
    }        
}

guard명령문 으로이 중첩을 피할 수 있습니다 .

guard let abc = abc else {
    // Handle failure and then exit this code block
    return
}

guard let xyz = xyz else {
    // Handle failure and then exit this code block
    return
}

// Do something with abc and xyz

1
위에서 언급했듯이 중첩 된 옵션 통계를 제거하기 위해이 작업을 수행 할 수도 있습니다. if abc = abc? .xyz? .something {}
Suhaib

1
@Suhaib Ah, true : 선택적 체인 ( developer.apple.com/library/prerelease/content/documentation/… )을 사용하여 중첩 된 속성에 빠르게 액세스 할 수도 있습니다 . 나는 그것이 원래의 질문에서 너무 접할 수 있다고 생각했기 때문에 여기에 언급하지 않았습니다.
Chris Frederick

좋은 대답입니다! 그러나 Swift, OMG ... 여전히 프로그래머 친화적 인 방식에서 멀다!
turingtest에

@turingtested 감사합니다! 사실, 나는이 생각 이다 가 실수로 사용하려고하지 않을 것이다 당신을 보장한다는 의미에서 프로그래머 친화적 인 nil가치를, 그러나 나는 학습 곡선이 조금 가파른 동의합니다. :)
Chris Frederick

4

스위프트 5 프로토콜 확장

선택적인 nil check를 쉽게 인라인 할 수 있도록 프로토콜 확장을 사용하는 접근법이 있습니다.

import Foundation

public extension Optional {

    var isNil: Bool {

        guard case Optional.none = self else {
            return false
        }

        return true

    }

    var isSome: Bool {

        return !self.isNil

    }

}

용법

var myValue: String?

if myValue.isNil {
    // do something
}

if myValue.isSome {
    // do something
}

이 답변에 대해 몇 가지 의견을 얻었으며 그 이유를 알고 싶습니다. 다운 보트를하려는 경우에는 적어도 의견을 말하십시오.
Brody Robertson

1
아마도 언어를 파이썬 순결의 형태로 유지하려고 시도 swift하는 pythonistas것은 아마도 아날로그 일 것입니다 . 내 테이크? 방금 Utils 믹스 인으로 코드를 들어 올렸습니다.
javadba

2

이제 다음 목표를 신속하게 수행 할 수 있습니다. if nil else

if textfieldDate.text?.isEmpty ?? true {

}

2

대신 if삼항 연산자는 무언가가 없는지 여부에 따라 값을 얻으려고 할 때 유용 할 수 있습니다.

func f(x: String?) -> String {
    return x == nil ? "empty" : "non-empty"
}

xyz == nil표현은 작동하지 않지만 작동 x != nil합니다. 이유를 모릅니다.
앤드류

2

선택적 바인딩을 수행하기 위해 if또는 guard문을 사용하는 것 외에 다른 방법 은 다음 Optional과 같이 확장하는 것 입니다.

extension Optional {

    func ifValue(_ valueHandler: (Wrapped) -> Void) {
        switch self {
        case .some(let wrapped): valueHandler(wrapped)
        default: break
        }
    }

}

ifValue옵션이 nil이 아닌 경우 클로저를 수신하고 값을 인수로 호출합니다. 이 방법으로 사용됩니다 :

var helloString: String? = "Hello, World!"

helloString.ifValue {
    print($0) // prints "Hello, World!"
}

helloString = nil

helloString.ifValue {
    print($0) // This code never runs
}

당신은 아마를 사용해야 if하거나 guard그러나 사람들은 대부분 기존의 (따라서 익숙한) 스위프트 프로그래머가 사용하는 접근 방법이기 때문에.


2

구체적으로 다루지 않은 옵션 중 하나는 Swift의 무시 된 값 구문을 사용하는 것입니다.

if let _ = xyz {
    // something that should only happen if xyz is not nil
}

nilSwift와 같은 현대 언어로 된 느낌이 들지 않기 때문에 이것을 좋아합니다 . 나는 그것이 제자리에 있다고 느끼는 이유 nil는 기본적으로 센티넬 값 이라고 생각합니다 . 우리는 현대 프로그래밍의 다른 곳에서 센티넬을 거의 없애 버렸 nil습니다.


1

또한 사용할 수 있습니다 Nil-Coalescing Operator

nil-coalescing operator( a ?? b) 옵션을 펼쳤다 a가 포함 된 경우 a값 또는 반환 a기본값을 b경우 a입니다 nil. 표현식 a는 항상 선택적 유형입니다. 식은 b안에 저장된 형식과 일치해야합니다 a.

let value = optionalValue ?? defaultValue

경우 optionalValue이며 nil, 자동에 값을 할당defaultValue


기본값을 지정하는 쉬운 옵션을 제공하기 때문에 좋아합니다.
thowa

0
var xyz : NSDictionary?

// case 1:
xyz = ["1":"one"]
// case 2: (empty dictionary)
xyz = NSDictionary() 
// case 3: do nothing

if xyz { NSLog("xyz is not nil.") }
else   { NSLog("xyz is nil.")     }

이 테스트는 모든 경우에 예상대로 작동했습니다. BTW는 괄호가 필요하지 않습니다 ().


2
OP가 우려되는 경우는 다음과 같습니다 if (xyz != nil)..
zaph

0

조건이 있고 랩을 풀고 비교하고 싶다면 복합 부울 식의 단락 평가를 활용하는 방법은 어떻습니까?

if xyz != nil && xyz! == "some non-nil value" {

}

물론, 이것은 다른 제안 된 게시물만큼 읽을 수는 없지만 다른 제안 된 솔루션보다 작업을 완료하고 다소 간결하게 만듭니다.

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