Search code examples
iosswiftnsarraynsuserdefaultssigabrt

[__NSCFArray insertObject:atIndex:]: mutating method sent to immutable object', Thread: SIGABRT


I was building a To-do-list app. And when I press the "Add Task" button, my app crashes and gives me the following error:

[__NSCFArray insertObject:atIndex:]: mutating method sent to immutable object'

It also returns me to Thread SIGABRT error. Any help would be appreciated.

Here is my SecondViewController

class SecondViewController: UIViewController, UITextFieldDelegate {
    @IBOutlet weak var taskValue: UITextField!
    @IBAction func addTask(_ sender: Any) {
        let itemsObject = UserDefaults.standard.object(forKey: "items")

        var items:NSMutableArray!

        if let tempItems = itemsObject as? NSMutableArray{
            items = tempItems
            items.addObjects(from: [taskValue.text!])
        } else{
            items = [taskValue.text!]
        }

        UserDefaults.standard.set(items, forKey: "items")

        taskValue.text = ""
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.view.endEditing(true)
    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return true
    }
}

My first view controller is here:

class FirstViewController: UIViewController, UITableViewDataSource, UITableViewDelegate{
    var items: NSMutableArray = []

    //table view
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return items.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cellContent = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "Cell")

        var cellLabel = ""

        if let tempLabel = items[indexPath.row] as? String{
            cellLabel = tempLabel
        }
        cellContent.textLabel?.text = cellLabel
        return cellContent
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        let itemsObject = UserDefaults.standard.object(forKey: "items")

        if let tempItems = itemsObject as? NSMutableArray{
            items = tempItems
        }
    }
}

Solution

  • The error occurs because you can't cast a Swift array to NSMutableArray. Don't use NSMutable... Foundation types in Swift at all.

    In Swift it's very easy to get a mutable object, just use the var keyword.

    And UserDefaults has a dedicated method to get a string array.

    @IBAction func addTask(_ sender: Any) {
    
        var items : [String]
        if let itemsObject = UserDefaults.standard.stringArray(forKey: "items") {
            items = itemsObject
            items.append(taskValue.text!) // it's pointless to use the API to append an array.
        } else{
            items = [taskValue.text!]
    
        }
        UserDefaults.standard.set(items, forKey: "items")
        taskValue.text = ""
    
    }