2017-06-22 27 views
0

使用Swift 3Swift:没有正确访问JSON代码。 (在解包时发现零)

当我单击MainController.swift中的按钮followButtonClick时导致崩溃的错误。 blogID导致零,但是当我打印mainArray所有的对象都在那里,所以我的代码中有一些错误,我无法修复。 blogID未被正确访问。

fatal error: unexpectedly found nil while unwrapping an Optional value

而不是使用NSCoder和UserDefaults保存的mainArrayfollowedArray整个阵列的,我节省了跟随blogsID,然后显示那些我们被抓住的是有它们的ID保存的对象保存。

MainController.swift

var mainArray = [Blog]() 
var followedArray = [Blog]() 
var filteredArray = [Blog]() 
var followedIdentifiers = Set<String>() 

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

    retrieveDataFromServer() 
    loadUserDefaults() 
} 

// Title for Header 
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { 

if !(searchController.isActive && searchController.searchBar.text != "") { 

    if section == 0 { 
     return "Followed Blogs" 
    } 
    else { 
     return "All Blogs" 
    } 
} 
return "Filtered Blogs" 
} 

// Number of Rows in Section 
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 

if !(searchController.isActive && searchController.searchBar.text != "") { 

    if section == 0 { 

     return followedArray.count 
    } 
    else if (section == 1) { 

     return mainArray.count 
    } 
} 
return filteredArray.count 
} 

// CellForRowAt indexPath 
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 

let CellIdentifier = "Cell" 
var cell = tableView.dequeueReusableCell(withIdentifier: CellIdentifier) as! CustomCell 

if cell != cell { 
    cell = CustomCell(style: UITableViewCellStyle.default, reuseIdentifier: CellIdentifier) 
} 

// Configuring the cell 
var blogObject: Blog 

if !(searchController.isActive && searchController.searchBar.text != "") { 
    if indexPath.section == 0 { 
     blogObject = followedArray[indexPath.row] 
     cell.populateCell(blogObject, isFollowed: true, indexPath: indexPath, parentView: self) 
    } 
    else if indexPath.section == 1 { 
     blogObject = mainArray[indexPath.row] 
     cell.populateCell(blogObject, isFollowed: false, indexPath: indexPath, parentView: self) 
    } 
} 
else { 
    blogObject = filteredArray[indexPath.row] 
    cell.populateCell(blogObject, isFollowed: false, indexPath: indexPath, parentView: self) 
} 

return cell 
} 

// Follow Button 
@IBAction func followButtonClick(_ sender: UIButton!) { 

    // Adding row to tag 
    let buttonPosition = (sender as AnyObject).convert(CGPoint.zero, to: self.myTableView) 
    if let indexPath = self.myTableView.indexPathForRow(at: buttonPosition) { 

     // Showing Status Labels 
     let cell = self.myTableView.cellForRow(at: indexPath) as! CustomCell 
     cell.firstStatusLabel.isHidden = false 
     cell.secondStatusLabel.isHidden = false 

     // Change Follow to Following 
     (sender as UIButton).setImage(UIImage(named: "follow.png")!, for: .normal) 
     cell.followButton.isHidden = true 
     cell.followedButton.isHidden = false 

     // Checking wether to import from mainArray or filteredArray to followedArray 
     if !(searchController.isActive && searchController.searchBar.text != "") { 

      self.myTableView.beginUpdates() 

      // -*- Error breaks here -*- 
      // Save identifier into followedIdentifier array 
    self.followedIdentifiers.insert(mainArray[indexPath.row].blogID) 

      // ----- Inserting Cell to followedArray ----- 
      followedArray.insert(mainArray[indexPath.row], at: 0) 
      myTableView.insertRows(at: [IndexPath(row: 0, section: 0)], with: .fade) 

      // ----- Removing Cell from mainArray ----- 
      mainArray.remove(at: indexPath.row) 
      let rowToRemove = indexPath.row 
      self.myTableView.deleteRows(at: [IndexPath(row: rowToRemove, section: 1)], with: .fade) 

      self.myTableView.endUpdates() 

      myTableView.reloadData() 

      // After Updating Table, Save the Archived to UserDefaults 
      saveUserDefaults() 
     } 
     else { 

      self.myTableView.beginUpdates() 

      // Remove identifier into followedIdentifier array 
self.followedIdentifiers.remove(followedArray[indexPath.row].blogID) 

      // ----- Inserting Cell to followedArray ----- 
      let blogObject: Blog = filteredArray[indexPath.row] 
      let indexOfObjectInArray = mainArray.index(of: blogObject) 

      followedArray.insert(blogObject, at: 0) 

      // ----- Removing Cell from filteredArray ----- 
      filteredArray.remove(at: indexPath.row) 
      mainArray.remove(at: indexOfObjectInArray!) 
      let rowToRemove = indexPath.row 
      self.myTableView.deleteRows(at: [IndexPath(row: rowToRemove, section: 0)], with: .fade) 

      self.myTableView.endUpdates() 

      myTableView.reloadData() 

      // After Updating Table, Save the Archived to UserDefaults 
      saveUserDefaults() 
     } 
    } 
} 

// Unfollow Button 
@IBAction func followedButtonClick(_ sender: UIButton!) { 

    // Adding row to tag 
    let buttonPosition = (sender as AnyObject).convert(CGPoint.zero, to: self.myTableView) 
    if let indexPath = self.myTableView.indexPathForRow(at: buttonPosition) { 

     // Hiding Status Labels 
     let cell = self.myTableView.cellForRow(at: indexPath) as! CustomCell 
     cell.firstStatusLabel.isHidden = true 
     cell.secondStatusLabel.isHidden = true 

     // Change Following to Follow 
     (sender as UIButton).setImage(UIImage(named: "followed.png")!, for: .normal) 
     cell.followButton.isHidden = false 
     cell.followedButton.isHidden = true 

     self.myTableView.beginUpdates() 

     // Remove identifier into followedIdentifier array 
     self.followedIdentifiers.remove(followedArray[indexPath.row].blogID) 

     // ----- Inserting Cell to mainArray ----- 
     mainArray.insert(followedArray[indexPath.row], at: 0) 
     myTableView.insertRows(at: [IndexPath(row: 0, section: 1)], with: .fade) 

     // ----- Removing Cell from followedArray ----- 
     followedArray.remove(at: indexPath.row) 
     let rowToRemove = indexPath.row 
     self.myTableView.deleteRows(at: [IndexPath(row: rowToRemove, section: 0)], with: .fade) 

     self.myTableView.endUpdates() 

     myTableView.reloadData() 

     // After Updating Table, Save the Archived to UserDefaults 
     saveUserDefaults() 
    } 
} 

// Saving UserDefaults 
func saveUserDefaults() { 

    let key = "followedID" 
    UserDefaults.standard.setValue(self.followedIdentifiers, forKey: key) 
    UserDefaults.standard.synchronize() 
} 

// Load UserDefaults 
func loadUserDefaults() { 

    let key = "followedID" 
    UserDefaults.standard.setValue(Array(self.followedIdentifiers), forKey: key) 
    self.followedIdentifiers = Set(UserDefaults.standard.stringArray(forKey: key)!) 
} 

// Retrieving Data from Server 
func retrieveDataFromServer() { 

    let getDataURL = "http://example.com/receiving.php" 
    let url: NSURL = NSURL(string: getDataURL)! 

    do { 
     let data: Data = try Data(contentsOf: url as URL) 
     let jsonArray = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! NSMutableArray 

     // Clear the arrays 
     self.followedArray = [Blog]() 
     self.mainArray = [Blog()] 

     // Looping through jsonArray 
     for jsonObject in jsonArray { 

      if let blog = Blog.createBlog(from: jsonObject as AnyObject) { 

       // Check if identifiers match 
       if followedIdentifiers.contains(blog.blogID) { 
        self.followedArray.append(blog) 
       } else { 
        self.mainArray.append(blog) 
       } 
      } 
     } 
    } catch { 
     print("Error: (Retrieving Data)") 
    } 
    myTableView.reloadData() 
} 

Blog.swift - 处理的对象博客

import UIKit 

class Blog: NSObject, NSCoding { 

var blogName: String! 
var blogStatus1: String! 
var blogStatus2: String! 
var blogURL: String! 
var blogID: String! 
var blogType: String! 
var blogDate: String! 
var blogPop: String! 

static func createBlog(from jsonObject: AnyObject) -> Blog? { 

    guard let bID: String = jsonObject.object(forKey: "id") as? String, 
     let bName: String = jsonObject.object(forKey: "blogName") as? String, 
     let bStatus1: String = jsonObject.object(forKey: "blogStatus1") as? String, 
     let bStatus2: String = jsonObject.object(forKey: "blogStatus2") as? String, 
     let bURL: String = jsonObject.object(forKey: "blogURL") as? String, 
     let bType: String = jsonObject.object(forKey: "blogType") as? String, 
     let bDate: String = jsonObject.object(forKey: "blogDate") as? String, 
     let bPop: String = jsonObject.object(forKey: "blogPop") as? String 

     else { 
      print("Error: (Creating Blog Object)") 
      return nil 
} 

let blog = Blog() 
    blog.blogName = bName 
    blog.blogStatus1 = bStatus1 
    blog.blogStatus2 = bStatus2 
    blog.blogURL = bURL 
    blog.blogID = bID 
    blog.blogType = bType 
    blog.blogDate = bDate 
    blog.blogPop = bPop 
    return blog 
} 

convenience required init?(coder aDecoder: NSCoder) { 
    self.init() 
    self.blogName = aDecoder.decodeObject(forKey: "blogName") as! String 
    self.blogStatus1 = aDecoder.decodeObject(forKey: "blogStatus1") as! String 
    self.blogStatus2 = aDecoder.decodeObject(forKey: "blogStatus2") as! String 
    self.blogURL = aDecoder.decodeObject(forKey: "blogURL") as! String 
    self.blogID = aDecoder.decodeObject(forKey: "blogID") as! String 
    self.blogType = aDecoder.decodeObject(forKey: "blogType") as! String 
    self.blogDate = aDecoder.decodeObject(forKey: "blogDate") as! String 
    self.blogPop = aDecoder.decodeObject(forKey: "blogPop") as! String 
} 

func encode(with aCoder: NSCoder) { 
    aCoder.encode(blogName, forKey: "blogName") 
    aCoder.encode(blogStatus1, forKey: "blogStatus1") 
    aCoder.encode(blogStatus2, forKey: "blogStatus2") 
    aCoder.encode(blogURL, forKey: "blogURL") 
    aCoder.encode(blogID, forKey: "blogID") 
    aCoder.encode(blogType, forKey: "blogType") 
    aCoder.encode(blogDate, forKey: "blogDate") 
    aCoder.encode(blogPop, forKey: "blogPop") 
} 
} 
+0

它会崩溃在哪一行?使用链接重复中描述的调试技术 – Paulw11

+0

在MainController中,followButtonClick,'self.followedIdentifiers.insert(mainArray [indexPath.row] .blogID)' – BroSimple

+0

因此,使用调试器并计算出哪个值为零 - 是self.followedIdentifiers '无?是'mainArray [indexPath.row] .blogID' nil? – Paulw11

回答

0

你眼前的问题是,你有一个隐含展开可选blogID尚未分配一个值。导致这种情况的根本原因在于您使用隐式解包选项,因为它没有揭示您无法正确初始化Blog实例的位置。

而不是使用静态函数从JSON字典创建Blog,您应该使用failable的初始化程序。这将允许您在适当的情况下使用非可选属性,并在对象未正确初始化时为您提供编译器或运行时错误。

import Foundation 

class Blog: NSObject, NSCoding { 

    var blogName: String 
    var blogStatus1: String 
    var blogStatus2: String 
    var blogURL: String  // Note this should probably be a URL rather than a String 
    var blogID: String 
    var blogType: String 
    var blogDate: String // Note this should probably be a Date rather than a String 
    var blogPop: String 


    private init (name: String,status1: String,status2: String,url: String,id: String,type: String,date: String,pop: String) { 
     blogName = name 
     blogStatus1 = status1 
     blogStatus2 = status2 
     blogURL = url 
     blogID = id 
     blogType = type 
     blogDate = date 
     blogPop = pop 
     super.init() 
    } 

    convenience init?(jsonObject: [String:Any]) { 

     guard let bID = jsonObject["id"] as? String, 
      let bName = jsonObject["blogName"] as? String, 
      let bStatus1 = jsonObject["blogStatus1"] as? String, 
      let bStatus2 = jsonObject["blogStatus2"] as? String, 
      let bURL = jsonObject["blogURL"] as? String, 
      let bType = jsonObject["blogType"] as? String, 
      let bDate = jsonObject["blogDate"] as? String, 
      let bPop = jsonObject["blogPop"] as? String 

      else { 
       print("Error: (Creating Blog Object)") 
       return nil 
     } 

     self.init(name: bName, status1: bStatus1, status2: bStatus2, url: bURL, id: bID, type: bType, date: bDate, pop: bPop) 

    } 

    convenience required init?(coder aDecoder: NSCoder) { 
     guard let blogName = aDecoder.decodeObject(forKey: "blogName") as? String, 
      let blogStatus1 = aDecoder.decodeObject(forKey: "blogStatus1") as? String, 
      let blogStatus2 = aDecoder.decodeObject(forKey: "blogStatus2") as? String, 
      let blogURL = aDecoder.decodeObject(forKey: "blogURL") as? String, 
      let blogID = aDecoder.decodeObject(forKey: "blogID") as? String, 
      let blogType = aDecoder.decodeObject(forKey: "blogType") as? String, 
      let blogDate = aDecoder.decodeObject(forKey: "blogDate") as? String, 
      let blogPop = aDecoder.decodeObject(forKey: "blogPop") as? String else { 
       print("Error: (Creating Blog Object)") 
       return nil 
     } 
     self.init(name: blogName, status1: blogStatus1, status2: blogStatus2, url: blogURL, id: blogID, type: blogType, date: blogDate, pop: blogPop) 
    } 

    func encode(with aCoder: NSCoder) { 
     aCoder.encode(blogName, forKey: "blogName") 
     aCoder.encode(blogStatus1, forKey: "blogStatus1") 
     aCoder.encode(blogStatus2, forKey: "blogStatus2") 
     aCoder.encode(blogURL, forKey: "blogURL") 
     aCoder.encode(blogID, forKey: "blogID") 
     aCoder.encode(blogType, forKey: "blogType") 
     aCoder.encode(blogDate, forKey: "blogDate") 
     aCoder.encode(blogPop, forKey: "blogPop") 
    } 
} 

注意,这可能不会立即解决您的显示ID的问题,但它会帮助你找到你没有正确的初始化实例Blog