## やりたいこと
SearchRootVCクラスにて、URLSessionのコードをRepositoryApiクラスから呼び出したい。
SearchRootVC
1 var repositoryApi = RepositoryApi() 2 3... 4 5 func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { 6 repositoryApi.getRandomRepoUrlSession() 7 }
RepositoryApi
1 2// URLSessionの処理
## selfが原因の、EXC_BAD_ACCESSが出る
EXC_BAD_ACCESSエラーにて、
self = CodeCheck_Test_Yumemi.SearchRootVC   0x00007ff8c083db00だと エラー原因が特定出来たので、
下記を記述してselfの使用を避けようとしましたが、引き続きEXC_BAD_ACCESSでクラッシュします...
RepositoryApi
1var searchRootVC = SearchRootVC()
## URLSessionコード
なお、呼び出しをせずにSearchRootVCのみで実行すると
EXC_BAD_ACCESSは無く、正常に動作します。
RepositoryApi
1import UIKit 2 3class RepositoryApi: SearchRootVC { 4 5 var searchRootVC = SearchRootVC() 6 7 8 func getRandomRepoUrlSession() { 9 10 let word = searchBar.text! 11 let REPOSITORY_URL = URL_BASE + "(word)" 12 13 // nilは許さない。urlの強制アンラップを修正。 14 guard let url = URL(string: REPOSITORY_URL) else { return } 15 16 let task = URLSession.shared.dataTask(with: url) { (data, responce, error) in 17 18 guard error == nil else { 19 debugPrint(error.debugDescription) 20 return 21 } 22 23 // dataの強制アンラップを修正。 24 guard let data = data else { return } 25 26 // try!は、例外が発生したときにはクラッシュするので修正。(-> エラーが起こり得ないケースでのみ使用可) 27 // try?で例外を安全に無視できるが、エラーを表示するため do-catch を使用。 28 29 do { 30 let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] 31 if let items = json?["items"] as? [[String: Any]] { 32 self.searchRootVC.repo = items 33 // DispatchQueue で一つ以上のタスクを管理し、async で複数のAPIの非同期通信を実行。 34 DispatchQueue.main.async { 35 // UIを更新する処理 36 self.searchRootVC.tableView.reloadData() 37 } 38 } 39 } catch { 40 debugPrint(error.localizedDescription) 41 return 42 } 43 } 44 // 新しく初期化されたタスクは一時停止状態で開始されるため、このメソッドを呼び出してタスクを開始する必要がある。 45 task.resume() 46 } 47 48} 49 50
SearchRootVC全文
SearchRootVC
1import UIKit 2 3class SearchRootVC: UITableViewController, UISearchBarDelegate { 4 5 @IBOutlet weak var searchBar: UISearchBar! 6 7 // Var 8 var word: String! 9 var url: String! 10 var RepoToPass: Int! 11 12 var task: URLSessionTask? 13 var repo: [[String: Any]]=[] 14 15 var repositoryApi = RepositoryApi() 16 17 override func viewDidLoad() { 18 super.viewDidLoad() 19 setupTableView() 20 } 21 22 // 以下3つ、元から用意されているsearchBar関数名なので、変更NG。 23 func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool { 24 searchBar.text = "" 25 return true 26 } 27 28 func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { 29 task?.cancel() 30 } 31 32 func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { 33 repositoryApi.getRandomRepoUrlSession() 34 } 35 36 func setupTableView() { 37 // UISearchBarのdelegateプロパティに、self(=SearchRootVC)を代入。 38 searchBar.delegate = self 39 } 40 41 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 42 if segue.identifier == Segues.ToProfileDetail { 43 if let detailVC = segue.destination as? ProfileDetailVC { 44 detailVC.selectedUser = self 45 } 46 } 47 } 48} 49 50 51// extension 52 53extension SearchRootVC { 54 55 override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 56 return repo.count 57 } 58 59 override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 60 61 // dequeueReusableCellで、セルを再利用。 62 // nilを返さない為、オプショナルバインディングは不要。 63 64 let cell: RepositoryCell = tableView.dequeueReusableCell(withIdentifier: Identifiers.RepositoryCell, for: indexPath) as! RepositoryCell 65 let UserRepo = repo[indexPath.row] 66 cell.configureCell(UserRepo) 67 cell.tag = indexPath.row 68 return cell 69 } 70 71 override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 72 RepoToPass = indexPath.row 73 performSegue(withIdentifier: Segues.ToProfileDetail, sender: self) 74 } 75} 76
質問は以上です。
お時間あるときに、ご返信頂けましたら幸いです????
RepositoryApi は、SearchRootVCにかなり依存しているようなので、SearchRootVC が何者かわからないと回答できないと思います。
ご自身で作られたクラスであれば、依存関係はおわかりだと思うので、もう少し整理できるかと思いますが、そうでないならば、まずは依存関係を整理されたらいかがでしょうか。
質問の変更履歴ですが、適当なタイトル「あ、とかaとか」にせず、適切なタイトルをつけることはできないのでしょうか。
改変履歴は誰でも参照できますが、適当なタイトルだと何が変わったのかひと目ではわからないため大変困ります。
ちなみに、RepositoryApiのベースクラス(継承元)が SearchRootVC なのは、どういう意図からなのでしょうか。
申し訳ありませんでした。変更タイトルに関して以後、気を付けます。????♂️
質問に添った回答か分かりませんが..
現在、コードに対してリファクタリングを行っており、
SearchRootVCにて、レポジトリ検索画面の主な機能(searchBarShouldBeginEditingなど) を実装しております。
URLSessionを他のファイルに分割する為、RepositoryApiを新たに作りURLSessionを記述し、
それをSearchRootVCから呼び出したいと考えています。
クラスの継承、という考え方は理解されていますでしょうか。
また、個別のクラス間におけるプロパティ参照の理屈についても理解されていますでしょうか。
: で継承し、親の機能を参照できる..という認識です。
個別のクラス間におけるプロパティ参照に関しては、少し自信がないかもです..
今回のエラーは、self含め、これらが原因でしょうか?
selectedUserがnilで、Unexpectedly found nilエラーに関してもそうですが、
別ファイル間の行き来の問題でエラーが起こっているように思われます????
繰り返しになりますが、文法全般の理解が不足していることが原因かと思います。
また、不用意にクラスを継承させたことが原因で、見えなくてもいい変数が見えてしまい、それがかえって混乱を招いている雰囲気があります。
また、型や定数などの名付け方もSwiftの流儀に沿っていないところがあるので読みにくいところがあります。
リファクタリングは重要なことかと思いますが、どこまでを一般化するのか整理しないと、かえって使いづらくなるのではないでしょうか。
たとえば、RepositoryApiから親クラスの tableView などが見えていますが、見えているからといって具体的なインスタンス(値)が入っているわけではありません。プロパティやメソッドは経由しますが、プロパティに対して動的に代入される値までは継承されません。
なので、そのあたりをきちんと考えてリファクタリングする必要があります。
ちなみに、このアプリはどこのWebAPIを検索して(つまり、URL_BASEはどんなURLにアクセスして)結果を表示しようとしたのでしょうか。
https://api.github.com/search/repositories?q=\(word!)
GitHubAPIです。
(word = searchBar.text!)
URLSessionがSearchRootVCにあると、煩雑かなと思ったのですが、どうなのでしょうか..?
回答1件
あなたの回答
tips
プレビュー