如何使用Swift处理空对象?

时间:2016-09-24 06:12:23

标签: ios swift core-data swift2 nscalendar

我有一个跟踪每月费用的应用。我有一个费用实体,其属性可以跟踪创建的当前月费用。然后,我会在表格视图中显示每个月的费用,如下所示。只有在下一个月或上个月有费用时,用户才能左右切换

@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月份仍然可以看到他/她的费用而不会跳过它。有任何想法吗?

2 个答案:

答案 0 :(得分: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的数据模型中获取数据,然后每月渲染一次根据{{​​1}}变量(关于用户当前看到的月份)。

因此,您只能在控制器的负载中调用currentMonth方法,并且每次用户更改当前月份视图时都会。{/ p>

答案 1 :(得分:0)

在@ 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
}

使用pedroruan的processMonth(),我能够浏览空的tableViews,以便用户可以看到August仍然是空的,但仍然能够进入6月的月份。谢谢你们。