2016-05-10 11 views
0

明らかに単純なもので作業している間、私は本当に厄介なエラーがあります。NSArray、NSUserDefaults、オプションとアンラッピングの混乱

私はNSArrayを持っています。これは、アプリが初めて起動するときに言葉で埋めます。

その後、私は、配列を使用したいので、私はクラスの内部で別の配列を宣言し、ある時点で:

var localArray = NSUserDefaults.standardUserDefaults().arrayForKey("array")!

その後、私はラベル内の単語を表示したいです。ユーザーがボタンを押すと(前/後)、次/前の単語が表示されます。かなり簡単ですね。それはありますが、どういうわけか私は本当に厄介なエラーになります。

Iは、次/前の単語のための2つの方法がある:

@IBAction func nextWord(sender: AnyObject) { 
     if let currentIndex = localArray.indexOf(label.text!) 
     { 
      if currentIndex == localArray.count-1 
      { 
       label.text = localArray[0] as? String 
      } 
      else 
      { 
       label.text = localArray[currentIndex+1] 
      } 
     } 
    } 

後方に行くための他の方法は、(必要な変更を加えて)同一です。

そしてviewDidLoadに私だけ設定ラベルのテキスト:

label.text = localArray[0] as? String 

問題がif let文です。ユーザーのデフォルトを使用する前に、ちょうどいくつかの文字列でlocalArrayを初期化しました。そしてすべてがうまくいった。しかし、ユーザーのデフォルトを追加すると、狂気が始まりました。どこにでもエラーがありましたlocalArrayは、配列がラップされていないと言っています。だから私は!をローカルの初期化時にユーザーのデフォルト配列の後に追加しました。

しかし、最後の2つのエラー(if let文)は意味をなさない。今度はindexOf()メソッドがエラーを投げます。これは以前には起こりませんでした。また、文字列(label.text!)を@noescape (AnyObject) throws -> Boolに変換できないこともわかります。

だから、私はその文字列をNSStringに変換して動作させる必要がありますか?私はユーザーのデフォルトの配列に関連する "ブリッジング"について何かを発見しました。それは私の問題ですか?

ここで私はどんなバグですか?なぜ、配列内の文字列を文字列に明示的にダウンキャストする必要がありますか?なぜindexOfメソッドが変更されたのですか?

アンラップされたオプションの動作はオプションではありませんか?

+2

純粋なスウィフトコードですか?その場合は、NSArrayを使用しないでください。ネイティブのコレクション型を代わりに使用します。これは、NSArrayをNSUserDefaultsに格納するために自由にブリッジできます(要素がobj-cにブリッジ可能である限り)。 – Hamish

+0

スイフトのみです。ネイティブコレクションタイプを使用するとどういう意味ですか? – Lawrence413

+0

まあ... [Swift自体が提供するコレクションの種類](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html#//apple_ref/doc/uid/TP40014097 -CH8-ID105)!文字列の配列が必要な場合は、 '[String]'が必要です。 'String'は' NSString'に自由にブリッジすることができるので、配列をNSArrayに自由にブリッジすることができます。 – Hamish

答えて

1

作成しているオブジェクトは配列ではありません(少なくともコンパイラはそれがわからない)。 arrayForKey("array")!関数は、ではなく、AnyObjectを返しています。だから、コンパイラはこのオブジェクトがAnyObjectだと思っています。私はこの問題を解決する方法をすぐに配列をキャストすることであろう(正しい方法ではないかもしれない):

if let myArray: AnyObject! = NSUserDefaults.standardUserDefaults().objectForKey("array") { 
    //Your array exists, cast it now and use it 
    var localArray = myArray as! Array<String> 
} 
else 
{ 
    //Something bad happened, the array isn't there. 
} 

次に、あなたが後でアンラップ行う必要があります。このオブジェクトが常に存在し、キャストが常に機能することがわかっている場合は?!に変更できます。

さらに詳しい情報はthis answerをご覧ください。

+1

if文で囲み、エラー処理をelse部分に入れてください。 –

+0

それは、常にキャストに失敗することを私に伝えます... – Lawrence413

+0

今すぐコードを試して、私が参照した答えを正確に使用するように編集しました。 – Putz1103

0

これはモジュロ演算子で実装された方がずっと良いでしょう。

let newIndex = (oldIndex + 1) % localArray.count

私はあなたの質問の大半に答えるためより多くの情報が必要。 localArrayの種類は何ですか?

+0

私はそれを指定しなかった。しかし、それは 'NSArray'でなければなりません。 'newIndex'を使うために何を置き換えるべきですか?まだ 'currentIndex'を使っているので、何も修正しません。 – Lawrence413

+0

わかりやすくするため、 'currentIndex'の名前を変更しました。 – Alexander

+0

"私はそれを指定していませんが、NSArrayでなければなりません"という意味はどうですか?あなたはその配列をユーザーのデフォルトに置きます。どのタイプですか?私はそれが何であるべきか尋ねることはありません**、率直に言って、それは無関係です。それは何ですか? – Alexander

0

常にavoid force unwrapping optionals(大部分の強制ダウンキャスト)にする必要があります。安全に(正しいタイプで)NSUserDefaultsからあなたの配列を取得するために、次の操作を行うことができます。

if let array = NSUserDefaults.standardUserDefaults().arrayForKey("array") as? [String] { 
    // do something with your [String] array 
} else { 
    // do error handling 
} 

これが何をするか、あなたの配列を表す、NSUserDefaultsから[AnyObject]?を取得することです。 as?を使用して、条件付きでダウンキャスト&を紐のスウィート配列([String])に戻すことができます。これがうまくいかなかった場合は、その事態を安全に処理できます。

+0

ありがとうございました!それは私の状況を明らかにした。 – Lawrence413