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

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

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

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

Q&A

解決済

1回答

1033閲覧

Swift dictionaryの要素を識別する方法としてindexを使用するメリットについて

moriman

総合スコア615

Swift

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

0グッド

0クリップ

投稿2020/05/19 03:02

swift

1import UIKit 2import SwiftUI 3import CoreLocation 4 5let landmarkData: [Landmark] = load("landmarkData.json") 6 7func load<T: Decodable>(_ filename: String) -> T { 8 let data: Data 9 10 guard let file = Bundle.main.url(forResource: filename, withExtension: nil) 11 else { 12 fatalError("Couldn't find (filename) in main bundle.") 13 } 14 15 16 do { 17 data = try Data(contentsOf: file) 18 } catch { 19 fatalError("Couldn't load (filename) from main bundle:\n(error)") 20 } 21 22 do { 23 let decoder = JSONDecoder() 24 return try decoder.decode(T.self, from: data) 25 } catch { 26 fatalError("Couldn't parse (filename) as (T.self):\n(error)") 27 } 28} 29 30 31 32 33final class ImageStore { 34 typealias _ImageDictionary = [String: CGImage] 35 fileprivate var images: _ImageDictionary = [:] 36 37 fileprivate static var scale = 2 38 39 static var shared = ImageStore() 40 41 42 func image(name: String) -> Image { 43 let index = _guaranteeImage(name: name) 44 45 return Image(images.values[index], scale: CGFloat(ImageStore.scale), label: Text(name)) 46 } 47 48 49 50 51 static func loadImage(name: String) -> CGImage { 52 53 guard 54 let url = Bundle.main.url(forResource: name, withExtension: "jpg"), 55 let imageSource = CGImageSourceCreateWithURL(url as NSURL, nil), 56 let image = CGImageSourceCreateImageAtIndex(imageSource, 0, nil) 57 else { 58 fatalError("Couldn't load image (name).jpg from main bundle.") 59 } 60 61 return image 62 } 63 64 65 66 67 fileprivate func _guaranteeImage(name: String) -> _ImageDictionary.Index { 68 if let index = images.index(forKey: name) { return index } 69 images[name] = ImageStore.loadImage(name: name) 70 return images.index(forKey: name)! 71 } 72}

https://developer.apple.com/tutorials/swiftui/building-lists-and-navigation
上記ページのダウンロードしたプロジェクトのData.swiftなんですが、

ストアドプロパティimagesはディクショナリで、その要素を識別・指定するためにindexを使っています。
ディクショナリ内の要素を識別するのはkeyでできるような気がします。
keyで識別できるのであればindexを使う必要はないと思うのですが、
indexを使っている理由がよくわかりません。

上記コードはindexを使わずに実装することは不可能なのでしょうか?
使わなくてもできるけど使っているのであれば、indexを使うなんらかのメリットがあると思うのですが、
それって何なのでしょうか?

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

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

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

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

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

hoshi-takanori

2020/05/19 16:53

毎回 key でアクセスするよりは index を使った方が速い可能性はありますが、key の追加や削除があると index がずれて事故の原因になるので、普通は key でアクセスする方がいいと思います。(Apple 内部ではレビュー体制が整っているので事故は起こさないし、それよりも速度が重要なのでしょう、きっと。)
guest

回答1

0

ベストアンサー

たしかに Key でできそうですね。同じく、インデックスを使う理由はまだ分からないですけれど、ひとまず Key を使ったコードに書き換えてみました。書き換えたメソッドだけを抜粋します。

swift

1func image(name: String) -> Image { 2 3 return Image(_guaranteeImage(name: name), scale: CGFloat(ImageStore.scale), label: Text(name)) 4} 5 6fileprivate func _guaranteeImage(name: String) -> CGImage { 7 8 if let image = images[name] { 9 10 return image 11 } 12 else { 13 14 let image = ImageStore.loadImage(name: name) 15 images[name] = image 16 17 return image 18 } 19}

キーだけで画像をやりくりできるので、インデックスは必要なくなっています。

今回の修正では、もともとインデックスをやり取りしていたコードを、CGImage 型の値を直接やり取りするコードに変更しましたけれど、この部分は好みによっては、Key をやり取りするコードにしても良いかもしれません。

インデックスを使わない理由は今のところ不明

インデックスを使っていた理由は、想像ですけれど、最後の image(named:) 関数まで画像データの最終的な取得を避けているところから、もしかすると引数や戻り値で CGImage 型の値を渡したり受け取ったりするのを最後の最後まで避けたかったのかもしれません。

ただ、loadImage メソッドを使う必要があったときには格納と再取得が必要になっているので、インデックスを使わないコードと「どっちもどっち」にも見えるので、この想像が当たっているかはわかりません。

また、一般的には Int 型の値を扱うのが最も速いと思うので、インデックスを扱うのも効率的かと思うのですけれど、CGImage はクラス型で定義されている様子なので、同等の速度が期待できるポインターで扱えるため、そちらも「どっちもどっち」な印象でした。

確かな理由を想像できないので、インデックスを使う意図が汲める人がいらしたら教えてください。

インデックスにするかどうかは好みの可能性も

上記のようにインデックスを使わない理由を考えてみましたけれど、そもそものコードの修正で今回の修正ではやり取りするデータに「画像」を選びましたけど、扱うものがインデックスでも、キーでも、画像でも良さそうなことを踏まえると、好みに帰着する可能性もありそうです。

投稿2020/05/19 10:47

TomohiroKumagai

総合スコア441

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

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

moriman

2020/05/25 01:06

ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問