設計
・懸念点
・初回起動時のログイン作業を避ける
・外観の整合性をとる
・操作の一環性
・直接操作させる
・操作のフィードバック
・メタファを使用(UIを現実世界のものに例える)
・ユーザの望ましくない操作を回避
・控えめであること
・明瞭であること
・奥行きを与えること
データ(Model)
なし ↓↑instance
処理(Controller)
IBOutlet↓↑IBAction
表示(View)
・アプリのライフサイクル
読み込み前 > loadView
読み込み後 > viewDidLoad ... 最初に一度だけ行いたい処理
(別画面から遷移)
表示前 > viewWillAppear
レイアウト前 > viewWillLayoutSubviews
レイアウト後 > viewDidLayoutSubviews
(画面表示開始)
表示後 > viewDidAppear
・・・
消える前 > viewWillDisappear
(画面表示終了)
消えた後 > viewDidDisappear
(別画面へ遷移)
Swift
segue
・戻ってきた時
@IBAction func ファンクション名(_ segue: UIStoryboardSegue) {
// 処理
}
let 変数 = segue.destination as! 別クラス名
タイマー
・宣言
// タイマー
var timer: Timer!
// 時間
var timer_sec: Float = 0
・始動
インターバル秒毎にselecterで指定した以下の関数を実行する
self.timer = Timer.scheduledTimer(timeInterval: インターバル秒, target: self, selector: #selector(関数名(_:)), userInfo: nil, repeats: true)
@objc func updateTimer(_ timer: Timer) {
// ラベルに(インターバル秒毎に)経過時間を表示する
self.timer_sec += インターバル秒
self.ラベル名.text = String(format: "%.1f", self.timer_sec)
}
・タイマー停止
self.timer.invalidate()
日時フォーマット
// 取得
let formatter = DateFormatter()
// 指定
formatter.dateFormat = "yyyy-MM-dd HH:mm"
// 変換
let 変数:String = formatter.string(from: 変換するデータ)
通知
・AppDelegateに記述
import UserNotifications
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// ユーザに通知の許可を求める
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound]) { (granted, error) in
// Enable or disable features based on authorization
}
center.delegate = self // フォアグラウンド時に通知を受け取る場合は記述
return true
}
フォアグラウンド時に通知を受け取る場合は
デリゲート「UNUserNotificationCenterDelegate」を追加して以下を記述
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.banner, .list, .sound])
}
.badge ... アプリアイコンに通知件数表示
.alert ... 通知バナー表示
.sound ... 通知音
・登録
以下はローカル通知を登録する処理
// 通知のインスタンス
let content = UNMutableNotificationContent()
content.title = task.title //タイトル
content.body = task.contents //詳細
content.sound = UNNotificationSound.default //通知
// ローカル通知が発動するtrigger(日付マッチ)を作成
let calendar = Calendar.current
let dateComponents = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: task.date)
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)
// identifier, content, triggerからローカル通知を作成(identifierが同じだとローカル通知を上書き保存)
let request = UNNotificationRequest(identifier: String(task.id), content: content, trigger: trigger)
// ローカル通知を登録
let center = UNUserNotificationCenter.current()
center.add(request) { (error) in
print(error ?? "ローカル通知登録成功)
}
// 未通知のローカル通知一覧をログ出力
center.getPendingNotificationRequests { (requests: [UNNotificationRequest]) in
print("未通知のローカル通知一覧")
for request in requests {
print("/---------------")
print(request)
print("---------------/")
}
}
・削除
Realm
・宣言
クラス外
import RealmSwift
クラス内
let realm = try! Realm()
var realmSample = try! Realm().objects(Sample.self).sorted(byKeyPath: "date", ascending: true)
・segue で画面遷移時
override func prepare(for segue: UIStoryboardSegue, sender: Any?){
let inputViewController:InputViewController = segue.destination as! InputViewController
if segue.identifier == "cellSegue" {
let indexPath = self.tableView.indexPathForSelectedRow
inputViewController.task = taskArray[indexPath!.row]
} else {
let task = Task()
let allTasks = realm.objects(Task.self)
if allTasks.count != 0 {
task.id = allTasks.max(ofProperty: "id")! + 1
}
inputViewController.task = task
}
}
UITableVeiwデリゲート
// データの数(=セルの数)を返すメソッド
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return taskArray.count // ←修正する
}
// 各セルの内容を返すメソッド
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// 再利用可能な cell を得る
let cell = tbl_sample.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
// Realmから情報を取得
let task:Task = realmSample[indexPath.row]
// Cellに値を設定
cell.textLabel?.text = task.title
cell.detailTextLabel?.text = task.date
return cell
}
// 各セルを選択した時に実行されるメソッド
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "cellSegue",sender: nil)
}
// セルが削除が可能なことを伝えるメソッド
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath)-> UITableViewCell.EditingStyle {
return .delete
}
// Delete ボタンが押された時に呼ばれるメソッド
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
// データベースから削除
try! realm.write {
self.realm.delete(self.taskArray[indexPath.row])
tableView.deleteRows(at: [indexPath], with: .fade)
}
}
}