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

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

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

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

Swift

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

Q&A

解決済

2回答

1004閲覧

テキスト文字列をモデルに保存して、VCの関数から参照したい。

kazuki_user

総合スコア147

iOS

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

Swift

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

0グッド

1クリップ

投稿2020/09/12 00:36

編集2020/09/14 21:26

## お願い

本問は解決致しましたので、
こちらに質問を移動しました。

## やりたいこと

テキスト文字列をConstants.swift(モデル)に保存して、
ProfileDetailVCsetupUI()から参照したい。

## エラー

// Constants.swift Cannot assign to property: 'selectedUser' is immutable

Constants.swiftのプロパティ辺りでエラー。
複数のファイル間に共通する変数(?) の swift基礎文法が欠けているのかな..と思います。

この機会に学びたいので、本問題において 具体的にどの知識が欠けているのか、
差し支えなければ ご指摘お願いします。????‍♀️

## コード

swift

1// Constants.swift 2 3import UIKit 4 5let githubBaseUrl = "https://api.github.com/search/repositories?q=" 6 7var selectedUser: SearchRootVC! 8// 以下でエラー 9let repo = selectedUser.repo[selectedUser.RepoToPass] // Cannot assign to property: 'selectedUser' is immutable 10 11 12struct Segues { 13 static let toProfileDetail = "Detail" 14} 15 16struct Identifiers { 17 static let repositoryCell = "Repository" 18} 19 20struct ApiKey { 21 static let language = "language" 22 static let stars = "stargazers_count" 23 static let watchers = "wachers_count" 24 static let forks = "forks_count" 25 static let issues = "open_issues_count" 26 static let userName = "full_name" 27 static let user = "owner" 28 static let imgUrl = "avatar_url" 29} 30 31struct repoTxt { 32 static let title = repo[ApiKey.userName] as? String 33 34 static let language = "Written in (repo["language"] as? String ?? "")" 35 static let stars = "(repo["stargazers_count"] as? Int ?? 0) stars" 36 static let watchers = "(repo["wachers_count"] as? Int ?? 0) watchers" 37 static let forks = "(repo["forks_count"] as? Int ?? 0) forks" 38 static let issues = "(repo["open_issues_count"] as? Int ?? 0) open issues" 39}

swift

1// ProfileDetailVC 2 3import UIKit 4 5class ProfileDetailVC: UIViewController { 6 7 @IBOutlet weak var ImgView: UIImageView! 8 9 @IBOutlet weak var TitleLbl: UILabel! 10 11 @IBOutlet weak var LanguageLbl: UILabel! 12 13 @IBOutlet weak var StarsLbl: UILabel! 14 @IBOutlet weak var WatchersLbl: UILabel! 15 @IBOutlet weak var ForksLbl: UILabel! 16 @IBOutlet weak var IssuesLbl: UILabel! 17 18 // Var 19 var selectedUser: SearchRootVC! 20 21 override func viewDidLoad() { 22 super.viewDidLoad() 23 setupUI() 24 getProfileImage() 25 } 26 27 28 func setupUI() { 29 TitleLbl.text = repoTxt.title 30 31 LanguageLbl.text = repoTxt.language 32 StarsLbl.text = repoTxt.stars 33 WatchersLbl.text = repoTxt.watchers 34 ForksLbl.text = repoTxt.forks 35 IssuesLbl.text = repoTxt.issues 36 } 37 38 func getProfileImage() { 39 // 以下、省略。
// SearchRootVC import UIKit class SearchRootVC: UITableViewController, UISearchBarDelegate { @IBOutlet weak var searchBar: UISearchBar! var repoToPass: Int! var task: URLSessionTask? var repo: [[String: Any]] = [] override func viewDidLoad() { super.viewDidLoad() setupTableView() tableViewBgImage() } // 以下3つ、元から用意されているsearchBar関数名なので、変更NG。 func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool { searchBar.text = "" searchBar.autocapitalizationType = .none // 検索時、先頭を小文字で始める return true } func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { task?.cancel() } func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { // キーボード非表示 searchBar.resignFirstResponder() // MARK: - 不用意なIUOを削除。 // let query = searchBar.text! guard let query = searchBar.text, query.isEmpty == false else { print("検索文字がない") return } // word, completion, errorHandler 3つの引数をメソッドに渡す。 task = SearchAPI.getRandomRepoUrlSession(query, completionHandler: { items in self.repo = items // DispatchQueue で一つ以上のタスクを管理し、async で複数のAPIの非同期通信を実行。 DispatchQueue.main.async { // UIを更新する処理 self.tableView.reloadData() } }, errorHandler: { error in debugPrint(error?.localizedDescription ?? "") }) } func setupTableView() { // UISearchBarのdelegateプロパティに、self(=SearchRootVC)を代入。 searchBar.delegate = self } // MARK: - TableView で背景画像を表示。 func tableViewBgImage() { let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: self.tableView.frame.width, height: self.tableView.frame.height)) let image = UIImage(named: "bg_right1") imageView.image = image imageView.alpha = 0.8 self.tableView.backgroundView = imageView } // MARK: - // Segueが実行される前に呼び出される。 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { // Segueの識別子確認 if segue.identifier == Segues.toProfileDetail { // 遷移先ViewCntrollerの取得 if let detailVC = segue.destination as? ProfileDetailVC { // 値の設定 detailVC.selectedUser = self } } } } // extension extension SearchRootVC { override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return repo.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { // dequeueReusableCellで、セルを再利用。 // nilを返さない為、オプショナルバインディングは不要。 // MARK: - セルの再利用 let cell = tableView.dequeueReusableCell(withIdentifier: "RepositoryCell", for: indexPath) let userRepo = repo[indexPath.row] // MARK: - nil回避しつつ、nilの場合は「None」を表示。 if let userName = userRepo[ApiKey.userName] as? String { cell.textLabel?.text = userName } else { cell.textLabel?.text = "--None--" } // カスタムクラスの参照を修正。(-> detailTextLabelの表示) if let language = userRepo[ApiKey.language] as? String { cell.detailTextLabel?.text = language } else { cell.detailTextLabel?.text = "--None--" } return cell } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { repoToPass = indexPath.row performSegue(withIdentifier: Segues.toProfileDetail, sender: self) } } // MARK: - Cellの備忘録 // register() ... 用意したviewをcellのテンプレートとして登録するメソッドであり、cellの再利用に必要。 // Right Detail を表示は、コード不可 StoryBoard可なので、register()は使用しない。 // MARK: - クラスメソッドとして定義 class SearchAPI { // staticとして宣言すると、クラスのインスタンス化が不要。 static func getRandomRepoUrlSession(_ query: String, completionHandler completion: @escaping ([[String: Any]]) -> (), errorHandler: @escaping (Error?) -> ()) -> URLSessionTask? { // MARK: - 下記の部分はメソッドに渡す前に処理しておく // let word = searchBar.text! // guard let word = searchBar.text, word.isEmpty == false else { // print("検索文字がない") // return // } let repositoryUrl = githubBaseUrl + query guard let url = URL(string: repositoryUrl) else { return nil } let task = URLSession.shared.dataTask(with: url) { (data, responce, error) in guard error == nil else { // MARK: - 処理をクロージャに任せる errorHandler(error) return } guard let data = data else { return } // try!は、例外が発生したときにはクラッシュするので修正。(-> エラーが起こり得ないケースでのみ使用可) // try?で例外を安全に無視できるが、エラーを表示するため do-catch を使用。 do { let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] if let items = json?["items"] as? [[String: Any]] { // MARK: - 処理をクロージャに任せる completion(items) // MARK: - 以下の処理はクロージャに任せる // self.repo = items // // DispatchQueue で一つ以上のタスクを管理し、async で複数のAPIの非同期通信を実行。 // DispatchQueue.main.async { // // UIを更新する処理 // self.tableView.reloadData() // } } } catch { // MARK: - 処理をクロージャに任せる errorHandler(error) } } task.resume() return task } }

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

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

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

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

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

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

unhappychoice

2020/09/12 03:19

省略せずに Constants.swift VC のコードを全文掲載をお願いしますmm
kazuki_user

2020/09/12 03:34

追記致しました。????‍♂️
TsukubaDepot

2020/09/12 03:39

あるいは、Cannot assign to property: 'selectedUser' is immutable というエラーが出るような、最低限(できれば Playground で実行できるレベル)のコードを提示してもらうことはできますでしょうか。 仮に定義は間違っていなくとも、その使い方が間違っていればエラーがおきますので、それを確認できるレベルでコードを示していただいた方が有意義な議論ができるかと思います。 あと、 > (structを使用しているので、「値渡し」?というものでしょうか????) とありますが、struct と値渡しは全く関係ありません。 新たにインスタンス化した構造体やクラスのプロパティに対し、値を代入している操作を便宜的に「値渡し」と呼んでいるだけであり、構造体だけに特化した話ではありませんし、特別な操作でもありません。 Udemy の英語講座を受けていらっしゃったかと思いますが、おそらく pass variables to other properties of the class (or struct) みたいなタイトルで言及されていると思いますし、View Controller 間の値渡しであれば「pass variable to next view controller」というキーワードでも参考記事は見つかるかと思います。
TsukubaDepot

2020/09/12 03:51

あと、SearchRootVCのコードも追記いただけないでしょうか。 細かい点はともかく、上記のコードを真似して作ってみても、コンパイルは通ってしまいます。そうなると、SearchRootVC の方と関連する可能性も否めません。 あと、「selectedUserがnilで、Unexpectedly found nilエラー」というご質問で、Implicitly Unwrapped Optinal Value の扱いについて指摘いたしましたが、その対策は取られているのでしょうか。 今回のコードにも改善された形跡がないため、仮に今回のエラーが解決しても、次は実行時エラーが出てしまうことは明白です。 https://teratail.com/questions/290812
kazuki_user

2020/09/12 04:08 編集

> 今回のコードにも改善された形跡がないため、 ..。見直してみます。 var selectedUser: SearchRootVC! のことでしょうか? SearchRootVCに関しては、コードを追記しました。
TsukubaDepot

2020/09/12 04:11

はい、 var selectedUser: SearchRootVC! この部分です。 これだと、selectedUser は nil のままなので(かつ、nil のまま操作することを許されていないプロパティなので)、結局はselectedUser.repo[selectedUser.RepoToPass]を実行しようとした時点でエラーとなってしまいます。
kazuki_user

2020/09/12 11:52

オプショナル型の変数を宣言する際に付ける「!」と、 強制的アンラップの 「! 」とを混同していました。 オプショナル型の基礎については学びましたが、 クラスのデータ型を持つ変数の参照する際に、別のエラーが発生してしまい、 テキストデータのモデル格納が未解決なので、それに関しては別の質問として投稿させて頂きます。
guest

回答2

0

自己解決

オプショナル型の変数を宣言する際に付ける「!」と、 強制的アンラップの 「!」とを混同していました。

使用するとき必ず強制的アンラップを行い、(= 自動でアンラップをしてくれる)
nilでアンラップするとアプリが落ちるため、絶対に値がある(= nilでない) 場合のみ使用可能なImplicitly Unwrapped Optionalの基礎についてはしっかりと学んだつもりですが、

未だ別のエラーが発生してしまい、テキストデータのモデル格納が未解決なので、
それに関しては別の質問として投稿させて頂きます。

投稿2020/09/12 11:56

編集2020/09/12 11:58
kazuki_user

総合スコア147

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

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

0

Swift

1let repo = selectedUser.repo[selectedUser.RepoToPass] // Cannot assign to property: 'selectedUser' is immutable

上記のエラーが出る理由は単純な理由です。

Swift

1class SearchRootVC: UITableViewController, UISearchBarDelegate { 2 3 var repoToPass: Int!

SearchRootVC で定義されている repoToPass は小文字始まりです。
なので、selectedUser.repoToPassと変更すればコンパイルは通るのではないでしょうか。

しかし、次は実行時エラー(Unexpectedly found nil while implicitly unwrapping an Optional value)になるかと思います。

これを解決しようとするには、(おそらく以前も指摘しましたが)SearchRootVC のインスタンスを作ることになりなりますが、そもそも SearchRootVC というクラスはこういう流れでインスタンス化するように意図されていませんので、様々なところで不都合が起きてくると思います。

投稿2020/09/12 04:09

TsukubaDepot

総合スコア5086

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問