【问题标题】:pass a Empty Object Array Model to another View controller Swift将一个空对象数组模型传递给另一个视图控制器 Swift
【发布时间】:2019-11-24 07:18:41
【问题描述】:

我有一个对象数组来将联系人数据存储在模型中。还有一个带有两个任务的视图控制器。在此视图 Controller 中修改和创建联系人。在修改模式下,我将模型数据传入 表视图 didSelectRow ,现在那里有问题。 但在创建模式下,当在第一个 VC 应用程序中触摸添加按钮时会导致此崩溃:致命错误:在隐式展开可选值时意外发现 nil。 主要问题是如何在不崩溃的情况下将空模型传递给 VC2。

型号:

class ContactModel : NSObject {
    var identifier : String!
    var thumbnailImageData : UIImage?
    var givenName : String!
    var familyName : String!
    var phoneNumbers : [String]!
    var emailAddresses : [String]!

    override init()
    {
        super.init();
    }

    init(identi:String,img:UIImage?,name:String,family:String,phone:[String],email:[String]) {
        self.identifier = identi
        self.thumbnailImageData = img
        self.givenName = name
        self.familyName = family
        self.phoneNumbers = phone
        self.emailAddresses = email
    }

    class func generateModelArray() -> [ContactModel]{
         let contactStore = CNContactStore()
         var contactsData = [ContactModel]()
         let key = [CNContactGivenNameKey,CNContactFamilyNameKey,CNContactImageDataKey,CNContactThumbnailImageDataKey,CNContactPhoneNumbersKey,CNContactEmailAddressesKey,CNLabelPhoneNumberMobile] as [CNKeyDescriptor]
         let request = CNContactFetchRequest(keysToFetch: key)
         try? contactStore.enumerateContacts(with: request, usingBlock: { (contact, stoppingPointer) in
             let givenName = contact.givenName
             let familyName = contact.familyName
//             let emailAddress = contact.emailAddresses.first?.value ?? ""
            let email : [String] = contact.emailAddresses.map { ($0.value as String) }
//             let phoneNumber = contact.phoneNumbers.first?.value.stringValue ?? ""
            let phone : [String] = contact.phoneNumbers.map { $0.value.stringValue }
             let identifier = contact.identifier
            var image : UIImage?
             if contact.thumbnailImageData != nil{
                 image = UIImage(data: contact.thumbnailImageData!)!
             }
             contactsData.append(ContactModel(identi: identifier, img: image, name: givenName, family: familyName, phone: phone, email: email))

         })
         return contactsData
     }
}

第一个表视图确实选择了行:

   func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
      if let storyboard = self.storyboard
      {
         let vc = storyboard.instantiateViewController(withIdentifier: "InsertContactViewController") as! InsertContactViewController
         vc.strTitle = "edit contact"
         vc.contactModel = dataArray[indexPath.row]
         vc.delegate = self
         self.navigationController?.pushViewController(vc, animated: true)
      }
   }

在第一个 VC 中添加按钮:

   @IBAction func btnAdd_DidTouch(_ sender: Any) {
      let story = UIStoryboard(name: "Main", bundle: nil)
      let vc = story.instantiateViewController(withIdentifier: "InsertContactViewController") as! InsertContactViewController
      vc.isCreateContact = true
      vc.delegate = self
      self.navigationController?.pushViewController(vc, animated: true)
   }

VC 2:

var contactModel : ContactModel!


    override func viewDidLoad() {
        super.viewDidLoad()
}

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if section == 0 {
            return 1
        }else if section == 1{
            return contactModel.phoneNumbers.count
        }else if section == 2 {
            return contactModel.emailAddresses.count
        }
        return 0
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if indexPath.section == 0 {
            let cell0 = tableView.dequeueReusableCell(withIdentifier: "InsertTableCell0") as! InsertTableCell0
                 //////crash happend here
            cell0.txtFirstName.text = self.contactModel.givenName
               //////crash happend here
            cell0.txtLastName.text = self.contactModel.familyName
            return cell0
        }else if indexPath.section == 1 {
            let cell1 = tableView.dequeueReusableCell(withIdentifier: "InsertTableCell1") as! InsertTableCell1
            cell1.btnDelete.addTarget(self, action: #selector(deleteRowDate(_:)), for: .touchUpInside)
            cell1.txtPhoneNumber.placeholder = "Phone Number"
            cell1.txtPhoneNumber.text = contactModel.phoneNumbers[indexPath.row]
            return cell1
        }else {
            let cell2 = tableView.dequeueReusableCell(withIdentifier: "InsertTableCell2") as! InsertTableCell2
            cell2.btnEmail.addTarget(self, action: #selector(deleteRowDate(_:)), for: .touchUpInside)
            cell2.txtEmail.placeholder = "Email"
            cell2.txtEmail.text = contactModel.emailAddresses[indexPath.row]
            return cell2
        }
    }

【问题讨论】:

  • 将var contactModel : ContactModel! 更改为var contactModel : ContactModel?。应用不会崩溃。

标签: swift xcode


【解决方案1】:

在 InsertContactViewController 中传递一个新的 ContactModel 引用。

代码:

@IBAction func btnAdd_DidTouch(_ sender: Any) {
  let story = UIStoryboard(name: "Main", bundle: nil)
  let vc = story.instantiateViewController(withIdentifier: "InsertContactViewController") as! InsertContactViewController
  vc.isCreateContact = true
  vc.contactModel = ContactModel() // pass a new reference 
  vc.delegate = self
  self.navigationController?.pushViewController(vc, animated: true)
}

型号:

class ContactModel : NSObject {
    var identifier : String?
    var thumbnailImageData : UIImage?
    var givenName : String?
    var familyName : String?
    var phoneNumbers : [String]?
    var emailAddresses : [String]?

   // rest of your code
}

注意:将 var contactModel : ContactModel! 更改为 var contactModel : ContactModel?。应用不会崩溃。

【讨论】:

  • 当我改变了这个contactModel:ContactModel!到这个 var contactModel : ContactModel? , Xcode Show 39 Error with this Value : Value of optional type 'ContactModel?'必须解包以引用已包装基类型“ContactModel”的成员“familyName”
  • 像这个 ContactModel() 一样传递空对象模式。但在它从模型中删除所有 ! 之前,否则应用程序会崩溃。
  • 抱歉,如果不对ContactModel 进行修改,您的代码也会崩溃。
  • tnx 为你的答案兄弟。但是在第二个 VC 中存在一个问题,我尝试处理它但是 icant 。当我尝试你的方式时,问题是 xcode 用这个值显示了很多错误:可选类型“[String]?”的值必须解包以引用已包装基本类型 '[String]' 的成员 'count' 。例如:contactModel.phoneNumbers.count,此行应转换为:contactModel?.phoneNumbers.count 或其他?
  • 是的,修复所有错误最多需要 5 分钟。这是解决您的问题的好方法。现在由你决定。
【解决方案2】:

首先从不将属性声明为隐式展开的可选属性,这些属性使用init 方法初始化。将它们声明为非可选 - 如果参数是非可选的 - 或作为常规可选 (?)

并删除默认初始化器init(),这使得其他初始化器成为必需(且可靠)

class ContactModel : NSObject {
    var identifier : String
    var thumbnailImageData : UIImage?
    var givenName : String
    var familyName : String
    var phoneNumbers : [String]
    var emailAddresses : [String]

    init(identi: String,img: UIImage?,name: String,family: String,phone:[String],email:[String]) {
        self.identifier = identi
        self.thumbnailImageData = img
        self.givenName = name
        self.familyName = family
        self.phoneNumbers = phone
        self.emailAddresses = email
    }

罢工>

override init()
{
    super.init();
} 

在 VC 2 中将 contactModel 声明为可选

var contactModel : ContactModel?

并且在numberOfRowsInSection 中使用可选绑定来安全地解包可选,switch 语句更清晰。

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    guard let model = contactModel else { return 0 }
    switch section {
        case 0: return 1
        case 1: return model.phoneNumbers.count
        case 2: return model.emailAddresses.count
        default: return 0
    }
}

强制解开cellForRow 中出现的其他contactModel,仅当contactModel 不是nil 时才会调用。

最后在viewWillAppear中添加一行重新加载表格视图

【讨论】:

  • tnx 为您的答案。以你的方式,xcode 显示了这个值的很多错误:可选类型“ContactModel?”的值必须解包以引用已包装基类型 'ContactModel' 的成员 'familyName' 。例如:contactModel.phoneNumbers.count,此行应转换为:contactModel?.phoneNumbers.count 或其他?
  • 请把我的回答读到最后。我在cellForRow 中写了Force unwrap 其他出现的contactModel,这仅在contactModel 不为零时调用
猜你喜欢
  • 1970-01-01
  • 2015-10-13
  • 1970-01-01
  • 2021-12-20
  • 2012-05-02
  • 2011-09-08
  • 2013-04-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多