質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

308閲覧

Swift3 配列の初期化ができません

mitci

総合スコア37

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2017/08/27 06:48

###前提・実現したいこと
辞書へ代入するための仮の配列を作り、辞書へ代入したあと、
その配列をもう一度使えるように初期化したいのですが、
配列が初期化できません。

ある文字列
-> 行ごとに配列へ
-> さらに1要素を2つにわける
-> 1つを辞書にキーに、1つを値にする

というコードなのですが、最初の文字列や辞書は初期化、代入ができるものの、配列のみ初期化できません。

###発生している問題・エラーメッセージ

swift

1Swift Compiler Error 2 Value of tuple type '()' has no member 'removeAll'

###該当のソースコード

swift

1func updateMediaInfo(mediaItem: MPMediaItem) { 2 //一部省略 3 lyricsDict = [:] 4 //前回のキーと要素を初期化 5 lyricsString = mediaItem.lyrics! 6 var lyricsArray = lyricsString.components(separatedBy: CharacterSet.newlines) 7 .map { $0.components(separatedBy: "//") } 8 .filter { $0.count == 2 } 9 .forEach {lyricsDict[$0[0]] = $0[1]} 10 lyricsString = "" 11 //使用したlyricsStringを初期化 12 lyricsArray.removeAll() //これがエラーになる・・・

見てわかると思いますが、ある要素(歌詞mediaItem.lyrics!)を行ごとに配列の要素にし、さらに//で歌詞1行を2つの文字列に分けた上で一つをlyricsDictのキーに、もう一方を値にしています。
これを何度か繰り返すに当たって、lyricsDictlyricsArrayを初期化したいのですが、配列のみ初期化や他の値の代入ができません。
もちろん、
.allRemove()lyricsArray = []に変えても、同じエラーが出てしまいます。


ちなみにこれは音楽再生系のアプリで、上記コードは**nowPlayingItemChangedメソッドが呼び出されるたびに呼び出されるコード**です。
1秒ごとにキーを更新して値を呼び出すというコードもこのアプリには含まれていますが、配列はその辞書を作るためのものなので、そちらの処理は関係ないように思えます。

###考察
エラーの文中にタプルとの記述があるため、.map.filterの過程でlyricsArrayが普通の配列ではなくなってしまったのでは、と考えました。
また、.forEachについては調べてもわからず、
とりあえずそう書いてみたら理想の動き(//の前後をわけて、キーと値にする)ができたので使っている状態なのです・・・

しかし、
playgroundで以下のように簡易的に再現してみると、

swift

1var array = ["りんご//Apple", "ばなな//Banana", "マンゴー//Mango", "トマト//Tomato"] 2var dictionary = [String:String]() 3array.map { $0.components(separatedBy: "/") } 4 .filter { $0.count == 2 } 5 .forEach { dictionary[$0[0]] = $0[1] } 6print(array) 7 //["りんご//Apple", "ばなな//Banana", "マンゴー//Mango", "トマト//Tomato"] 8array = [] 9print(array) 10 //[]

結果は[]と普通に初期化されます。

###試したこと
ViewControllerの直下にvar lyricsArray :[String] = []として宣言しておき、
問題の箇所を、

swift

1lyricsArray = [] 2lyricsArray = lyricsString.components(separatedBy: CharacterSet.newlines) 3 .map { $0.components(separatedBy: "//") } 4 .filter { $0.count == 2 } 5 .forEach {lyricsDict[$0[0]] = $0[1]}

とメソッド内で変数の宣言をなしにすると、
.forEachの部分で別のエラーが出てしまいました。

swift

1Swift Compiler Error 2 Cannot assign value of type '()' to type '[String]'

です。

###補足情報(言語/FW/ツール等のバージョンなど)
swift3Xcode8

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Stripe

2017/08/27 13:51

ところで、forEachの戻り値の型が何なのか知ってますか?
mitci

2017/08/28 00:21 編集

ごめんなさい。さっぱりわかっておりません…。お恥ずかしい話、ここで同様に質問して回答をそのまま貼り付けたのです。 type of ()ということは空のタプルでしょうか?
fuzzball

2017/08/28 01:19

回答を書こうと思ったら答えが出てますねw 戻り値はVoid = 空のタプル、で正解です。
mitci

2017/08/28 01:28 編集

なるほど・・・つまりlyricsArrayが空のタプルになってしまって、変更ができないということですね ということはnowPlayingItemChangedメソッドで繰り返し使いたい場合は、どうすればいいのでしょうか・・・(というかむしろ、最初からlyricsArrayは配列として宣言できていないのでしょうか・・・?)
fuzzball

2017/08/28 01:30

質問のコードを見る限りでは lyricsArray はそもそも必要ないように思えますが?
mitci

2017/08/28 01:36

はい・・・ ずっとwarningが出ていて気になったのですが、_ = lyricsString.components...という書き方で大丈夫でした・・・ そして文字列が増えていってしまう原因はlyricsArrayの初期化ではなく、lyricsDictの初期化ができていなかったからのようですね・・・ ここまで言われてやっと気がつくことができました・・・
fuzzball

2017/08/28 01:40

戻り値は無いのですから _ = を書く必要はありません。lyricsDictは lyricsDict = [:] で初期化出来ているはずですが?
mitci

2017/08/28 01:43

ああ、そうなんですね はい、lyricsDict = [:]を入れたコードを詳細に実機で検証するより前に、頭の中で辞書は初期化したから、次は配列の初期化か…と考えてしまっていました。大変ご迷惑をおかけしました…
guest

回答1

0

自己解決

解決しました。
大変にお恥ずかしい話なのですが、
そもそも初期化する必要がなかったことに気がつかせていただきました。

というかそもそも配列自体必要がなかったとは・・・

Stripeさん、fuzzballさん
ご迷惑をおかけしました

投稿2017/08/28 10:34

mitci

総合スコア37

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問