final class ImageStore { typealias _ImageDictionary = [String: CGImage] fileprivate var images: _ImageDictionary = [:] fileprivate static var scale = 2 static var shared = ImageStore() func image(name: String) -> Image { let index = _guaranteeImage(name: name) return Image(images.values[index], scale: CGFloat(ImageStore.scale), label: Text(name)) } static func loadImage(name: String) -> CGImage { guard let url = Bundle.main.url(forResource: name, withExtension: "jpg"), let imageSource = CGImageSourceCreateWithURL(url as NSURL, nil), let image = CGImageSourceCreateImageAtIndex(imageSource, 0, nil) else { fatalError("Couldn't load image (name).jpg from main bundle.") } return image } fileprivate func _guaranteeImage(name: String) -> _ImageDictionary.Index { if let index = images.index(forKey: name) { return index } images[name] = ImageStore.loadImage(name: name) return images.index(forKey: name)! } }
swiftUIのチュートリアル
https://developer.apple.com/tutorials/swiftui/building-lists-and-navigation
に出てくるコードなのですが、
_guaranteeImage(name: String)メソッドの中に出てくるimages.index(forKey: name)の定義に飛ぶと、
extension Dictionary : Collection { //省略 /// Returns the index for the given key. /// /// If the given key is found in the dictionary, this method returns an index /// into the dictionary that corresponds with the key-value pair. /// /// let countryCodes = ["BR": "Brazil", "GH": "Ghana", "JP": "Japan"] /// let index = countryCodes.index(forKey: "JP") /// /// print("Country code for (countryCodes[index!].value): '(countryCodes[index!].key)'.") /// // Prints "Country code for Japan: 'JP'." /// /// - Parameter key: The key to find in the dictionary. /// - Returns: The index for `key` and its associated value if `key` is in /// the dictionary; otherwise, `nil`. @inlinable public func index(forKey key: Key) -> Dictionary<Key, Value>.Index?
上記のコードが出てきました。コメントを見るとだいたい「キーを指定すると対応するインデックスを返す」くらいのことはわかるのですが、文法というかコードの作りとして上記のコードは、
エクステンションを用いてDictionary型がCollectionプロトコルに準拠している。
そのために必要な実装をブロック内に記述する。その一部が上記の
@inlinable public func index(forKey key: Key) -> Dictionary<Key, Value>.Index?
ということだと思うのですが、メソッドの実装がありません。(引数名、引数の型注釈、戻り値の型注釈のみ)
index(forKey key: Key)メソッドの本体(実装)は書かなくて良いのでしょうか?
多分@inlinable属性が関係あるようなので
https://docs.swift.org/swift-book/ReferenceManual/Attributes.html
のinlinableの部分を見て、インライン関数、インライン展開などネットで調べたのですが、いまいちよくわかりません。
結局@inlinableをつけると、メソッドの本体を呼び出し側に記述できる、ということなのでしょうか?
そしてそれが
images.index(forKey: name) { return index }
の最後の{ return index }の部分なのでしょうか?
ただ、2つ目のサンプル(コメントに書いてあるサンプルコード)のメソッド呼び出しでは、
let index = countryCodes.index(forKey: "JP")
とあり、本体部分は記述されていません(普通の関数呼び出し)。それでも普通に期待通りの挙動で結果が返されます。
つまり呼び出し側で本体を定義しない場合はどこかに事前に作ってある定義が呼び出される、みたいなことなんでしょうか?
全て推測なのですが、どういう仕組みなんでしょうか?
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/02/17 07:07