2017-06-22 4 views
0

Utilisation de Swift 3Swift: Ne pas accéder au code JSON à droite. (trouvé nul lors du déballage)

Erreur provoquant un blocage lorsque je clique sur le bouton followButtonClick dans MainController.swift. blogID se traduit par zéro mais quand j'imprime mainArray tous les objets sont là, donc il y a quelque chose de mal dans mon code que je ne peux pas réparer. blogID n'est pas accessible à droite.

fatal error: unexpectedly found nil while unwrapping an Optional value

Au lieu d'utiliser NSCoder et UserDefaults pour sauver je sauver le suivi blogsID l'ensemble du réseau de mainArray et followedArray, puis afficher ceux que nous sommes sauvés en saisissant les objets qui avaient leurs papiers d'identité enregistrés.

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 - Poignées les objets Blogs

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

quelle ligne ça plante sur? Utilisez les techniques de débogage décrites dans la copie liée – Paulw11

+0

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

+0

Utilisez donc le débogueur et déterminez quelle valeur est nulle - 'self.followedIdentifiers 'nil? est-ce que 'mainArray [indexPath.row] .blogID' nil? – Paulw11

Répondre

0

Votre problème immédiat est que vous avez une option blogID implicitement déballés qui n'a pas été attribué une valeur. La cause sous-jacente de ceci est masquée par votre utilisation d'options optionnelles non enveloppées car elle ne révèle pas l'emplacement où vous ne parvenez pas à initialiser correctement une instance Blog.

Plutôt que d'utiliser une fonction statique pour créer un Blog à partir d'un dictionnaire JSON, vous devez utiliser un initialiseur fable. Cela vous permettra d'utiliser des propriétés non facultatives, le cas échéant, et vous donnera une erreur de compilation ou d'exécution lorsque l'objet n'est pas initialisé correctement.

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") 
    } 
} 

Notez que cela ne peut pas immédiatement résoudre votre problème de montrer l'ID, mais il vous aidera à trouver où vous n'êtes pas le Blog INITIALISATION exemple correctement