🪶

Cannot convert value of type 'String' to expected argument type 'URL?'

2024/07/24に公開

AsyncImageを使ってエラーでつまる(−_−;)

前のページから、String型のプロパティを受け取って、表示するだけなのだが、なぜかできない???

詳細ページを作っていたときのソースコード

import SwiftUI

struct ShopDetailView: View {
    var shop: Shop
    
    var body: some View {
        NavigationView {
            VStack(alignment: .leading, spacing: 10) {
                AsyncImage(url: shop.imageUrl)
                Text("お店の名前: \(shop.shop_name)")
            }
            .padding()
            .navigationBarTitle(shop.shopname, displayMode: .inline)
        }
    }
}

🤖AIに質問してみる

エラーの原因は、AsyncImageがURL型を期待しているのに対し、shop.imageUrlがString型であることです。この問題を解決するために、StringをURLに変換する必要があります。

import SwiftUI

struct ShopDetailView: View {
    var shop: Shop
    
    var body: some View {
        NavigationView {
            ScrollView {
                VStack(alignment: .leading, spacing: 10) {
                    // get shop image url
                    if let url = URL(string: shop.imageUrl) {
                        AsyncImage(url: url) { phase in
                            switch phase {
                                // loading...
                            case .empty:
                                ProgressView()
                            case .success(let image):
                                image
                                    .resizable()
                                    .aspectRatio(contentMode: .fit)
                                    .frame(height: 200)
                            case .failure:
                                Image(systemName: "photo")
                                    .resizable()
                                    .aspectRatio(contentMode: .fit)
                                    .frame(height: 200)
                                // error
                            @unknown default:
                                EmptyView()
                            }
                        }
                    } else {
                        Image(systemName: "photo")
                            .resizable()
                            .aspectRatio(contentMode: .fit)
                            .frame(height: 200)
                    }
                    
                    Text("お店の名前: \(shop.shop_name)")
                }
                .padding()
            }
            .navigationBarTitle(shop.shop_name, displayMode: .inline)
        }
    }
}

上記に記載のコードでは、if let を使用して、nilでないかチェックする処理をしています。

what is if let?

if letは、オプショナル型の値がnilでない場合にその値を取り出し、そのスコープ内で利用します。値がnilの場合、elseブロックが実行されます。

例:

if let someString = b {
    // 値があるときは、この処理を実行する
    print("Optional Value \(b)")
} else if b == nil {
    // 値がnilのときは、この処理を実行する
    print("b is nil")
} else {
    print("b has a value")
}

今回だと、値がnilでなければ、画像を表示することができます。表示に時間がかかるときは、ローディングが表示されます。画像がなかったら仮のイメージを表示します。

まとめ

今回は、AsyncImageを使ってハマったエラーについて記事を書きました。Stringの値を渡すだけと思いきやまさか、nilでないかチェックが必要なんですね。Dartでもnullでないかチェックしてますが......

Discussion