code

가치가 있다는 것을 알고 있다는 것을 의미하기 때문에 "암시적으로 포장되지 않은 옵션"을 만들어야 하는 이유는 무엇입니까?

starcafe 2023. 4. 28. 21:11
반응형

가치가 있다는 것을 알고 있다는 것을 의미하기 때문에 "암시적으로 포장되지 않은 옵션"을 만들어야 하는 이유는 무엇입니까?

규칙적인 변수나 상수만 만드는 것이 아니라 "암시적으로 포장되지 않은 선택사항"을 만드는 이유는 무엇입니까?포장을 성공적으로 풀 수 있다는 것을 알고 있다면 애초에 옵션을 만들 이유가 무엇입니까?예를 들어, 다음과 같은 이유가 있습니다.

let someString: String! = "this is the string"

다음보다 더 유용할 것:

let someString: String = "this is the string"

"선택사항이 상수 또는 변수가 '값 없음'을 허용함을 나타내지만, "가끔 프로그램 구조에서 옵션이 처음 설정된 후에 항상 값을 가질 것이라는 것이 분명하다"고 한다면, 우선 그것을 선택사항으로 만드는 것은 무엇입니까?옵션이 항상 가치가 있다는 것을 안다면, 그것은 옵션이 아니라는 것을 의미하지 않습니까?

Implicitly Unlapped Options의 사용 사례를 설명하기 전에 Swift에서 Options와 Implicitly Unlapped Options가 무엇인지 이미 이해해야 합니다.그렇지 않다면 먼저 옵션에 대한 제 기사를 읽어보시기를 권합니다.

암묵적으로 래핑 해제 옵션을 사용해야 하는 경우

암묵적으로 래핑 해제 옵션을 만드는 두 가지 주요 이유가 있습니다.이 모든 것은 다음과 같은 경우에 절대로 액세스되지 않을 변수를 정의하는 것과 관련이 있습니다.nil그렇지 않으면 Swift 컴파일러는 항상 옵션을 명시적으로 해제하도록 강제하기 때문입니다.

초기화 중에 정의할 수 없는 상수

모든 멤버 상수는 초기화가 완료될 때까지 값을 가져야 합니다.초기화 중에 올바른 값으로 상수를 초기화할 수 없는 경우도 있지만 액세스하기 전에 값이 있어야 합니다.

되므로 이 됩니다.nil그리고 그것이 궁극적으로 포함할 가치는 여전히 변하지 않을 것입니다.그러나 0이 아니라는 것을 확실히 알고 있는 변수의 포장을 계속 푸는 것은 고통스러울 수 있습니다.암묵적으로 포장 해제 옵션은 옵션과 동일한 이점을 제공하며 모든 곳에서 포장 해제를 명시적으로 수행할 필요가 없는 추가 이점을 제공합니다.

보기가 로드될 때까지 UIView 하위 클래스에서 멤버 변수를 초기화할 수 없는 경우가 좋은 예입니다.

class MyView: UIView {
    @IBOutlet var button: UIButton!
    var buttonOriginalWidth: CGFloat!

    override func awakeFromNib() {
        self.buttonOriginalWidth = self.button.frame.size.width
    }
}

여기서 보기가 로드될 때까지 버튼의 원래 너비를 계산할 수 없지만 다음과 같은 경우에는awakeFromNib뷰의 다른 메서드보다 먼저 호출됩니다(초기화 제외).클래스 전체에서 값을 의미 없이 명시적으로 풀도록 강제하는 대신 암묵적으로 풀림 선택사항으로 선언할 수 있습니다.

앱이 변수 상태에서 복구할 수 없는 경우nil

이는 매우 드물지만 변수가 다음과 같은 경우 앱을 계속 실행할 수 없는 경우입니다.nil액세스할 때, 그것을 테스트하는 것은 시간 낭비일 것입니다.nil일반적으로 앱이 계속 실행되기 위해서는 절대적으로 참이어야 하는 조건이 있다면, 당신은assertImplicitly Unlaped Optional(암묵적으로 래핑되지 않은 선택사항)에는 0에 대한 주장이 포함되어 있습니다.그럼에도 옵션의 포장을 풀고 0인 경우 더 설명적인 어설션을 사용하는 것이 좋습니다.

암묵적으로 랩 해제 옵션을 사용하지 않는 경우

게으르게 계산된 멤버 변수

멤버 변수가 0이 되어서는 안 되는 경우가 있지만 초기화 중에는 올바른 값으로 설정할 수 없습니다.한 가지 해결책은 암시적으로 랩 해제 옵션을 사용하는 것이지만 더 나은 방법은 게으른 변수를 사용하는 것입니다.

class FileSystemItem {
}

class Directory : FileSystemItem {
    lazy var contents : [FileSystemItem] = {
        var loadedContents = [FileSystemItem]()
        // load contents and append to loadedContents
        return loadedContents
    }()
}

멤버 변수 자, 멤변수는버는▁now▁the변수▁member▁variablecontents처음 액세스할 때까지 초기화되지 않습니다.이렇게 하면 클래스가 초기 값을 계산하기 전에 올바른 상태로 전환될 수 있습니다.

참고: 이것은 위의 #1과 모순되는 것처럼 보일 수 있습니다.하지만, 중요한 차이점이 있습니다.buttonOriginalWidth속성에 액세스하기 전에 다른 사용자가 단추 너비를 변경하지 않도록 하려면 viewDidLoad 동안 위를 설정해야 합니다.

다른 모든 곳

대부분의 경우, 실수로 사용하면 다음 시간 동안 액세스될 때 전체 앱이 충돌하기 때문에 암묵적으로 랩 해제 옵션은 피해야 합니다.nil변수가 0이 될 수 있는지 확실하지 않으면 항상 일반 옵션을 사용하도록 기본 설정합니다.로 절대그가 해제 핑제해래의nil확실히 많이 아프지는 않습니다.

구성 및 구성 중에 nil 속성을 가질 수 있지만 이후에는 불변하고 nil이 아닌 개체의 경우를 생각해 보십시오(NSImage는 종종 이러한 방식으로 처리되지만 경우에 따라 여전히 변환하는 데 유용합니다).암묵적으로 포장되지 않은 옵션은 상대적으로 안전 손실이 적은 코드를 상당한 수준으로 정리할 것입니다(하나의 보증이 유지되는 한 안전할 것입니다).

(편집) 하지만 명확하게 하기 위해: 일반 옵션이 거의 항상 선호됩니다.

암묵적으로 래핑되지 않은 옵션은 표지 아래에서 선택적이어야 할 경우 비선택적으로 속성을 표시하는 데 유용합니다.이것은 종종 서로에 대한 참조가 필요한 두 개의 관련 개체 사이의 "끈을 묶는" 데 필요합니다.두 참조 중 어느 것도 실제로 선택 사항이 아니지만 쌍을 초기화하는 동안 하나가 0이어야 하는 경우에 의미가 있습니다.

예:

// These classes are buddies that never go anywhere without each other
class B {
    var name : String
    weak var myBuddyA : A!
    init(name : String) {
        self.name = name
    }
}

class A {
    var name : String
    var myBuddyB : B
    init(name : String) {
        self.name = name
        myBuddyB = B(name:"\(name)'s buddy B")
        myBuddyB.myBuddyA = self
    }
}

var a = A(name:"Big A")
println(a.myBuddyB.name)   // prints "Big A's buddy B"

조금도B에는 항상 한 "" "" "" " ""가 .myBuddyA할 수 , 참조, 그래우사선취하않싶만지리, 구수야우있성합어할우다, 이니선그도록적택이것는리가택지로고적급게으것하리는용을그가자.B하기도 전에A참고로

하지만!이러한 종류의 상호 참조 요구 사항은 종종 엄격한 결합과 빈약한 설계를 나타냅니다.잠재적으로 포장되지 않은 옵션에 의존하는 경우 상호 의존성을 제거하기 위해 리팩터링을 고려해야 합니다.

암묵적으로 포장되지 않은 옵션은 기존의 코코아 프레임워크 및 해당 규칙과 상호 운용되어야 하는 하이브리드 환경에서의 작업을 보다 쾌적하게 만드는 동시에 Swift 컴파일러에 의해 시행되는 null 포인터 없이 안전한 프로그래밍 패러다임으로 단계적으로 마이그레이션할 수 있도록 하는 실용적인 타협입니다.

Swift book의 The Basics 장에서 암묵적으로 포장되지 않은 옵션 섹션은 다음과 같이 말합니다.

암묵적으로 포장되지 않은 옵션은 옵션이 처음 정의된 직후에 옵션의 값이 존재하는 것으로 확인되고 그 이후의 모든 시점에 존재한다고 확실히 가정할 수 있을 때 유용합니다.Swift에서 암시적으로 래핑 해제 옵션을 주로 사용하는 것은 클래스 초기화 중입니다. 이는 소유되지 않은 참조 및 암묵적으로 래핑 해제 옵션 속성에 설명되어 있습니다.

임의로 래핑 해제 옵션을 사용할 때마다 자동으로 래핑 해제할 수 있는 권한을 부여하는 것으로 간주할 수 있습니다.사용할 때마다 선택사항 이름 뒤에 느낌표를 붙이는 대신, 선언할 때 선택사항 유형 뒤에 느낌표를 넣습니다.

이는 사용 규칙을 통해 속성의 비-non-nessnil 설정되고 클래스 초기화 중 컴파일러에 의해 시행될 수 없는 사용 사례로 이어집니다.예를 들어,UIViewController Storyboard에서으로, 되지만 NIB 에는 Storyboard에서 초기화되는 속성입니다.viewDidLoad()속성이 일반적으로 존재한다고 가정할 수 있습니다.그렇지 않으면 컴파일러를 만족시키기 위해 코드의 주요 목적을 모호하게 하기 위해 강제 언랩, 선택적 바인딩 또는 선택적 체인을 사용해야 했습니다.

Swift 책의 위 부분은 자동 참조 카운팅 장을 참조하기도 합니다.

그러나 세 번째 시나리오가 있는데, 두 속성 모두 항상 값을 가져야 하며 두 속성 모두 다음과 같은 값을 가질 수 없습니다.nil되지 않은 의 암묵적으로 않은 합니다.이 시나리오에서는 한 클래스의 소유되지 않은 속성을 다른 클래스의 암묵적으로 래핑되지 않은 선택적 속성과 결합하는 것이 유용합니다.

이를 통해 초기화가 완료되면 두 속성에 모두 직접 액세스할 수 있으며(선택 사항인 래핑 해제 없이) 참조 주기를 피할 수 있습니다.

이것은 가비지 수집 언어가 아닌 특성으로 귀결됩니다. 따라서 보유 주기의 중단은 프로그래머로서 당신에게 달려 있으며 암묵적으로 포장되지 않은 옵션은 이러한 특성을 숨기기 위한 도구입니다.

여기에는 "코드에서 암묵적으로 포장되지 않은 옵션을 사용해야 하는 경우"에 대한 내용이 포함됩니다.질문.응용 프로그램 개발자로서, 당신은 선택적 유형을 표현하는 기능이 없는 오브젝티브-C로 작성된 라이브러리의 메소드 서명에서 그것들을 주로 접하게 될 것입니다.

코코아 목표-C와 함께 Swift 사용에서 0으로 작업 섹션:

Objective-C는 개체가 nil이 아님을 보장하지 않으므로 Swift는 가져온 Objective-C API에서 인수 유형 및 반환 유형의 모든 클래스를 선택적으로 만듭니다.Objective-C 개체를 사용하기 전에 개체가 누락되지 않았는지 확인해야 합니다.

경우에 따라 Objective-C 방법 또는 속성이 다음을 반환하지 않는다고 절대적으로 확신할 수 있습니다.nil객체 참조이 특수 시나리오의 개체를 보다 편리하게 작업할 수 있도록 Swift는 개체 유형을 암시적으로 래핑 해제 옵션으로 가져옵니다.암묵적으로 포장 해제된 옵션 유형에는 옵션 유형의 모든 안전 기능이 포함됩니다.또한 다음을 확인하지 않고 직접 값에 액세스할 수 있습니다.nil직접 포장을 뜯거나.먼저 래핑을 안전하게 해제하지 않고 이러한 종류의 선택적 유형의 값에 액세스하면 암시적으로 래핑 해제된 옵션이 값이 누락되었는지 여부를 확인합니다.값이 없으면 런타임 오류가 발생합니다.따라서 값이 누락될 수 없는 경우를 제외하고는 암묵적으로 포장 해제된 선택사항을 항상 확인하고 포장을 해제해야 합니다.

이 에는...그리고 이 너머에는용들

한 줄(또는 여러 줄)의 간단한 예는 옵션의 동작을 잘 다루지 못합니다. 예, 변수를 선언하고 바로 값을 제공하면 옵션에 의미가 없습니다.

지금까지 본 가장 좋은 사례는 객체 초기화 후에 발생하는 설정이며, 그 다음에는 뷰 컨트롤러와 같이 해당 설정을 "보증"하여 사용하는 것입니다.

class MyViewController: UIViewController {

    var screenSize: CGSize?

    override func viewDidLoad {
        super.viewDidLoad()
        screenSize = view.frame.size
    }

    @IBAction printSize(sender: UIButton) {
        println("Screen size: \(screenSize!)")
    }
}

우리는 알고 있다.printSize보기가 로드된 후 호출됩니다. 이는 해당 보기 내부의 컨트롤에 연결된 작업 방법이므로 다른 방법으로 호출하지 않도록 했습니다.그래서 우리는 우리 자신을 저장할 수 있습니다.!Swift는 (적어도 Apple이 중단 문제를 해결하기 전까지는) 보증을 인식할 수 없으므로 컴파일러에게 보증이 존재한다고 말합니다.

그러나 이것은 형식 안전을 어느 정도 깨뜨립니다.경우 될 수 하는 것이."보증"이 항상 유지되지 않는 경우 앱이 중단될 수 있는 위치를 암시적으로 선택할 수 있습니다. 따라서 사용을 자제하는 것이 좋습니다. 게가다, 사는것을 사용합니다.!항상 소리지르는 것처럼 들리지만 아무도 그걸 좋아하지 않습니다.

Apple은 스위프트 프로그래밍 언어 -> 자동 참조 카운팅 -> 클래스 인스턴스 간의 강력한 참조 사이클 해결 -> 소유하지 않은 참조 및 암묵적으로 랩 해제된 선택적 속성에서 좋은 예를 제시합니다.

class Country {
    let name: String
    var capitalCity: City! // Apple finally correct this line until 2.0 Prerelease (let -> var)
    init(name: String, capitalName: String) {
        self.name = name
        self.capitalCity = City(name: capitalName, country: self)
    }
}

class City {
    let name: String
    unowned let country: Country
    init(name: String, country: Country) {
        self.name = name
        self.country = country
    }
}

의 .City다음에 대해 이니셜라이저 내에서 호출됩니다.Country그나다대이저이라셜니의 Country합격할 수 self에▁City가 될 까지 Country인스턴스가 완전히 초기화됩니다(2단계 초기화).

사항에 이요사처기위다선음다니언합을해리하항을구를 합니다.capitalCityCountry암묵적으로 랩핑되지 않은 선택적 속성으로.

암묵적 옵션의 이론적 근거는 먼저 강제 해제 이론적 근거를 살펴봄으로써 설명하기가 더 쉽습니다.

! 연산자를 사용하여 선택사항(암묵적이든 아니든)의 강제적인 래핑 해제는 코드에 버그가 없으며 선택사항에 이미 래핑 해제 위치 값이 있음을 의미합니다.! 연산자가 없으면 선택적 바인딩을 사용하여 어설션할 수 있습니다.

 if let value = optionalWhichTotallyHasAValue {
     println("\(value)")
 } else {
     assert(false)
 }

보다 좋지 않은 것은

println("\(value!)")

이제 암시적 옵션을 사용하면 가능한 모든 흐름에서 래핑 해제 시 항상 값을 가질 으로 예상되는 옵션을 표시할 수 있습니다.따라서!를 작성하여 매번 포장을 풀고 흐름에 대한 가정이 잘못된 경우에도 런타임 오류가 발생하도록 함으로써 한 걸음 더 나아가 도움이 됩니다.

확실하게 알고 있는 경우, 값은 다음 대신 선택 사항에서 반환됩니다.nil암시적으로 래핑되지 않은 옵션은 옵션에서 해당 값을 직접 캡처하는 데 사용하고 비옵션은 그렇지 않습니다.

//Optional string with a value
let optionalString: String? = "This is an optional String"

//Declaration of an Implicitly Unwrapped Optional String
let implicitlyUnwrappedOptionalString: String!

//Declaration of a non Optional String
let nonOptionalString: String

//Here you can catch the value of an optional
implicitlyUnwrappedOptionalString = optionalString

//Here you can't catch the value of an optional and this will cause an error
nonOptionalString = optionalString

그래서 이것이 사용하는 것의 차이입니다.

let someString : String! 그리고. let someString : String

Implicitly Unwrapped Optional(IUO)

에 대한 통사적인 설탕입니다.Optional프로그래머가 변수를 풀도록 강요하지 않습니다.다음 기간 동안 초기화할 수 없는 변수에 사용할 수 있습니다.two-phase initialization process그리고 비반응성을 의미합니다.이 변수는 자체적으로 n이 아닌 변수로 동작하지만 실제로는 선택적 변수입니다.좋은 예는 - 인터페이스 빌더의 아웃렛입니다.

Optional으로 선호되는 것은 ▁usually입니다.

var implicitlyUnwrappedOptional: String! //<- Implicitly Unwrapped Optional
var nonNil: String = ""
var optional: String?

func foo() {
    //get a value
    nonNil.count
    optional?.count
    
    //Danderour - makes a force unwrapping which can throw a runtime error
    implicitlyUnwrappedOptional.count
    
    //assign to nil
//        nonNil = nil //Compile error - 'nil' cannot be assigned to type 'String'
    optional = nil
    implicitlyUnwrappedOptional = nil
}

생각합니다Optional많은 초보자들을 혼란스럽게 하는 이 구조물에 대한 나쁜 이름입니다.

다른 언어(예: Kotlin 및 C#)에서는 이 용어를 사용합니다.Nullable그리고 이것을 이해하는 것을 훨씬 더 쉽게 만듭니다.

Nullable이 유형의 변수에 null 값을 할당할 수 있음을 의미합니다.그래서 만약에.Nullable<SomeClassType>당신은 그것에 null을 할당할 수 있습니다, 만약 그것이 단지.SomeClassType그럴수는 없어요.그게 바로 스위프트가 작동하는 방식입니다.

왜 그것들을 사용합니까?음, 가끔은 널이 필요해, 그게 이유야.예를 들어 클래스에 필드가 있지만 해당 클래스의 인스턴스를 만들 때 필드를 할당할 수 없지만 나중에 필드를 할당할 수 있습니다.예를 들어보지 않겠습니다. 사람들이 이미 여기에 그것들을 제공했기 때문입니다.제 2센트를 주기 위해 이 글을 쓰는 겁니다.

그나저나, 코틀린과 C#과 같은 다른 언어에서 이것이 어떻게 작동하는지 살펴보시기를 제안합니다.

코틀린에서 이 기능을 설명하는 링크가 있습니다. https://kotlinlang.org/docs/reference/null-safety.html

자바와 스칼라와 같은 다른 언어들은Optional 작동합니다.Optional으로 모두 하므로 .s Swift에서는 Java와 Scala의 유형을 null로 지정합니다.

대체적으로, 저는 이 기능의 이름이 지어졌어야 한다고 생각합니다.Nullable 가트프아닌이 .Optional...

언급URL : https://stackoverflow.com/questions/24006975/why-create-implicitly-unwrapped-optionals-since-that-implies-you-know-theres

반응형