オプション変数の印刷


118

私はこれらのコード行を試しています

class Student {
    var name: String
    var age: Int?

    init(name: String) {
        self.name = name
    }

    func description() -> String {
        return age != nil ? "\(name) is \(age) years old." : "\(name) hides his age."
    }
}

var me = Student(name: "Daniel")
println(me.description())
me.age = 18
println(me.description())

上記のコードは次のように生成されます

Daniel hides his age.
Daniel is Optional(18) years old.

私の質問は、なぜそこにオプション(18)があるのか​​、オプションを削除して印刷する方法です

Daniel is 18 years old.

回答:


190

オプションとは何かを理解する必要があります。Swiftの初心者の多くvar age: Int?は、年齢はIntであり、値を持つ場合と持たない場合があると考えています。ただし、年齢はオプションであり、Intを保持する場合と保持しない場合があります。

description()関数内ではIntを出力せず、代わりにOptionalを出力します。Intを印刷する場合は、オプションをアンラップする必要があります。「オプションのバインディング」を使用して、オプションをアンラップできます。

if let a = age {
 // a is an Int
}

オプションがオブジェクトを保持していることが確実な場合は、「強制アンラップ」を使用できます。

let a = age!

または、例では、description関数にすでにnilのテストがあるので、次のように変更できます。

func description() -> String {
    return age != nil ? "\(name) is \(age!) years old." : "\(name) hides his age."
}

この例を使用するように変更した方が少し良いと思いますif let age = age { return ""} else { return "" }
kubi

13
+1:Many Swift beginners think var age: Int? means that age is an Int which may or may not have a value. But it means that age is an Optional which may or may not hold an Int.
lee 2016年

18

オプションは、値がタイプに対応するかどうかをSwiftが完全に確信できないことを意味します。たとえば、Int?つまり、Swiftは、数値がIntかどうかを完全には確信していません。

それを削除するには、3つの方法があります。

1)タイプが確実にわかっている場合は、次のように感嘆符を使用して強制的にラップを解除できます。

// Here is an optional variable:

var age: Int?

// Here is how you would force unwrap it:

var unwrappedAge = age!

オプションを強制的にアンラップし、それがnilに等しい場合、このクラッシュエラーが発生する可能性があります。

ここに画像の説明を入力してください

これは必ずしも安全であるとは限らないため、タイプと値がわからない場合にクラッシュを防ぐ方法を次に示します。

方法2および3は、この問題に対する保護手段です。

2)暗黙的にアンラップされたオプション

 if let unwrappedAge = age {

 // continue in here

 }

ラップされていない型がIntではなくIntになっていることに注意してください

3)ガードステートメント

 guard let unwrappedAge = age else { 
   // continue in here
 }

ここから先に進んで、ラップされていない変数を使用できます。変数の型が確実である場合は、(!を使用して)アンラップを強制することのみを確認してください。

あなたのプロジェクトで頑張ってください!


1
return age!= nil?「(名前)は(年齢!)歳です。」:「(名前)は彼の年齢を隠しています。」
leedream

1
私が抱えていた問題で頭痛がしなくなりました。どうもありがとうございました。
Bruno Recillas 2017年

8

テスト/デバッグの目的で、常にnil値をテストする必要なくオプションを文字列として出力することがよくあるため、カスタム演算子を作成しました。

この回答を別の質問で読んだ後、さらに改善しました。

fileprivate protocol _Optional {
    func unwrappedString() -> String
}

extension Optional: _Optional {
    fileprivate func unwrappedString() -> String {
        switch self {
        case .some(let wrapped as _Optional): return wrapped.unwrappedString()
        case .some(let wrapped): return String(describing: wrapped)
        case .none: return String(describing: self)
        }
    }
}

postfix operator ~? { }
public postfix func ~? <X> (x: X?) -> String {
    return x.unwrappedString
}

明らかに、演算子(およびその属性)を好みに合わせて調整したり、代わりに関数にすることもできます。とにかく、これにより、次のような単純なコードを記述できます。

var d: Double? = 12.34
print(d)     // Optional(12.34)
print(d~?)   // 12.34
d = nil
print(d~?)   // nil

他の人のプロトコルのアイデアを統合することで、オプションのチェーンを使用する場合によく発生するネストされたオプションでも機能するようになりました。例えば:

let i: Int??? = 5
print(i)              // Optional(Optional(Optional(5)))
print("i: \(i~?)")    // i: 5

1
Swift 3以降、Swift標準ライブラリ関数debugPrint(_:separator:terminator :)を使用することもできます。ただし、これは文字列を二重引用符で囲んで印刷します。
psmythirl 2016

@psmythirl:知っておきたい!ただし、オプションをString別の場所に単に渡すか埋め込むことが必要な場合があります(たとえば、ログ/エラーメッセージ)。
ジェレミー

print(d as Any)
DawnSong

7

更新

単に使用しますme.age ?? "Unknown age!"。3.0.2で動作します。

古い答え

強制的にアンラップしない場合(マッハシグナル/ nilの場合はクラッシュなし)、これを行う別の良い方法は次のとおりです。

(result["ip"] ?? "unavailable").description

result["ip"] ?? "unavailable" 動作するはずですが、少なくとも2.2では動作しません

もちろん、「利用不可」を「nil」、「not found」など、あなたに合ったものに置き換えてください。


4

オプションのラップを解除するage!には、の代わりに使用しますage。現在、オプションの値を出力している可能性がありますnil。それがで包まれた理由Optionalです。


4

迅速にOptionalnil、いくつかのケースであることができるものです。100%である場合、a variableは常に何らかの値を持ち、強制的にアンラップする変数を使用してniladd !を返しません。

他のケースでは、値に確信が持てない場合は、if letブロックを追加guardするか、値が存在することを確認してください。それ以外の場合は、クラッシュが発生する可能性があります。

if letブロック:

if let abc = any_variable {
 // do anything you want with 'abc' variable no need to force unwrap now.
}

以下のためのguard声明:

guard 条件が満たされない場合に制御を返す条件構造です。

特定の値が存在しない場合にを返すことができるため、私は多くの状況でguardover if letblock を使用することを好みfunctionます。変数が存在することが不可欠である関数があるときのように、私たちはガードステートメントでそれをチェックすることができ、それが存在しないことを返します。すなわち;

guard let abc = any_variable else { return }

変数が存在する場合、ガードスコープ外の関数で「abc」を使用できます。


3

ageオプションの型Optional<Int>です。nilと比較すると、値がある場合とない場合は毎回falseを返します。値を取得するには、オプションをアンラップする必要があります。

あなたの例では、あなたはそれが値を含んでいるのかわからないので、代わりにこれを使うことができます:

if let myAge = age {
    // there is a value and it's currently undraped and is stored in a constant
}
else {
   // no value
}

3

別のビューコントローラーから文字列(プロパティ)の値を出力するためにこれを行いました。

ViewController.swift

var testString:NSString = "I am iOS Developer"

SecondViewController.swift

var obj:ViewController? = ViewController(nibName: "ViewController", bundle: nil)
print("The Value of String is \(obj!.testString)")

結果:

The Value of String is I am iOS Developer

2
オプションを強制的にアンラップしないでください
E-Riddie

3

次のguardステートメントを確認してください。

for student in class {
    guard let age = student.age else { 
        continue 
     }
    // do something with age
}

3

デフォルト値がある場合:

print("\(name) is \(age ?? 0) years old")

または名前がオプションの場合:

print("\(name ?? "unknown") is \(age) years old")


1

テーブルビューのセルでOptional( "String")を取得していました。

最初の答えは素晴らしいです。そして私がそれを理解するのを助けました。ここに私がしたことは、私のような新人を助けるためです。

カスタムオブジェクトに配列を作成しているので、常に最初の位置に項目があるので、別の変数に強制的にアンラップできます。次に、その変数を使用して印刷します。私の場合は、テーブルビューのセルテキストに設定します。

let description = workout.listOfStrings.first!
cell.textLabel?.text = description

今はとてもシンプルに思えますが、理解するのに少し時間がかかりました。


-1

これはこの質問に対する正確な答えではありませんが、この種の問題の1つの理由です。私の場合、「if let」と「guard let」を使用して文字列からOptionalを削除できませんでした。

したがって、AnyではなくAnyObjectを使用して、swiftの文字列からオプションを削除します。

答えはリンクを参照してください。

https://stackoverflow.com/a/51356716/8334818

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.