Reputation: 890
I am trying to add an item to my array (which was declared as a var), using anything that might work (+=, append, insert), however I keep getting the error 'Immutable value of type 'AnyObject[]' only has mutating members named 'append''.
Here is where the error occurs:
func testSave(item : NSString, date : NSString){
itemsArray.append(item)
UPDATE: HERE IS THE FULL CODE:
import UIKit
class ToDoListTableViewController: UITableViewController, UITableViewDelegate, UITableViewDataSource, UIAlertViewDelegate {
var itemsArray = NSUserDefaults .standardUserDefaults().arrayForKey("items")
var dateArray = NSUserDefaults .standardUserDefaults().arrayForKey("dates")
override func viewDidLoad() {
super.viewDidLoad()
NSUserDefaults .standardUserDefaults().setObject("test", forKey: "items")
NSUserDefaults .standardUserDefaults().setObject("test", forKey: "dates")
self.itemsArray = NSUserDefaults .standardUserDefaults().arrayForKey("items")
self.dateArray = NSUserDefaults .standardUserDefaults().arrayForKey("dates")
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// #pragma mark - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView?) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView?, numberOfRowsInSection section: Int) -> Int {
// Return the number of rows in the section.
if itemsArray{
return itemsArray.count}
else{
return 0}
}
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell!{
//variable type is inferred
/*var cell = tableView.dequeueReusableCellWithIdentifier("Cell") as? UITableViewCell
if !cell {
cell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "Cell")
}
//we know that cell is not empty now so we use ! to force unwrapping
cell!.textLabel.text = self.itemsArray[indexPath.row] as String
cell!.detailTextLabel.text = self.dateArray[indexPath.row] as String
*/
let cell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier:"Cell")
if itemsArray{
println("Working")
cell.textLabel.text = itemsArray[indexPath.row] as String
cell.detailTextLabel.text = dateArray[indexPath.row] as String
}
return cell
}
@IBAction func addItem(sender : UIBarButtonItem) {
var alert = UIAlertController(title: "Alert", message: "Message", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: {(action: UIAlertAction!) in
var stringText = alert.textFields[0].text
var dateText = alert.textFields[0].text
self .testSave(stringText, date: dateText)
}))
alert.addTextFieldWithConfigurationHandler(nil)
self.presentViewController(alert, animated: true, completion: nil)
}
func testSave(item : NSString, date : NSString){
itemsArray.append(item)
/* NSUserDefaults .standardUserDefaults().setObject(item, forKey: "items")
/* NSUserDefaults .standardUserDefaults().setObject(stringText, forKey: "items")
NSUserDefaults .standardUserDefaults().setObject(dateText, forKey: "dates")
NSUserDefaults.standardUserDefaults().synchronize()
*/
self.dateArray = NSUserDefaults .standardUserDefaults().arrayForKey("dates")
self.tableView .reloadData() */
}
func alertviewClick(){
}
}
Upvotes: 3
Views: 28616
Reputation: 2575
If you are doing Mix and Match (gradually migrating from objc to swift)
Then use
nsMutableArray.addObject(nsMutableDictionary)
The replacement of append
you are looking for is addObject
Hope this helps someone in future.
Upvotes: 1
Reputation: 33967
Put this code in the sandbox and you will see that the value "hello" is appended properly. Figuring out what is different between my code and yours will be a great learning experience for you:
class ToDoListTableViewController: UITableViewController /*...*/ {
var itemsArray: Array<AnyObject>!
override func viewDidLoad() {
super.viewDidLoad()
if let savedItems = NSUserDefaults.standardUserDefaults().arrayForKey("items") {
itemsArray = savedItems
}
else {
itemsArray = []
}
}
func testSave(item : NSString, date : NSString) {
itemsArray.append(item)
}
}
let list = ToDoListTableViewController()
list.viewDidLoad()
list.testSave("hello", date: "")
list.itemsArray
Upvotes: 2
Reputation: 3953
It is not that your code is syntactically wrong, it is just that the method "arrayForKey" always gives back an immutable array which you can not modify.
You are trying to append, which modifies the length, hence it is not allowed.
You can verify this in the documentation here is an extract for the return value:
arrayForKey: Returns the array associated with the specified key.
...
Return Value The array associated with the specified key, or nil if the key does not exist or its value is not an NSArray object.
Special Considerations The returned array and its contents are immutable, even if the values you originally set were mutable.
Upvotes: 1
Reputation: 3649
Problem is here:
var itemsArray = NSUserDefaults.standardUserDefaults().arrayForKey("items")
See the Apple's document:
func arrayForKey(_ defaultName: String!) -> AnyObject[]!
But if you are 100% sure that "items" is not an empty NSArray
, then you can downcast it to Array then .append()
will work:
var itemsArray = NSUserDefaults.standardUserDefaults().arrayForKey("items") as Array
If the return object from .arrayForKey()
is nil
or can't be cast to Array (e.g. it's objects can't be casted into Swift type), error will rise as it can't unwrap the optional.
Upvotes: 3
Reputation: 498
Even if you declare something as var it still needs a type to be anything other than AnyObject. Var I believe is just a keyword declaring that that the following identifier (the variable name) is to be inferred by it's assignment
Since you want a Mutable Array try this
var itemsArray: NSMutableArray
or
var itemsArray = NSMutableArray()
Edit: Don't know why I keep getting thumbs down. Now that that the question's been updated it seems that I was right. When you called
NSUserDefaults.standardUserDefaults().arrayForKey("items")
The return type is NSArray. The type inferred for the variable itemsArray is therefore NSArray, which is not mutable. Therefore wrap it in a mutable array
var itemsArray: NSMutableArray = NSMutableArray(array:NSUserDefaults.standardUserDefaults().arrayForKey("items"))
Upvotes: -1
Reputation: 17428
This works fine:
var itemsArray = ["one", "two"]
func testSave(item : NSString, date : NSString){
itemsArray.append(item)
}
testSave("three", "today")
itemsArray
Upvotes: 8