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

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

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

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Swift

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

Q&A

解決済

1回答

549閲覧

structの中の関数を参照したいです【Swift】

kazuki_user

総合スコア147

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Swift

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

0グッド

0クリップ

投稿2020/09/15 08:06

編集2020/09/15 08:13

## やりたいこと

structの中のfuncの中のインスタンスを参照したいです!
早急なご返信をお待ちしております...!????‍♂️????‍♂️

初歩的な質問ですが、しっかりと学ぶ所存ですのでご返答頂けますと幸いです。

## エラー

swift

1Type 'RepoTxt' has no member 'title'

## コード

func setupUI() { TitleLbl.text = RepoTxt.title // Type 'RepoTxt' has no member 'title' LanguageLbl.text = RepoTxt.language // Type 'RepoTxt' has no member 'title' StarsLbl.text = RepoTxt.stars // Type 'RepoTxt' has no member 'title' WatchersLbl.text = RepoTxt.watchers // Type 'RepoTxt' has no member 'title' ForksLbl.text = RepoTxt.forks // Type 'RepoTxt' has no member 'title' IssuesLbl.text = RepoTxt.issues // Type 'RepoTxt' has no member 'title' }

swift

1var selectedUser: SearchRootVC? 2 3... 4 5struct RepoTxt { 6 7 func repoTxt() { 8 guard let selectedUser = selectedUser else { return } 9 let repo = selectedUser.repo[selectedUser.repoToPass] 10 11 let title = repo[ApiKey.userName] as? String 12 13 let language = "Written in (repo["language"] as? String ?? "")" 14 let stars = "(repo["stargazers_count"] as? Int ?? 0) stars⭐️" 15 let watchers = "(repo["wachers_count"] as? Int ?? 0) watchers????" 16 let forks = "(repo["forks_count"] as? Int ?? 0) forks????" 17 let issues = "(repo["open_issues_count"] as? Int ?? 0) open issues????" 18 } 19 20} 21 22

質問は以上です。
お時間あるときに、ご返信頂けましたら幸いです????

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

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

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

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

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

guest

回答1

0

ベストアンサー

今回の場合、アプローチから見直した方が良いのかなと思います。

struct (RepoTxt) の中の func (repoTxt) 中の インスタンス` (selectedUser, repo, title, language, stars, watchers, forks, issues) は、仕様上、参照できません。

これは「スコープ」という、変数の生存範囲の約束事で、スコープは基本的に内側から外側のものは参照できるけれど、外側から内側のものは一般に参照できないような仕組みになっています。

この「スコープ」という仕組みは、変数を参照できる範囲を必要以上に広げないことで、バグを生みにくいコードをプログラマーが少ない労力で書ける手助けをしてくれています。


そうなると、struct (RepoTxt) の設計を見直す必要があると思うのですけれど、通常であれば各変数を RepoTxt の「インスタンスプロパティー(メンバープロパティー)」として持たせてイニシャライザーなどで状態を整えることになるのが一般的と思うのですけれど、setupUI のコードを見るとこちらでは RepoTxt で各変数が「スタティックプロパティー(静的プロパティー)」として提供されていることが前提のコードになっています。

そうすると、静的プロパティーを使ったアプローチで改修していくのが近道なのかなとも思うのですけれど、そうしたときに「計算型プロパティー」を使えば上手くいくとは思うのですけど、少し冗長で無意味なコードになりそうな気もします。

そこまで書いて思うこととして、そもそも、データの扱い方を知っていると思う RepoTxt の役割は repo["language"] as? String をすることまでで、"Written in" とか "stars⭐️" みたいな情報は UI がどういったものかを知っていると思う setupUI 側で行う処理のような気もしてきます。

そう思うと、表示文字の整形を struct (RepoTxt) に切り出さずに setupUI の中に埋め込んでも良いような気がしますし、もう少しデータを扱いやすくしたいのだったら RepoTxt よりは、selectedUser.repo[selectedUser.repoToPass] のデータをラップして扱いやすくするクラス(名称は例えば Repo など)を設計してみるのが良いように思も感じます。


いずれにしても、内側の変数にアクセスするというアプローチでは上手くいかないと思うので、全体を見渡して、アプローチを再検討してみるのが良さそうに思います。

見通しが立たないようでしたらとりあえず、今回挙げてくださった処理コードを setupUI 内だけで実装してみると良いかもしれません。

今回の場合はそれだけでも完成としても良い気がしますし、正常に動くコードが書けてから、少しずつ切り出せるコードを見つけて struct などに切り出していくと、今よりも良さそうなアプローチが思いつくかもしれません。

投稿2020/09/15 15:36

TomohiroKumagai

総合スコア441

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

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

kazuki_user

2020/09/15 21:26 編集

ご返信ありがとうございます????‍♂️ では今回はsetupUI 内だけでの実装を検討してみます。 > selectedUser.repo[selectedUser.repoToPass] のデータをラップして扱いやすくするクラスを設計 guard let selectedUser = selectedUser else { return } let repo = selectedUser.repo[selectedUser.repoToPass] を同ファイル内のクラスメソッド等に切り出すという事でしょうか?? guard let は関数内でしか使えなかったり、この2行は同じスコープ内でしか使えなかったり、 色々と制限がありどのようにすれば良いのか分からないのですが、 教えて下さいませんか?????‍♂️
TomohiroKumagai

2020/09/16 11:01

クラスメソッドに切り出すアプローチもありますし、インスタンスメソッド(普通のメソッド)に切り出すアプローチでも良さそうです。 そう、ご指摘の `guard let` 周りが、クラスメソッドだとどうしていくか難しいところなのですよね。 クラスメソッドを使う場合、少し冗長になりますけれど、計算型プロパティーと「オプショナルチェイニング」を使って変数ごとに `selectedUser` から取り出すみたいな書き方になりそうに感じます。たとえば `starz` でしたら次のようだとどうでしょう。`repo` をラップする `Repo` クラスでは値を取り出すことに専念して、文字列の整形や guard 相応の処理は `setupUI` の中かそれを呼び出すところで行うことを想定します。 ``` class Repo { class var stars: String? { get { return selectedUser?.repo[selectedUser.repoToPass]?["stargazers_count"] as? Int ?? 0 } } } ``` このようにすると `Repo.stars` でスターの数が Int? 型で得られるので、`setupUI` では `StarsLbl.text = "(Repo.stars ?? 0) stars⭐️"` のようにして UI に合ったテキストに整形します。
kazuki_user

2020/09/16 12:34

ご返答ありがとうございます。 とても勉強になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問