你能在打开包装时发现 nil 吗?

Posted

技术标签:

【中文标题】你能在打开包装时发现 nil 吗?【英文标题】:can you spot the nil while unwrapping? 【发布时间】:2017-05-03 00:41:41 【问题描述】:

我试图在展开时找到 nil 的位置。这是我的一段代码。发现致命错误的行位于:

第一个文件:

date = dateFormatter().date(from: dictionary[kDATE] as! String)!

第二个文件:

self.allLists.append(ShoppingList.init(dictionary: currentList))

这是来自 shoppingList.swift 文件,该函数在控制器中调用

import Foundation
import Firebase

class ShoppingList
    let name: String
    var totalPrice: Float
    var totalItems: Int
    var id: String
    var date: Date
    var ownerId: String

    init(_name: String, _totalPrice: Float = 0, _id: String = "") 
        name = _name
        totalPrice = _totalPrice
        totalItems = 0
        id = _id
        date = Date()
        ownerId = "1234"
    

    //creates shopping list item from this dictionary

    init(dictionary: NSDictionary) 

        name = dictionary[kNAME] as! String
        totalPrice = dictionary[kTOTALPRICE] as! Float
        totalItems = dictionary[kTOTALITEMS] as! Int
        id = dictionary[kSHOPPINGLISTID] as! String
        date = dateFormatter().date(from: dictionary[kDATE] as! String)!
        ownerId = dictionary[kOWNERID] as! String
    

    func dictionaryFromItem(item: ShoppingList) -> NSDictionary 

        return NSDictionary(objects: [item.name, item.totalPrice, item.totalItems, item.id, dateFormatter().string(from: item.date), item.ownerId], forKeys: [kNAME as NSCopying, kTOTALPRICE as NSCopying, kTOTALITEMS as NSCopying, kSHOPPINGLISTID as NSCopying, kDATE as NSCopying, kOWNERID as NSCopying])

    

这里是控制器:

import UIKit
import KRProgressHUD


class AllListsViewController: UIViewController, UITableViewDataSource,UITableViewDelegate


    @IBOutlet weak var tableView: UITableView!

    var allLists:[ShoppingList] = []
    var nameTextField: UITextField!

    override func viewDidLoad() 

        super.viewDidLoad()
        loadLists()

    

    //MARK: TableView DataSource

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 

        return allLists.count
    

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 

        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)

        let shoppingList = allLists[indexPath.row]

        cell.textLabel?.text = shoppingList.name

        return cell
    

    //MARK: IBActions


    @IBAction func addBarButonItemPressed(_ sender: Any) 

        let alertController = UIAlertController(title: "Create Shopping List", message: "Enter the shopping list name", preferredStyle: .alert)

        alertController.addTextField (nameTextField) in

            nameTextField.placeholder = "Name"
            self.nameTextField = nameTextField
        

        let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) (action) in


        

        let saveAction = UIAlertAction(title: "Save", style: .default) (action) in

            if self.nameTextField.text != ""

                self.createShoppingList()

            else

                KRProgressHUD.showWarning(message: "Name is empty!")
            

        

        alertController.addAction(cancelAction)
        alertController.addAction(saveAction)

        self.present(alertController,animated: true, completion:nil)


    

    //MARK: LoadList


    func loadLists()

        //.values has all the info of the child

        firebase.child(kSHOPPINGLIST).child("1234").observe(.value, with: 
            snapshot in

            self.allLists.removeAll()

            //if we actually received smthing from firebase

            if snapshot.exists()

                let sorted = ((snapshot.value as! NSDictionary).allValues as NSArray).sortedArray(using: [NSSortDescriptor(key: kDATE,ascending: false)])

                for list in sorted 

                    let currentList = list as! NSDictionary

                    self.allLists.append(ShoppingList.init(dictionary: currentList))

                

             else 

                print("no snapshot")
            

            self.tableView.reloadData()

        )


    


    //MARK: Helper functions

    func createShoppingList()


        let shoppingList = ShoppingList(_name: nameTextField.text!)

        shoppingList.saveItemInBackground(shoppingList: shoppingList) (error) in

            if error != nil

                KRProgressHUD.showError(message: "Error creating shopping list")
                return

            
        
    

数据格式化程序也是另一个文件中的一个小函数。

import Foundation
import UIKit

private let dateFormat = "yyyyMMDDHHmmss"

func dateFormatter() -> DateFormatter 

    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = dateFormat

    return dateFormatter


【问题讨论】:

请发布相关代码。 请学习***.com/questions/32170456/… "我试图在展开时找到 nil 在哪里" 不,你没有尝试。您的代码 (!) 中的每个感叹号都表示“请让我崩溃”。如果这正是发生的事情,你不能抱怨。要找到nil,您所要做的就是自己寻找它。不要使用任何感叹号! 安全地执行所有向下转换和解包 Optionals 并在调试器中单步执行以查看实际发生的情况。 @rmaddy 我认为他们会帮助您了解我在做什么,我也对您提出的问题提出了质疑,我被卡住了。感谢您抽出宝贵时间发表评论。 @matt 我试图安全地解开 if 中的 valuew,但编译器抱怨我没有初始化所有值。感谢您抽出宝贵时间发表评论。 【参考方案1】:

所以你在这一行有一个强制向下转换和一个强制可选展开:

date = dateFormatter().date(from: dictionary[kDATE] as! String)!

您的字典没有返回字符串,或者从字典中出来的字符串无法作为日期处理。我猜这是第一个问题,因为日期通常存储为epoch。

试试这个而不是上面的行。在顶部添加断点并单步执行:

print(dictionary[kDATE])
if let dictValue = dictionary[kDATE] as? String 
   print(dictValue)
   if let unwrappedDate = dateFormatter().date(from: dictValue) 
       date = unwrappedDate
   
 

如果在第一个 if-let 上失败,则返回值不是字符串。如果第二次失败,则问题在于日期格式化程序无法读取格式。

第一个打印可能会为您提供有关要转换为哪种类型的线索,第二个打印可以帮助您修复格式。

强制解包时要小心,

optionalVar!

或用于向下转换。

unknownType as! Type

当你绝对确定值不可能为零时,你真的应该只“使用强制”。

【讨论】:

以上是关于你能在打开包装时发现 nil 吗?的主要内容,如果未能解决你的问题,请参考以下文章

在 SwiftUI 类中调用包装的 UIViewController 函数时获得 nil

Swift UIViewController tableView.reloadData nil 在第二次调用时包装

Swift 4:将 Bool 选项打印为未包装的 true 或 false 或包装的 nil?

你能指定 CSS flex 中包裹元素的顺序吗?

包装矩形算法

如何使用打开和关闭标记包装所选文本?