teratail header banner
teratail header banner
質問するログイン新規登録

質問編集履歴

6

誤字

2020/09/14 21:26

投稿

kazuki_user
kazuki_user

スコア147

title CHANGED
File without changes
body CHANGED
@@ -1,5 +1,6 @@
1
1
  ## お願い
2
2
 
3
+ 本問は解決致しましたので、
3
4
  [**こちら**](https://teratail.com/questions/291397)に質問を移動しました。
4
5
 
5
6
 

5

誤字

2020/09/14 21:26

投稿

kazuki_user
kazuki_user

スコア147

title CHANGED
File without changes
body CHANGED
@@ -1,3 +1,8 @@
1
+ ## お願い
2
+
3
+ [**こちら**](https://teratail.com/questions/291397)に質問を移動しました。
4
+
5
+
1
6
  ## やりたいこと
2
7
 
3
8
  テキスト文字列を`Constants.swift`(モデル)に保存して、

4

SearchRootVCの追記

2020/09/14 13:40

投稿

kazuki_user
kazuki_user

スコア147

title CHANGED
File without changes
body CHANGED
@@ -102,5 +102,189 @@
102
102
  // 以下、省略。
103
103
  ```
104
104
 
105
+ ```
106
+ // SearchRootVC
107
+
108
+ import UIKit
109
+
110
+ class SearchRootVC: UITableViewController, UISearchBarDelegate {
111
+
112
+ @IBOutlet weak var searchBar: UISearchBar!
113
+
114
+ var repoToPass: Int!
115
+
116
+ var task: URLSessionTask?
117
+ var repo: [[String: Any]] = []
118
+
119
+ override func viewDidLoad() {
120
+ super.viewDidLoad()
121
+ setupTableView()
122
+ tableViewBgImage()
123
+ }
124
+
125
+ // 以下3つ、元から用意されているsearchBar関数名なので、変更NG。
126
+ func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
127
+ searchBar.text = ""
128
+ searchBar.autocapitalizationType = .none // 検索時、先頭を小文字で始める
129
+ return true
130
+ }
131
+
132
+ func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
133
+ task?.cancel()
134
+ }
135
+
136
+ func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
137
+ // キーボード非表示
138
+ searchBar.resignFirstResponder()
139
+
140
+ // MARK: - 不用意なIUOを削除。
141
+ // let query = searchBar.text!
142
+ guard let query = searchBar.text, query.isEmpty == false else {
143
+ print("検索文字がない")
144
+ return
145
+ }
146
+
147
+ // word, completion, errorHandler 3つの引数をメソッドに渡す。
148
+ task = SearchAPI.getRandomRepoUrlSession(query, completionHandler: { items in
149
+ self.repo = items
150
+ // DispatchQueue で一つ以上のタスクを管理し、async で複数のAPIの非同期通信を実行。
151
+ DispatchQueue.main.async {
152
+ // UIを更新する処理
153
+ self.tableView.reloadData()
154
+ }
155
+ }, errorHandler: { error in
156
+ debugPrint(error?.localizedDescription ?? "")
157
+ })
158
+ }
159
+
160
+ func setupTableView() {
161
+ // UISearchBarのdelegateプロパティに、self(=SearchRootVC)を代入。
162
+ searchBar.delegate = self
163
+ }
164
+
165
+ // MARK: - TableView で背景画像を表示。
166
+ func tableViewBgImage() {
167
+ let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: self.tableView.frame.width, height: self.tableView.frame.height))
168
+ let image = UIImage(named: "bg_right1")
169
+
170
+ imageView.image = image
171
+ imageView.alpha = 0.8
172
+
173
+ self.tableView.backgroundView = imageView
174
+ }
175
+
176
+ // MARK: - // Segueが実行される前に呼び出される。
177
+ override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
178
+ // Segueの識別子確認
179
+ if segue.identifier == Segues.toProfileDetail {
180
+ // 遷移先ViewCntrollerの取得
181
+ if let detailVC = segue.destination as? ProfileDetailVC {
182
+ // 値の設定
183
+ detailVC.selectedUser = self
184
+ }
185
+ }
186
+ }
187
+ }
188
+
189
+
190
+ // extension
191
+
192
+ extension SearchRootVC {
193
+
194
+ override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
195
+ return repo.count
196
+ }
197
+
198
+ override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
199
+
200
+ // dequeueReusableCellで、セルを再利用。
201
+ // nilを返さない為、オプショナルバインディングは不要。
202
+
203
+ // MARK: - セルの再利用
204
+ let cell = tableView.dequeueReusableCell(withIdentifier: "RepositoryCell", for: indexPath)
205
+
206
+ let userRepo = repo[indexPath.row]
207
+
208
+ // MARK: - nil回避しつつ、nilの場合は「None」を表示。
209
+ if let userName = userRepo[ApiKey.userName] as? String {
210
+ cell.textLabel?.text = userName
211
+ } else {
212
+ cell.textLabel?.text = "--None--"
213
+ }
214
+ // カスタムクラスの参照を修正。(-> detailTextLabelの表示)
215
+ if let language = userRepo[ApiKey.language] as? String {
216
+ cell.detailTextLabel?.text = language
217
+ } else {
218
+ cell.detailTextLabel?.text = "--None--"
219
+ }
220
+
221
+ return cell
222
+ }
223
+
224
+ override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
225
+ repoToPass = indexPath.row
226
+ performSegue(withIdentifier: Segues.toProfileDetail, sender: self)
227
+ }
228
+ }
229
+
230
+ // MARK: - Cellの備忘録
231
+ // register() ... 用意したviewをcellのテンプレートとして登録するメソッドであり、cellの再利用に必要。
232
+ // Right Detail を表示は、コード不可 StoryBoard可なので、register()は使用しない。
233
+
234
+ // MARK: - クラスメソッドとして定義
235
+
236
+ class SearchAPI {
237
+ // staticとして宣言すると、クラスのインスタンス化が不要。
238
+ static func getRandomRepoUrlSession(_ query: String, completionHandler completion: @escaping ([[String: Any]]) -> (), errorHandler: @escaping (Error?) -> ()) -> URLSessionTask? {
239
+
240
+ // MARK: - 下記の部分はメソッドに渡す前に処理しておく
241
+ // let word = searchBar.text!
242
+ // guard let word = searchBar.text, word.isEmpty == false else {
243
+ // print("検索文字がない")
244
+ // return
245
+ // }
246
+
247
+ let repositoryUrl = githubBaseUrl + query
248
+
249
+ guard let url = URL(string: repositoryUrl) else { return nil }
250
+
251
+ let task = URLSession.shared.dataTask(with: url) { (data, responce, error) in
252
+
253
+ guard error == nil else {
254
+ // MARK: - 処理をクロージャに任せる
255
+ errorHandler(error)
256
+ return
257
+ }
258
+
259
+ guard let data = data else { return }
260
+
261
+ // try!は、例外が発生したときにはクラッシュするので修正。(-> エラーが起こり得ないケースでのみ使用可)
262
+ // try?で例外を安全に無視できるが、エラーを表示するため do-catch を使用。
263
+
264
+ do {
265
+ let json = try JSONSerialization.jsonObject(with: data) as? [String: Any]
266
+ if let items = json?["items"] as? [[String: Any]] {
267
+ // MARK: - 処理をクロージャに任せる
268
+ completion(items)
269
+ // MARK: - 以下の処理はクロージャに任せる
270
+ // self.repo = items
271
+ // // DispatchQueue で一つ以上のタスクを管理し、async で複数のAPIの非同期通信を実行。
272
+ // DispatchQueue.main.async {
273
+ // // UIを更新する処理
274
+ // self.tableView.reloadData()
275
+ // }
276
+ }
277
+ } catch {
278
+ // MARK: - 処理をクロージャに任せる
279
+ errorHandler(error)
280
+ }
281
+ }
282
+ task.resume()
283
+
284
+ return task
285
+ }
286
+ }
287
+ ```
288
+
105
289
  質問は以上です。
106
290
  お時間あるときに、ご返信頂けましたら幸いです????

3

書式の改善。

2020/09/12 03:55

投稿

kazuki_user
kazuki_user

スコア147

title CHANGED
File without changes
body CHANGED
@@ -3,8 +3,6 @@
3
3
  テキスト文字列を`Constants.swift`(モデル)に保存して、
4
4
  `ProfileDetailVC`の`setupUI()`から参照したい。
5
5
 
6
- (`struct`を使用しているので、「値渡し」?というものでしょうか????)
7
-
8
6
  ## エラー
9
7
 
10
8
  ```

2

誤字

2020/09/12 03:45

投稿

kazuki_user
kazuki_user

スコア147

title CHANGED
File without changes
body CHANGED
@@ -28,10 +28,9 @@
28
28
  let githubBaseUrl = "https://api.github.com/search/repositories?q="
29
29
 
30
30
  var selectedUser: SearchRootVC!
31
+ // 以下でエラー
31
- let repo = selectedUser.repo[selectedUser.RepoToPass]
32
+ let repo = selectedUser.repo[selectedUser.RepoToPass] // Cannot assign to property: 'selectedUser' is immutable
32
33
 
33
- // static var(let)
34
- //「静的変数」...全てのプログラムが終了するまで、一貫してその値を保持し続ける変数。 初期化は1度のみ。
35
34
 
36
35
  struct Segues {
37
36
  static let toProfileDetail = "Detail"

1

追記

2020/09/12 03:35

投稿

kazuki_user
kazuki_user

スコア147

title CHANGED
File without changes
body CHANGED
@@ -23,15 +23,38 @@
23
23
  ```swift
24
24
  // Constants.swift
25
25
 
26
+ import UIKit
27
+
28
+ let githubBaseUrl = "https://api.github.com/search/repositories?q="
29
+
26
30
  var selectedUser: SearchRootVC!
27
- // 以下、エラー。
28
- let repo = selectedUser.repo[selectedUser.RepoToPass] // Cannot assign to property: 'selectedUser' is immutable
31
+ let repo = selectedUser.repo[selectedUser.RepoToPass]
29
32
 
30
- ...
33
+ // static var(let)
34
+ //「静的変数」...全てのプログラムが終了するまで、一貫してその値を保持し続ける変数。 初期化は1度のみ。
31
35
 
36
+ struct Segues {
37
+ static let toProfileDetail = "Detail"
38
+ }
39
+
40
+ struct Identifiers {
41
+ static let repositoryCell = "Repository"
42
+ }
43
+
44
+ struct ApiKey {
45
+ static let language = "language"
46
+ static let stars = "stargazers_count"
47
+ static let watchers = "wachers_count"
48
+ static let forks = "forks_count"
49
+ static let issues = "open_issues_count"
50
+ static let userName = "full_name"
51
+ static let user = "owner"
52
+ static let imgUrl = "avatar_url"
53
+ }
54
+
32
55
  struct repoTxt {
33
56
  static let title = repo[ApiKey.userName] as? String
34
-
57
+
35
58
  static let language = "Written in (repo["language"] as? String ?? "")"
36
59
  static let stars = "(repo["stargazers_count"] as? Int ?? 0) stars"
37
60
  static let watchers = "(repo["wachers_count"] as? Int ?? 0) watchers"