【问题标题】:How to handle empty objects with Swift?如何使用 Swift 处理空对象?
【发布时间】:2023-03-03 23:32:02
【问题描述】:

我有一个跟踪每月支出的应用程序。我有一个 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 月份的费用。有任何想法吗?

【问题讨论】:

  • 一次获取所有费用并将它们存储在一个数组中,按月排序。然后只需浏览数组

标签: ios swift core-data swift2 nscalendar


【解决方案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 中导航,以便用户可以看到八月是空的,同时仍然能够进入六月的月份。谢谢大家。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-05-12
      • 2016-01-16
      • 2022-01-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-13
      相关资源
      最近更新 更多