

swiftでコードを書いています。

swiftのシミュレーター でiphone8でビルドしても普通に動くんですが、それ以外の実機(iphoneX)などでビルドするとUnexpectedly
found nil while unwrapping an Optional valueというエラーが出ます。

ちなみにエラーの箇所は  
let userDefaults: UserDefaults = UserDefaults.standard  
let teamID: String = (userDefaults.object(forKey: "teamID")! as? String)!  
です。

userDefaultsの箇所なのですが、新しい実機でビルドすると値を取得できないとかあるのですか？

わかる方教えてください。


CC BY-SA 4.0
2018-09-29T11:12:55.773
48825
2022-09-26T08:05:40.513
29900
question
swift
Unexpectedly found nil while unwrapping an Optional valueについて


`UserDefaults`というのは、自分で値をセットしないと値は取り出せないのですが、アプリケーション起動時等、`object(forKey:)`を呼び出す前に`Userdefaults.standard.register([String:
Any])`で該当するキーの値をセットしていますか？  
もしくは、`userDefaults.set("[チームID]", forKey: "teamID")`で、値をセットしていますか？

もしセットしていないのであれば、  
`userDefaults.object(forKey: "teamID")`の直後の`!`で、`nil`をアンラップして落ちてしまうのだと思います。

ですので、一番簡単な解決方法は、  
`let teamID: String = (userDefaults.object(forKey: "teamID") ??
"[teamIDがnilだったときのデフォルト値]" as? String)!`  
なのですが、UserDefaultというのは、どちらかというとアプリケーションの設定などを保存すべき場所で、例に示されたチームIDは、外部ファイルやCoreData,
SQLite等のデーターベースファイルに保存すべきだとは思います。

このため`userDefaults.object(forKey: "teamID")`が`nil`にならないプログラムを作るには、

プロジェクト内に`defaults.plist`を作り、そこに参照されるキー（今回の場合だと`teamID`ですね。）の値を全て列挙しておき、アプリケーション起動時(`applicationDidFinishLaunching`等)に

[code]

    do {
        let bundle: Bundle = Bundle.main
        if let defaultsURL: URL = bundle.url(forResource: "defaults", withExtension: "plist") {
            let defaults: Dictionary<String, Any> = try NSDictionary(contentsOf: defaultsURL)
            UserDefaults.main.registerDefaults(defaults)
        } // end found defaults.plist
    } catch {
        print("defaults.plist is not found")
    }
    
[/code]

として、以降プログラムで参照する値を登録しておく必要があります。


CC BY-SA 4.0
2018-09-29T11:54:56.847
48827
2018-09-29T11:54:56.847
14745
48825
answer


**_userDefaultsの箇所なのですが、新しい実機でビルドすると値を取得できないとかあるのですか？_**

`UserDefaults`はあなたのアプリが初めてインストールされた直後は空っぽです。これは実機でもシミュレータでも変わりません。

「シミュレーター
でiphone8でビルドしても普通に動く」と言うことですが、開発中からiPhone8のシミュレータを何度か使用していたので、過去に値を設定するコードが動いていたのでしょう。試しに今まであなたのアプリを一度も試したことのないシミュレータがあれば、どうなるかやってみると良いでしょう。

と言うわけで、`UserDefaults`にアクセスする場合は、最初は空の可能性があると言うことを常に意識しておかないといけません。

と言うか、表題の **Unexpectedly found nil while unwrapping an Optional value**
に関連して言うと、あなたのコードは危険な「私のアプリをクラッシュさせて演算子」(`!`)を使いすぎですね。Conditional
Bindingや`??`演算子などをうまく使用して、`nil`耐性のあるコードにすることをお勧めします。

さらについでに言うと、設定値が`String`型であることがわかっている場合には、`string(forKey:)`メソッドを使われた方がいいでしょう。

[code]

        let userDefaults = UserDefaults.standard
        if let teamID = userDefaults.string(forKey: "teamID") {
            //teamIDを使う
            print("teamID:", teamID)
            //...
        } else {
            //teamIDに初期値を入れる
            print("teamID is nil, setting default value")
            userDefaults.set("...", forKey: "teamID")
            //...
        }
    
[/code]

teamIDがどんな使い方をされるのかによって、色々なやり方はあるでしょうが、もしセキュリティ上外部から見られてはいけない情報なら`UserDefaults`(や普通のファイルやCore
Data等)ではなく、Keychainの使用を検討された方がいいと思います。


CC BY-SA 4.0
2018-09-29T15:13:53.177
48833
2018-09-29T15:13:53.177
13972
48825
answer