如何使用 Swift 处理空对象?
Posted
技术标签:
【中文标题】如何使用 Swift 处理空对象?【英文标题】:How to handle empty objects with Swift? 【发布时间】:2016-09-24 06:12:23 【问题描述】:我有一个跟踪每月支出的应用程序。我有一个 Expense 实体,该实体具有一个 month 属性,用于跟踪创建当前月份的费用。然后,我将在表格视图中显示每个月的费用,如下所示。用户只有在下个月或上个月有费用时才能左右切换
@IBAction func backMonthButtonPressed(sender: AnyObject)
print("Back Button Pressed")
currentMonth = NSCalendar.currentCalendar().dateByAddingUnit(.Month, value: -1, toDate: currentMonth, options: [])!
if checkMonth(currentMonth)
updateFetch()
setMonth()
else
currentMonth = NSCalendar.currentCalendar().dateByAddingUnit(.Month, value: 1, toDate: currentMonth, options: [])!
tableView.reloadData()
@IBAction func nextMonthButtonPressed(sender: AnyObject)
print("Next Button Pressed")
currentMonth = NSCalendar.currentCalendar().dateByAddingUnit(.Month, value: 1, toDate: currentMonth, options: [])!
if checkMonth(currentMonth)
updateFetch()
setMonth()
else
currentMonth = NSCalendar.currentCalendar().dateByAddingUnit(.Month, value: -1, toDate: currentMonth, options: [])!
tableView.reloadData()
func checkMonth(month : NSDate) -> Bool
let app = UIApplication.sharedApplication().delegate as! AppDelegate
let context = app.managedObjectContext //scratch pad
let fetchRequest = NSFetchRequest(entityName: "Expense")
fetchRequest.predicate = NSPredicate(format: "month == %@", month.MonthYearDateFormatter())
let count = context.countForFetchRequest(fetchRequest, error: nil)
if count > 0
print("There are expenses for this month \(month.MonthYearDateFormatter()). Show expenses")
return true
else
print("There are no expenses for this month \(month.MonthYearDateFormatter()). Do Nothing")
return false
我的问题是,在不太可能的情况下,用户在 6 月份创建了一项费用,但在 8 月份没有创建费用。我怎样才能让用户在不跳过它的情况下仍然看到他/她在 8 月份的费用。有任何想法吗?
【问题讨论】:
一次获取所有费用并将它们存储在一个数组中,按月排序。然后只需浏览数组 【参考方案1】:在阐述之前我做了一些优化:
@IBAction func backMonthButtonPressed(sender: AnyObject)
self.processMonth(step: -1)
@IBAction func nextMonthButtonPressed(sender: AnyObject)
self.processMonth(step: 1)
// a method uses almost the same code for both cases, so it was merged
func processMonth(step: Int)
let direction = (step < 1 ? "Back" : "Next")
print("\(direction) Button Pressed")
currentMonth = NSCalendar.currentCalendar().dateByAddingUnit(.Month, value: step, toDate: currentMonth, options: [])!
//if checkMonth(currentMonth)
// I wouldn't test this because it locks you out from seeing empty month.
updateFetch()
setMonth()
//
tableView.reloadData()
回答您的确切问题:
如果你的 UITableView 的数据源设置正确,你应该可以度过空旷的几个月
// changed return type from `Bool` to `void` as I suggested in the method not to test empty month, as it could be useless
func checkMonth(month : NSDate)
let app = UIApplication.sharedApplication().delegate as! AppDelegate
let context = app.managedObjectContext //scratch pad
let fetchRequest = NSFetchRequest(entityName: "Expense")
fetchRequest.predicate = NSPredicate(format: "month == %@", month.MonthYearDateFormatter())
let count = context.countForFetchRequest(fetchRequest, error: nil)
if count > 0
print("There are expenses for this month \(month.MonthYearDateFormatter()). Show expenses")
else
print("There are no expenses for this month \(month.MonthYearDateFormatter()). Do Nothing")
// here you can make some additional actions, like seeting the empty table with "no expenses this month"
无论如何,正如 @Paulw11 所指出的,如果您的数据源不是大小耗尽的,您可以从数据模型中获取数据,例如 viewDidLoad/viewDidAppear,然后每月渲染根据currentMonth
变量(关于用户当前看到的月份)。
因此,您只能在控制器的负载中以及每次用户更改当前月份视图时调用 setMonth()
方法。
【讨论】:
【参考方案2】:在@Paulw11 和@pedrouan 的帮助下,我能够做我想做的事。
获取所有费用
func fetchExpenses()
let app = UIApplication.sharedApplication().delegate as! AppDelegate
let context = app.managedObjectContext //scratch pad
let fetchRequest = NSFetchRequest(entityName: "Expense")
//Always Sort Budget by the date it's created
let sortDescriptor = NSSortDescriptor(key: "created", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
do
let results = try context.executeFetchRequest(fetchRequest)
self.expenses = results as! [Expense]
catch let err as NSError
print(err.debugDescription)
将约束设置为第一个月和最后一个月,以确定用户可以在 viewDidLoad 中浏览月份的距离
//If array is not empty, set first and last month
if expenses.count > 0
guard let first = expenses.first?.month else
return
firstMonth = first
guard let last = expenses.last?.month else
return
lastMonth = last
else
//Set current month to be first and last
firstMonth = currentMonth.MonthYearDateFormatter()
lastMonth = currentMonth.MonthYearDateFormatter()
限制用户超过第一个月和上个月
@IBAction func backMonthButtonPressed(sender: AnyObject)
print("Back Button Pressed")
if currentMonth.MonthYearDateFormatter() != firstMonth
self.processMonth(step: -1)
@IBAction func nextMonthButtonPressed(sender: AnyObject)
print("Next Button Pressed")
if currentMonth.MonthYearDateFormatter() != lastMonth
self.processMonth(step: 1)
返回当月的所有费用,如果没有明确的取回空表。
func updateFetch()
setFetchResults()
do
try self.fetchedResultsController.performFetch()
catch
let error = error as NSError
print("\(error), \(error.userInfo)")
func setFetchResults()
let app = UIApplication.sharedApplication().delegate as! AppDelegate
let context = app.managedObjectContext //scratch pad
//Fetch Request
let fetchRequest = NSFetchRequest(entityName: "Expense")
let sortDescriptor = NSSortDescriptor(key: "created", ascending: false)
fetchRequest.predicate = NSPredicate(format: "month == %@", currentMonth.MonthYearDateFormatter())
fetchRequest.sortDescriptors = [sortDescriptor]
let count = context.countForFetchRequest(fetchRequest, error: nil)
let controller = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: ad.managedObjectContext , sectionNameKeyPath: section, cacheName: nil)
//If there is none, empty fetch request
if count == 0
print("There are no expenses for this month. Show nothing")
controller.fetchRequest.predicate = NSPredicate(value: false)
else
print("There are expenses for this month. Show expenses")
fetchedResultsController = controller
controller.delegate = self
使用 pedroran 的 processMonth(),我能够在空的 tableViews 中导航,以便用户可以看到八月是空的,同时仍然能够进入六月的月份。谢谢大家。
【讨论】:
以上是关于如何使用 Swift 处理空对象?的主要内容,如果未能解决你的问题,请参考以下文章
java中如何使用空参构造方法自动生成不同名字的对象,使用非静态的属性和静态属性有什么区别,原因是什么?如何理解static关键字