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

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

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

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

解決済

Swiftのinstance member cannot be used on typeエラーについて

Ririka
Ririka

総合スコア14

Swift

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

1回答

0グッド

0クリップ

271閲覧

投稿2022/09/29 04:39

編集2022/09/30 01:06

UIViewにextensionする形でgetImage()という関数(UIImageの型でreturn)を定義しました。

関数の内容としてはViewを画像に変換する、というものです。

それを

struct ContentView: View { var body: some View { ScrollView([.horizontal, .vertical]){ VStack{ Image("SampleImage") .frame(width:1000, height: 800) .aspectRation(contentMode: .fit) .overlay(Text("文字")) } } .frame(maxWidth: .infinity, maxHeight: .infinity) let image1 = UIView.getImage() } }

という形で実行しようとすると

instance member 'getImage' cannot be used on type 'UIView';
did you mean to use a value of this type instead?

というエラーが発生してしまいます。

定義している関数そのものはネットの有識者の方のものを書き写させてもらい、関数自体にエラーは発生していません。

なので、おそらく私が初学者ゆえに実行そのもので何か間違っているのだと思うのですが、検索してもどうしてもわかりませんでした。

お知恵を貸していただけると幸いです。

以下のような質問にはグッドを送りましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

グッドが多くついた質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

Ririka

2022/09/29 05:57

hosi-takanori様 素早い回答ありがとうございます! 教えていただいたURLを拝見したところ、 クラス(struct)そのものを変数に代入=インスタンス化(クラスそのものを使えるようにする?) インスタンス化したものに対して関数を実行する という手順が必要と考え、 let image1 = UIView().GetImage() という形にし、黄色い警告が出てしまうので、var body: some View{}内にあったのを外に出しました。 この後、実行中に別のエラーが出てきてしまいましたがとりあえず今回質問させていただいた部分は上手くプログラムが走ったように感じています。 この認識でhoshi-takanori様に教えていただいたことを何となくでも理解できているでしょうか?
hoshi-takanori

2022/09/29 16:10

文法的にはそれでコンパイルできるようになるかも知れませんが、そもそもどのビューの、どんな内容を画像にしたいのでしょうか? let image1 = UIView().GetImage() ってことは、新規の UIView (内容は何もない) を生成して、それを画像にするってことになりますが…。 あと、余計なお世話ですが、Swift ではメソッド名は小文字で始めるのが一般的なので、GetImage じやなくて getImage の方が良いかと。
Ririka

2022/09/30 01:16

ご指摘感謝します! getImageに変更しました! また、メインの部分に関してまさにおっしゃる通りで「予想外のnilが出ました」というようなエラーを吐いている状態です。 本当に勉強不足でお恥ずかしい限りです。 本来は、ContentViewに表示されているImageとそこにoverlayされているTextをまとめて一つの画像にしたいと思っています。 いわゆる画像加工アプリに近いものを作りたいと思っているのですが、このContentViewでoverlayしているTextはあくまでView内で重なっているだけだと認識しており、一度UIViewをUIImageに変換する必要があると考え、試しています。 なので、初心者考えですとContentView内のImageの下でgetImage()を走らせて新しい変数に画像を入れておき、保存ボタンか何かでその変数(UIImage)を保存できる状態を作れば良いのではないかと考えていたのですが、そもそもの認識が間違っているようなので、お時間が許しましたら再度ご指摘くださるとうれしいです。

回答1

1

ベストアンサー

SwiftUIとUIKitは別物ですので、それらは区別して理解しておいた方が作業がスムーズになるかなと思いました。

View構造体は「SwiftUI」の構造体です。
https://developer.apple.com/documentation/swiftui/view
UIViewクラスは「UIKit」のクラスです。
https://developer.apple.com/documentation/uikit/uiview

質問欄のコードでは、UIViewクラスの拡張機能としてgetImage()メソッドを実装していると思います。
これを活用するとして、
ContentViewはView構造体ですので、View構造体をUIViewクラスに変換して、getImage()メソッドを呼び出してあげると良いのかなと思います。
*JPEGにするかPNGにするかなどは画像の性質によって変えてみてください
*サンプルではロングプレスのジェスチャーで保存するようにしていますが、要件に合わせて修正してみてください

swift

1import SwiftUI 2 3struct ContentView: View { 4 var body: some View { 5 ScrollView([.horizontal, .vertical]) { 6 VStack { 7 Image("SampleImage") 8 .frame(width: 1000, height: 800) 9 .aspectRatio(contentMode: .fit) 10 .overlay(Text("文字")) 11 } 12 } 13 .frame(maxWidth: .infinity, maxHeight: .infinity) 14 // ロングプレスのジェスチャーでViewを画像の形式で保存します。 15 .onLongPressGesture(perform: action) 16 } 17 func action() { 18 // (SwiftUIの)ViewをUIImageに変換します。 19 let image = self.getImage() 20 // UIImageをJPEGのデータに変換します。 21 let data = image.jpegData(compressionQuality: 0.5) 22 guard let data = data else { 23 return 24 } 25 // ドキュメントディレクトリの中にoutput.jpgのファイルを保存します。 26 let urlDocumentDirectory = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) 27 guard let urlDocumentDirectory = urlDocumentDirectory else { 28 return 29 } 30 let urlJpeg = urlDocumentDirectory.appendingPathComponent("output.jpg") 31 print(urlJpeg) 32 do { 33 try data.write(to: urlJpeg) 34 } catch { 35 fatalError() 36 } 37 } 38} 39 40extension View { 41 // (SwiftUIの)ViewをUIImageに変換するメソッドです。 42 func getImage() -> UIImage { 43 // (SwiftUI)のViewを(UIKitの)UIViewに変換します。 44 let controller = UIHostingController(rootView: self) 45 let view = controller.view! 46 // (UIKitの)UIViewをUIImageに変換します。 47 let image = view.getImage() 48 return image 49 } 50} 51 52// UIViewのextensionの定義は省略...

追記です。

UIViewのextensionの定義も追記します。

画像を長押し(クリックで長押し。これでonLongPressGestureの確認方法が合っているのか検索しましたがわかりませんでした。ただ、エラーを吐くのでコードは走っていると感じます)

この操作で大丈夫だと思います。


UIView extensionをどう書くべきなのか、

https://www.hackingwithswift.com/quick-start/swiftui/how-to-convert-a-swiftui-view-to-an-image

私はリンク先のコードを参考にしてみたのですが、
UIGraphicsGetCurrentContext()メソッドを使っていないためちょっと方法が違うのかもしれませんね。
*すでに実装しているgetImage()メソッドを使わないのであれば、リンク先のようにextension Viewの拡張機能だけ実装して、extension UIViewの実装は削除する感じでも良いのかもしれませんね。
*UIViewのextensionを実装するとしたら、ということで下にコードを記載しておきます。
*リンク先には写真アプリのアルバムに画像を保存するメソッドも記載されているため、そちらも見てみると良いかもしれませんね。

swift

1extension UIView { 2 func getImage() -> UIImage { 3 let targetSize = self.intrinsicContentSize 4 self.bounds = CGRect(origin: .zero, size: targetSize) 5 self.backgroundColor = .clear 6 let renderer = UIGraphicsImageRenderer(size: targetSize) 7 return renderer.image { _ in 8 self.drawHierarchy(in: self.bounds, afterScreenUpdates: true) 9 } 10 } 11}

ちょっと調整しないといけないと思うところですが、
手元の環境で出力された画像を見ると、
上に余白ができてしまっています・・
ちょっとそれを調べるところまでできていません・・

投稿2022/10/03 14:25

編集2022/10/04 05:03
退会済みユーザー

退会済みユーザー

総合スコア0

Ririka👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

Ririka

2022/10/04 03:53

xg63ex2b様 大変丁寧なご回答ありがとうございます! 根本的に理解ができていなかったViewとUIViewの違いから、コメントアウトでの解説までとてもわかりやすく、大変ためになりました! まだ、xg63ex2b様からいただいたコードを丸々書き写した段階ですが、一つずつ検索して理解を深めていきたいと思います。 そしてこんなにもご丁寧な回答をいただいた上で大変恐縮なのですが、実際にこのコードを実行してみたところ、画像を長押し(クリックで長押し。これでonLongPressGestureの確認方法が合っているのか検索しましたがわかりませんでした。ただ、エラーを吐くのでコードは走っていると感じます)したところ、UIViewのextension内にある let context: CGContext = UIGraphicsGetCurrentContext()! と言うコードで Thread1: Fatal error: Unexpectedly found nil while unwrapping an Optional value という中身が入っていない、というようなエラーが出てしまいました。 nilについて調べてはみたのですが、どうしても理解ができず、そして他者のコードのため丸写しして質問することもできず…。 本当におんぶにだっこで申し訳ないのですが、お時間がございましたらUIView extensionをどう書くべきなのか、ヒントか何かいただけますと幸いです。 よろしくお願いいたします。
Ririka

2022/10/06 08:46

本当に何から何までありがとうございました!! エラーを吐かなくなりました! まだ画像保存が上手くはいっていないのですが、いただいたコードを読み解きながら進めれば自分のミスに気づけると思うので、ここでベストアンサーにさせていただきます。 繰り返しになりますが本当に初歩的なミスに対しても、根本的に理解できていない部分の指摘からご丁寧に回答いただきありがとうございました! 本当に助かりました。 まだ実装できていませんが今回のコメントをいただけたことで一歩進めた気がします。 頑張ります!

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

ただいまの回答率
86.12%

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

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

質問する

関連した質問

同じタグがついた質問を見る

Swift

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