Open JohnnyDark opened 4 years ago
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
textField.becomeFirstResponder()
textField.resignFirstResponder() //失去焦点
}
1. storyboard中, 设置键盘:Auto-enable Return Key
2. textField的代理方法
// MARK:- Text Field Delegates
func textField(_ textField: UITextField,
shouldChangeCharactersIn range: NSRange,
replacementString string: String) -> Bool {
let oldText = textField.text!
let stringRange = Range(range, in:oldText)!
let newText = oldText.replacingCharacters(in: stringRange,
with: string)
if newText.isEmpty {
doneBarButton.isEnabled = false
} else {
doneBarButton.isEnabled = true
}
return true
}
func textFieldShouldClear(_ textField: UITextField) -> Bool {
doneBarButton.isEnabled = false
return true
}
override func tableView(_ tableView: UITableView,
accessoryButtonTappedForRowWith indexPath: IndexPath) {
let controller = storyboard!.instantiateViewController(
withIdentifier: "ListDetailViewController")
as! ListDetailViewController
controller.delegate = self
let checklist = lists[indexPath.row]
controller.checklistToEdit = checklist
navigationController?.pushViewController(controller,
animated: true)
}
let navigationController = window?.rootViewController let controller = navigationController.viewControllers[0] as! AllListsViewController
Document目录获取
func documentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory,
in: .userDomainMask)
return paths[0]
}
func dataFilePath() -> URL {
return documentsDirectory().appendingPathComponent(
"Checklists.plist")
}
获取data.plist文件目录
func dataFilePath() -> URL {
return documentsDirectory().appendingPathComponent(
"Checklists.plist")
}
数据保存
func saveChecklistItems() {
// 1
let encoder = PropertyListEncoder()
// 2
do {
// 3
let data = try encoder.encode(items)
// 4
try data.write(to: dataFilePath(),
options: Data.WritingOptions.atomic)
// 5
} catch {
// 6
print("Error encoding item array: \(error.localizedDescription)")
}
}
数据加载
func loadChecklistItems() {
// 1
let path = dataFilePath()
// 2
if let data = try? Data(contentsOf: path) {
// 3
let decoder = PropertyListDecoder()
do {
// 4
items = try decoder.decode([ChecklistItem].self,
from: data)
} catch {
print("Error decoding item array: \(error.localizedDescription)")
}
}
}
DataModel类设计与使用
let navigationController = window!.rootViewController
as! UINavigationController
let controller = navigationController.viewControllers[0]
as! AllListsViewController
controller.dataModel = dataModel
添加identifier实例变量
let cellIdentifier = "ChecklistCell"
给table view注册cell
tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellIdentifier)
使用cell
override func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(
withIdentifier: cellIdentifier, for: indexPath)
cell.textLabel!.text = "List \(indexPath.row)"
return cell
}
//保存值
UserDefaults.standard.set(indexPath.row, forKey: "ChecklistIndex")
//取值:
UserDefaults.standard.integer( forKey: "ChecklistIndex")
//设置初始值
let dictionary = [ "ChecklistIndex": -1 ]
UserDefaults.standard.register(defaults: dictionary)
//结合计算属性使用:
var indexOfSelectedChecklist: Int {
get {
return UserDefaults.standard.integer(
forKey: "ChecklistIndex")
}
set {
UserDefaults.standard.set(newValue,
forKey: "ChecklistIndex")
}
}
//userDefaults设置值后,将值立即写入进行保存
UserDefaults.standard.synchronize()
应用:判断app是否首次启动,预先在userdefaults中添加该 bool类型变量,实现 场景2
应用:userdefaults中获取key的整数值,如果没有,会返回0,此时需要在userdefaults中提前设置默认值实现 场景2
应用:将最后一次的checklist的数据在 datamodel中的索引进行保存实现 场景1
app闪退后,新添加的checklist对象没有被保存到datamodel,但是这个checklist对应的index确被保存了,造成启动app时,查询index对应的checklist对象没有,app crash, 添加判断:if index >= 0 && index < dataModel.lists.count {}
实现navigation controller delegate
// MARK:- Navigation Controller Delegates
func navigationController(
_ navigationController: UINavigationController,
willShow viewController: UIViewController,
animated: Bool) {
// Was the back button tapped?
if viewController === self {
UserDefaults.standard.set(-1, forKey: "ChecklistIndex")
}
}
生命周期方法中为navigation controller设置代理对象
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
navigationController?.delegate = self
let index = UserDefaults.standard.integer(
forKey: "ChecklistIndex")
if index != -1 {
let checklist = dataModel.lists[index]
performSegue(withIdentifier: "ShowChecklist",
sender: checklist)
}
}
ps: 该方法中设置代理的分析:
func navigationController( _:willShow:animated:): 该方法在stack中任意vc显示时都会调用,前提是给它设置了代理对象
app启动时不应该先去设置代理对象,这样会导致每次启动都将userdefaults中保存的index设置为-1,不能实现切换到指定的checklist对象的界面
在viewDidLoad中设置代理对象,则只有在main screen显示出来后,其后续的操作中可以使用navigation view controller的代理方法,这样才能正确实现该场景
AppDelegate.swift中 didFinishLaunching方法中执行如下代码
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let center = UNUserNotificationCenter.current()
center.delegate = self
return true
}
AppDelegate实现代理方法:
//MARK:- app前台运行时收到local Notification,可以进行相关的任务处理,在如下方法中
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
print("收到 通知")
}
}
每个item创建时,同时判断是否需要创建notification,如果是true则不管是是否已有notification,统一先移除原有的notification,按当前item详情界面的数据,创建新的notification并保存,如果为否,则不执行notification的创建
只需要在 checklistItem 的 deinit方法中进行就可以,这样无论是直接删除item,还是删除item所属的checklist,都会执行deinit方法,将notification移除
整体界面设置
AllChecklists->ChecklistDetail->AddItem
Navigation controller