Swift初学者です。
こちらの記事を参考にソースコードのみ載っていたので、「スケジュールを日付別に時間順に並べる」ということができたのですが、所々コードを調べても分からない箇所があり完全な理解に至らず現在苦戦しております。
全体のコードが以下になります。
Swift4
1import UIKit 2 3struct Plan { 4 let name: String 5 let detail: String 6 let date: Date 7} 8 9class MyViewController : UIViewController { 10 11 var schedules = [Date: [Plan]]() 12 var dateOrder = [Date]() 13 14 private var formatter: DateFormatter { 15 let f = DateFormatter() 16 f.dateStyle = .long 17 f.timeStyle = .none 18 f.locale = Locale(identifier: "ja_JP") 19 return f 20 } 21 22 private var timeFormatter: DateFormatter { 23 let f = DateFormatter() 24 f.dateStyle = .none 25 f.timeStyle = .short 26 f.locale = Locale(identifier: "ja_JP") 27 return f 28 } 29 30 override func viewDidLoad() { 31 super.viewDidLoad() 32 33 prepare() 34 35 let tv = UITableView(frame: self.view.frame) 36 tv.dataSource = self 37 tv.delegate = self 38 view.addSubview(tv) 39 } 40 41 private func prepare() { 42 let f = DateFormatter() 43 f.locale = Locale(identifier: "en_US_POSIX") 44 f.dateFormat = "yyyy/MM/dd HH:mm" 45 46 let plans = [ 47 Plan(name: "休み", detail: "実家で過ごす", date: f.date(from: "2018/01/01 09:00")!), 48 Plan(name: "外出", detail: "初詣", date: f.date(from: "2018/01/03 10:00")!), 49 Plan(name: "仕事", detail: "社内会議", date: f.date(from: "2018/01/03 17:30")!), 50 Plan(name: "外出", detail: "買い出し", date: f.date(from: "2018/01/15 19:00")!), 51 Plan(name: "仕事", detail: "Team Meeting", date: f.date(from: "2018/01/15 15:30")!), 52 Plan(name: "休み", detail: "家族で水族館", date: f.date(from: "2018/01/17 08:00")!), 53 Plan(name: "休み", detail: "飲み会", date: f.date(from: "2018/01/17 20:00")!) 54 ] 55 56 schedules = Dictionary(grouping: plans) { plan -> Date in 57 f.dateFormat = "yyyy/MM/dd" 58 let s = f.string(from: plan.date) 59 return f.date(from: s)! 60 } 61 .reduce(into: [Date: [Plan]]()) { dic, tuple in 62 dic[tuple.key] = tuple.value.sorted { $0.date < $1.date } 63 } 64 65 // 日付順を保持するための配列 66 dateOrder = Array(schedules.keys).sorted { $0 < $1 } 67 } 68 69} 70 71extension MyViewController: UITableViewDataSource { 72 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 73 let targetDate = dateOrder[section] 74 return schedules[targetDate, default: []].count 75 } 76 77 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 78 let reuseIdentifier = "cell" 79 80 var cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier) 81 if cell == nil { 82 cell = UITableViewCell(style: .subtitle, reuseIdentifier: reuseIdentifier) 83 } 84 85 let targetDate = dateOrder[indexPath.section] 86 guard let plan = schedules[targetDate]?[indexPath.row] else { 87 return cell! 88 } 89 90 cell!.textLabel?.text = plan.name 91 92 let time = timeFormatter.string(from: plan.date) 93 cell!.detailTextLabel?.text = "(plan.detail) (time)予定" 94 return cell! 95 } 96} 97 98extension MyViewController: UITableViewDelegate { 99 100 func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { 101 102 let targetDate = dateOrder[section] 103 104 let label = UILabel() 105 label.backgroundColor = .lightGray 106 label.textColor = .white 107 108 label.text = formatter.string(from: targetDate) 109 110 return label 111 } 112 113 func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 114 return 60.0 115 } 116 117 func numberOfSections(in tableView: UITableView) -> Int { 118 return schedules.keys.count 119 } 120} 121
◆◆コードを読み進めていて難しいと感じている箇所◆◆
配列に入った構造体の値で辞書をDate型で宣言
var schedules = Date: [Plan]
以下が値に使われている構造体
struct Plan {
let name: String let detail: String let date: Date
}
⇨ここまでは構造体と辞書の宣言という表面的な理解ですが、あまり馴染みのない構造体が辞書の値に直接入っており(加えて配列で)最初の段階で応用の効いた?コードだと読むのに挫折しかけました。
schedules = Dictionary(grouping: plans) { plan -> Date in
f.dateFormat = "yyyy/MM/dd" let s = f.string(from: plan.date) return f.date(from: s)! }
⇨ここで先ほど宣言した辞書をGroupingしたDictionaryとして具体的に生成しているみたいです。**grouping:**の対象となる値を構造体Planを配列に入れたplansに指定しています。
let plans = [
Plan(name: "休み", detail: "実家で過ごす", date: f.date(from: "2018/01/01 09:00")!), Plan(name: "外出", detail: "初詣", date: f.date(from: "2018/01/03 10:00")!), Plan(name: "休み", detail: "飲み会", date: f.date(from: "2018/01/17 20:00")!) ]
⇨その後に記述されているクロージャもあまり馴染みがなく、planを引数名に指定して戻り値をDate型指定してどうやらplan.date=plans=Plan構造体のdateプロパティの値を「年月日」に整える処理をしているというに読みました。
.reduce(into: Date: [Plan]) { dic, tuple in
dic[tuple.key] = tuple.value.sorted { $0.date < $1.date } }
⇨辞書のkeyを使ってようやく辞書らしい?文法が出てきましたが、大枠ではreduceを使ってバラバラの値を再定義し直しているようです。ここでタプルの配列が出てくる意味がよくわかりません・・・m(_ _)m 検索して見つかった記事にtuple変数という表記は出てくるのですが詳しい解説は見つかりませんでした。
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let targetDate = dateOrder[section] return schedules[targetDate, default: []].count }
⇨ようやく馴染みのあるtableviewに今まで定義してきたコードを落とし込む集大成の部分です。日付順を保持した配列「dateOrder = Array(schedules.keys).sorted { $0 < $1 }」をtableviewのsectionのindexpath(0,1,2,3・・・)で全てピックアップして定数targetDateに入れ込む。その後、返り値でschedules[targetDate, default: []]として使用しているところまで普通の読み方で追いかけたのですが、default:が今いちよくわかりませんでした。Apple公式には「defaultValue・・・key辞書に存在しない場合に使用するデフォルト値」とありましたが、schedulesを定義する段階で表面的な理解のまま進めており、いざ使う段階でさらに何が起きてるのか追いつけてない状態です(説明が下手ですみません)。
let targetDate = dateOrder[indexPath.section]
guard let plan = schedules[targetDate]?[indexPath.row] else { return cell! }
⇨cellの内容を定義する部分で全体的にそこまで難しくは感じませんでしたが、schedules[targetDate]?[indexPath.row]のsectionとrowの間に使われている「?」がどういう意味なのか単純に引っかかりました。
拙い日本語と説明文ですみません。またコード全体的な質問になり、長い質問になっております。
こちらで知恵を拝借させていただけると幸いですm(_ _)m
回答2件
あなたの回答
tips
プレビュー