Open1
SwiftUI: Same-type requirement makes generic parameter '...' non-generic;の件
と出て、コンパイルできないことがあります。
今回詰まったのは.resizable
をカスタムモディファイアで使用しようとしたときでした。
struct DynamicTypeIconSizeModifier<IconT> : ViewModifier where IconT: View {
@Environment(\.dynamicTypeSize) var dynamicTypeSize
func body(content: Content) -> some View {
let size = self.imageSize
content
.resizable() // ←エラーになる
.frame(width: size, height: size)
}
var imageSize: CGFloat {
//略
}
}
そもそも.resizable
はView
ではなくてImage
にしか適用できないと分かりました[1]。
それでwhere IconT : Image
と書くと冒頭のメッセージが出ます。
メッセージとしてはImage
は具体的な型だから、これじゃノンジェネリックになっちゃうよね?というような感じだと思います。
View
はプロトコルなので具体的な型は分からずジェネリックで良いのですが、Image
はstruct
なのでwhere IconT : Image
と書いたらもうIconT
は必ずImage
となってしまいます。
このため、extension View
ではなく、extension Image
で書くべき、ということになります。
struct DynamicTypeIconSizeModifier<IconT> : ViewModifier where IconT: View {
@Environment(\.dynamicTypeSize) var dynamicTypeSize
func body(content: Content) -> some View {
let size = self.imageSize
content
//.resizable() // ←やめる
.frame(width: size, height: size)
}
var imageSize: CGFloat {
//略
}
}
extension Image {
func dynamicTypeIconSize() -> some View {
self
.resizable()
.modifier(DynamicTypeIconSizeModifier<Image>())
}
}
ちなみに上記の例では、.resizable()
も.frame()
も、両方extension Image
内の1つの関数でやってしまえば良さそうなものですが、extension
ではメンバ変数が持てないため、上記のように分けるしかないです。
-
よくよく調べると
.resizable
自身もモディファイアではなくてImage
のメソッドでした。 ↩︎