如何只为单元格内的某些视图提供值,同时留下一些零而不崩溃?

Posted

技术标签:

【中文标题】如何只为单元格内的某些视图提供值,同时留下一些零而不崩溃?【英文标题】:How to provide values for only certain views inside a cell while leaving some nil and not crash? 【发布时间】:2017-03-31 14:26:05 【问题描述】:

我有一个包含一些令人困惑的规范的课程。我需要编写一个应用程序来存储有关用户消费的食物的详细信息。我已经完成了所有这些,我将条目存储在一个核心数据实体中,并将​​它们显示在一个表中。问题在于,在用户可以提供的 6 条不同信息中,只有 3 条是强制性的(餐点名称、日期和时间以及食物组)。其他 3 个(照片、用餐类型和用户 ID)他可以跳过。我在核心数据中的所有属性都是可选的。当我完成所有字段时,它工作得很好。一旦我将不必要的 3 设置为 nil,我就会得到一个致命错误(在展开可选时发现 nil)。有人可以帮忙解决这个问题吗?谢谢你。代码清单如下。

 @IBAction func saveUserInput(_ sender: UIButton) 
    let userMeals = UserMeals(context: managedObjectContext!)
    if (mealName.text?.isEmpty)! || (foodGroup.text?.isEmpty)! || (dateAndTimeOfMeal.text?.isEmpty)!
        let screenAlert = UIAlertController(title: "Warning!", message: "You must enter at least the name of the meal, the date and time, and the group!", preferredStyle: .alert)
        screenAlert.addAction(UIAlertAction(title: "Got it!", style: .default, handler: nil))
        self.present(screenAlert, animated: true, completion: nil)
     else if photoView?.image == nil || (mealType.text?.isEmpty)! || (userName.text?.isEmpty)!
        userMeals.mealPhoto = nil
        userMeals.mealType = nil
        userMeals.userID = nil
        let screenNotification = UIAlertController(title: "Done!", message: "Your meal has been saved without a photo, meal type and user name!", preferredStyle: .alert)
        screenNotification.addAction(UIAlertAction(title: "Got it!", style: .default, handler: nil))
        self.present(screenNotification, animated: true, completion: nil)
     else 
        userMeals.mealPhoto = NSData(data: UIImageJPEGRepresentation((photoView?.image)!, 0.5)!)
        userMeals.mealName = mealName?.text
        userMeals.foodGroup = foodGroup?.text
        userMeals.dateAndTime = dateAndTimeOfMeal?.text
        userMeals.mealType = mealType?.text
        userMeals.userID = userName?.text
        let screenNotification = UIAlertController(title: "Done!", message: "Your meal has been saved!", preferredStyle: .alert)
        screenNotification.addAction(UIAlertAction(title: "Got it!", style: .default, handler: nil))
        self.present(screenNotification, animated: true, completion: nil)
    

表格视图类的代码:

private func loadData() 
    let mealRequest: NSFetchRequest<UserMeals> = UserMeals.fetchRequest() // get all information from core, of type guardian.
    do 
        storedMeals = try managedObjectContext.fetch(mealRequest)
     catch 
        print("could not load data from core \(error.localizedDescription)") // get more details from the error.
    


// MARK: - Table view data source

override func numberOfSections(in tableView: UITableView) -> Int 
    return 1


override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    return storedMeals.count


override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    let cell = tableView.dequeueReusableCell(withIdentifier: "cellForMeal", for: indexPath) as! ViewMealsCell
    let mealItem = storedMeals[indexPath.row]
    if let mealImage = UIImage(data: mealItem.mealPhoto as! Data) 
        cell.mealPhoto.image = mealImage
    
    cell.mealName.text = mealItem.mealName
    cell.foodGroup.text = mealItem.foodGroup
    cell.dateAndTime.text = mealItem.dateAndTime
    cell.mealType.text = mealItem.mealType
    cell.userName.text = mealItem.userID
    return cell


override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool 
    return true


override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) 
    if editingStyle == .delete  // delete the row from the data source
        tableView.deleteRows(at: [indexPath], with: .fade)
        self.tableView.reloadData()
    

用户餐的定义:

extension UserMeals 

@nonobjc public class func fetchRequest() -> NSFetchRequest<UserMeals> 
    return NSFetchRequest<UserMeals>(entityName: "UserMeals");


@NSManaged public var dateAndTime: String?
@NSManaged public var foodGroup: String?
@NSManaged public var mealName: String?
@NSManaged public var mealPhoto: NSData?
@NSManaged public var mealType: String?
@NSManaged public var userID: String?

【问题讨论】:

我用 UserMeals 定义编辑了代码清单 我添加了一张包含崩溃细节的照片 我在问问题之前已经完成了 if let ......结果是一样的...... 现在就可以了。谢谢您的宝贵时间 我在调试器中得到了一个循环。我在所有 3 个数据源函数中都加了点。当我按步进入或继续程序执行时,它会循环节数和节中的行数,但不会进入索引路径处的行的单元格。它只是向我显示带有十六进制值的页面。请给我一秒钟重做调试 【参考方案1】:

问题出在这一行:

if let mealImage = UIImage(data: mealItem.mealPhoto as! Data) 
    cell.mealPhoto.image = mealImage

只要你有一个感叹号,你就是在说“请让我崩溃”。如果运行时完全按照您的要求执行,您就不能抱怨。

你想在这里使用as?。这将安全地展开

可能需要进行额外的安全展开,但一般来说,这是您想要采用的方法。例如,你可能会这样写:

if let data = mailItem.mealPhoto as? Data 
    cell.mealPhoto.image = UIImage(data:data)

通过这种方式,我们首先将mealPhoto 安全解包到一个数据中,然后从该数据安全地创建图像。您需要分两步执行此操作,因为您不能使用 Data? 参数调用 UIImage(data:);你必须先打开Data


EDIT 正如 cmets 中正确指出的那样,我们需要为 每一 行设置image,而不仅仅是我们拥有数据的行。因此,将上述内容扩展为以下内容:

if let data = mailItem.mealPhoto as? Data 
    cell.mealPhoto.image = UIImage(data:data)
 else 
    cell.mealPhoto.image = nil

通过这种方式,我们删除了我们没有图像数据的重复使用表行的图像。

【讨论】:

但是 - 当你没有返回有效数据时,使用这个检查作为一个机会来提供一个默认图像 - 否则你最终会显示上一次可重复使用单元格的 mealPhoto如果 let data = mailItem.mealPhoto 显示为?数据 cell.mealPhoto.image = UIImage(data:data) else cell.mealPhoto.image = mealPhotoDefaultImage @Russell 非常好。我将添加nil 作为替代。 — 当我写下我的答案时,我专注于崩溃和展开,而不是这是一张桌子这一事实。 :)

以上是关于如何只为单元格内的某些视图提供值,同时留下一些零而不崩溃?的主要内容,如果未能解决你的问题,请参考以下文章

滚动后某些表格视图单元格内容消失(swift)

如何从表格视图的自定义单元格内的文本字段中获取值(标签)以发布到 URL [重复]

如何从表格视图的自定义单元格内的 TextField 获取值(标签)以发布到 te URL

从表格视图单元格内的文本字段中获取文本

表格视图单元格内的 UIImage

将indexpath标签传递给tableview原型单元格内的按钮