danutha danutha - 1 month ago 9
iOS Question

Could not cast value of type 'NSTaggedPointerString' to an array

I working on a project that is written in

swift 3.0
. My requirement is to save data that i enter on some text fields and populate one of those attributes in to a table view, and once a row is selected I wants to update that records (re-assign values on my text fields).

However im having an issue with my code when i try to fetch data that i have saved in
core data
and assigning them in to an array. Basically I have an entity named "Task" and it got three attributes, and since i wants to populate one of those attributes(called "name") that i have saved on core data, to a table view i have written the code as follow. But im getting an exception in the following line in my code saying "
Could not cast value of type NSTaggedPointerString (0x10d8f7b90) to NSArray (0x10d8f7c58)
".

The error line and the code as bellow.


tasks += expName as! [Task]


Here is my full code:

import UIKit
import CoreData

class TableViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {

@IBOutlet weak var tableView: UITableView!

let appDelegate : AppDelegate = UIApplication.shared.delegate as! AppDelegate
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext

var tasks = [Task] ()

override func viewDidLoad() {
super.viewDidLoad()

// Do any additional setup after loading the view.
}

override func viewDidAppear(_ animated: Bool) {

//var error : NSError?
let request = NSFetchRequest <NSFetchRequestResult> (entityName: "Task")
request.returnsObjectsAsFaults = false
do {

let results = try context.fetch(request)
// check data existance
if results.count>0 {
print(results.count)

for resultGot in results as! [NSManagedObject]{

if let expName = resultGot.value(forKey:"name"){
print("expence name is :", expName)
tasks += expName as! [Task]
print("my array is : \(tasks)")
}
}
}
}catch{
print("No Data to load")
}
self.tableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = tasks [indexPath.row] as? String
return cell
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tasks.count
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ShowEditTask"{
let v = segue.destination as! ViewController
let indexPath = self.tableView.indexPathForSelectedRow
let row = indexPath?.row


}
}

Answer

The error message says that NSTaggedPointerString (expName) can not be casted to NSArray ([Task])

Your goal is to add all Tasks to the task array if the name property is not nil but you're trying to add the name which causes the error.

Some suggestions:

fetch(context: returns always an array of the NSManagedObject subclass so cast it immediately.

Since you are using NSManagedObject subclass get the name property directly rather than with valueForKey.

The check for > 0 is not needed because the loop will be skipped in case of an empty array.

  let results = try context.fetch(request) as! [Task]
  // check data existance
  print(results.count)

  for task in results {
     if let expName = task.name {
        print("expence name is :", expName)
        tasks += task      
        print("my array is : \(tasks)")
     }
  }    

or shorter

 let results = try context.fetch(request) as! [Task]
 tasks.filter{ $0.name != nil  }

The most efficient way is to filter the tasks before the fetch via an appropriate predicate.