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

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

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

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

Q&A

解決済

2回答

5803閲覧

NSSingleObjectArrayIとは?

ToshiyukiSato

総合スコア12

Swift

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

0グッド

1クリップ

投稿2018/04/29 02:24

編集2018/05/01 12:02

Swiftにおいて、APIから取得したJSONをパースし、画面に表示しやすいように配列化しました。
その配列をprintすると、以下のように「NSSingleObjectArrayI」というものが入りました。

Swift

1["A", <__NSSingleObjectArrayI 0x604000208cc0>(12345), <__NSSingleObjectArrayI xxxxxxxxxxxxxx>(98765)]

この配列をtableViewで画面表示しようとすると、以下のエラーが出ます。

Swift

1Could not cast value of type '__NSSingleObjectArrayI' (0x10dddc328) to 'NSString' (0x10ca08d68).

「NSSingleObjectArrayI」とは何なのかをググってみたのですが、よくわかりません。
「NSSingleObjectArrayI」とは何でしょうか?

これを消して、以下のような通常(?)の配列にすることはできませんでしょうか?
的はずれな質問になっていましたら申し訳ございません。

Swift

1["A", 12345, 98765]

コメントいただいた不足点の追記です(2018/04/29)

※コードが長いので今回の相談内容とは関係なさそうな部分は削りましたが、この部分でコメントへの回答になっているか不安です。すみません。

JSONをパースした方法

Swift

1let taskReport = URLSession.shared.dataTask(with: request, completionHandler: {jsonData, response, error in 2 do { 3 let reportJsonData = try JSONSerialization.jsonObject(with: jsonData!) as! Dictionary<String, Any> 4 //取得データを画面表示用の配列に組み替える処理部分がここに入ります(省略) 5 }catch{ 6 print(error.localizedDescription) 7 } 8}) 9taskReport.resume()

元のJSON

JSON

1["reports": <__NSSingleObjectArrayI 0x6000002035d0>({ 2 columnHeader = { 3 dimensions = ("ga:pageTitle"); 4 }; 5 data = { 6 rows = ({ 7 dimensions = ("A"); 8 metrics = ({ 9 values = (12345); 10 },{ 11 values = (98765); 12 }); 13 }); 14 }; 15})]

以下のAPIからデータ取得しています。
Google Analytics Reporting API v4
https://developers.google.com/analytics/devguides/reporting/core/v4/basics?hl=ja

コメントいただいた不足点の追記です(2018/05/01)

「取得データを画面表示用の配列に組み替える処理部分がここに入ります(省略)」の部分は以下となっています。少し長いのですが。見づらくて申し訳ないです。

//reports以下の階層の処理 let reports = reportJsonData["reports"] as! NSArray //reports以下のデータを取得する for roop in reports { let next = roop as! NSDictionary //連想配列にする let data = next["data"] as! NSDictionary //data以下のデータを取得する //totals以下の階層の処理 let totals = data["totals"] as! NSArray for roopTotals in totals { let nextTotal = roopTotals as! NSDictionary //連想配列にする let totalValues = nextTotal["values"] as! NSArray //values以下のデータを取得する self.totalPvArray.append(totalValues) } //rows以下の階層の処理 var titleArray:[Any] = [] //ページタイトル格納用の空配列 var valuesArray:[Any] = [] //PV格納用の空配列 let rows = data["rows"] as! NSArray for roopNext in rows { let next2 = roopNext as! NSDictionary //連想配列にする let metrics = next2["metrics"] as! NSArray //metrics以下のデータを取得する //metrics以下の階層の処理 var valuesArray2:[Any] = [] for roopNext2 in metrics { let next3 = roopNext2 as! NSDictionary //連想配列にする let values = next3["values"] as! NSArray //values以下のデータを取得する valuesArray2.append(values) } titleArray = titleArray + [next2["dimensions"]!] //配列にページタイトルを格納する valuesArray = valuesArray + valuesArray2 //配列にPVを格納する } //配列を組み替える var count = 0 var count2 = 0 let countTotal = titleArray.count while count < countTotal { let pvArrayLine = [titleArray[count],valuesArray[count2],valuesArray[count2+1]] self.pvArray.append(pvArrayLine) count += 1 count2 += 2 } } //メインスレッドに戻して、テーブルを再描画する DispatchQueue.main.async() { () -> Void in self.PVTable.reloadData() }

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

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

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

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

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

MasakiHori

2018/04/29 13:30

JSONをパースした方法、元のJSONはどんなものですか?
ToshiyukiSato

2018/04/29 14:06

コメントをありがとうございます。質問内容へ追記しました。コメントいただいたことへの回答になっていると良いのですが。
newmt

2018/05/01 06:14

//取得データを画面表示用の配列に組み替える処理部分がここに入ります(省略)←ここはどうなっていますでしょうか?エラーメッセージ見てみると、配列の値を文字列としてキャストしようとしている気がします。
guest

回答2

0

ベストアンサー

すいません。ちゃんと追い切れていないかもしれませんが、

let values = next3["values"] as! NSArray //values以下のデータを取得する

ここが配列になっているので、

["A", [12345], [98765]]

になっているのではないでしょうか?

let values = next3["values"] as! NSString //values以下のデータを取得する

にしてみたらどうなりますでしょうか?

投稿2018/05/01 21:24

newmt

総合スコア1277

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

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

ToshiyukiSato

2018/05/03 05:34

ありがとうございます! いただいたアドバイスを元にいろいろ修正してみたのですが、以下はこのままNSArrayとして取得しないとエラーになってしまいました。 ```Swift let values = next3["values"] as! NSSArray //values以下のデータを取得する ``` そのため、無理矢理感があるのですが、以下のように取得したあとにString化したところ、期待していた配列に組み直すことができました! ```Swift let valuesArray = next3["values"] as! NSArray //values以下のデータを取得する let values:String = valuesArray.componentsJoined(by: ",") //配列をstringに変換する ``` どの部分に問題がありそうなのかも見当がつかず大変困っていましたが、問題箇所を特定できて、解決できそうでとても助かりました。 まだまだコードが未熟すぎるのですが、少しずつコードも精度アップしていきたいと思います。 ありがとうございます!
guest

0

まず_NSSingleObjectArrayIですが、これは非公開のNSArrayのサブクラスです。NSArrayだと考えてOKです。

reports.data.rows.metrics.valuesは配列ですので、(最初の)要素を取り出す必要があります。

ですので、そのまま修正すると

swift

1let values = next3["values"] as! NSArray 2valuesArray2.append(values[0])

となります。


これは好みだとは思いますが、SwiftではNSArrayやNSDictionaryを使うよりArray, Dictionaryを使う方が楽です。


_NSSingleObjectArrayIに付け加え。
NSArrayはクラスクラスタといって、非公開のサブクラスがたくさんあって、要素の数や生成のされ方によって、最も効率のいいサブクラスが自動的に選択されるようになっています。
なので具象クラスが何であるのかは気にしなくていいです。

投稿2018/05/02 01:50

MasakiHori

総合スコア3391

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

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

ToshiyukiSato

2018/05/03 05:37 編集

ありがとうございます! NSArrayだと考えていいのですね。 意味がわからずどう処理するべきか方針も見えていなかったのですが、すっきりしました。 また、NSArrayではなく、Arrayを使った方が良いとのこともありがとうございます! 影響範囲を見ながら、修正をしていきたいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問