Добавление элемента в массив в iOS с помощью Swift

Я пытаюсь добавить элемент в свой массив (который был объявлен как var), используя все, что может работать (+=, добавить, вставить), однако я продолжаю получать сообщение об ошибке «Неизменяемое значение тип «AnyObject[]» имеет только изменяющиеся члены с именем «append».

Вот где возникает ошибка:

func testSave(item : NSString, date : NSString){

    itemsArray.append(item) 

ОБНОВЛЕНИЕ: ЗДЕСЬ ПОЛНЫЙ КОД:

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(){

    }

}

person Jack Solomon    schedule 09.06.2014    source источник
comment
Из ошибки кажется, что itemsArray неизменен. Он определяется с помощью let или var?   -  person Jack    schedule 10.06.2014
comment
Кажется, что причина вашей проблемы лежит за пределами показанного кода. Можете ли вы показать больше кода, в частности, как itemsArray входит в область действия - это iVar? получено от другой функции? Заявлено локально?   -  person Paulw11    schedule 10.06.2014
comment
Я обновил свой ответ полным кодом:   -  person Jack Solomon    schedule 10.06.2014


Ответы (6)


Это отлично работает:

var itemsArray = ["one", "two"]
func testSave(item : NSString, date : NSString){

    itemsArray.append(item)
}

testSave("three", "today")
itemsArray
person Dash    schedule 09.06.2014
comment
Я обновил свой вопрос с полным кодом. Можете ли вы объяснить, где я сделал ошибку? - person Jack Solomon; 10.06.2014
comment
NSUserDefaults.standardUserDefaults().arrayForKey(items) — неизменяемый массив. Вам нужно создать экземпляр itemsArray как изменяемый массив, чтобы иметь возможность добавлять к нему элементы. - person Dash; 30.05.2015

Проблема здесь:

var itemsArray = NSUserDefaults.standardUserDefaults().arrayForKey("items")

См. документ Apple:

func arrayForKey(_ defaultName: String!) -> AnyObject[]!
  • Возвращаемый массив и его содержимое являются неизменяемыми, даже если значения, которые вы изначально установили, были изменяемыми.

Но если вы на 100% уверены, что "items" не является пустым NSArray, то вы можете преобразовать его в массив, тогда .append() будет работать:

var itemsArray = NSUserDefaults.standardUserDefaults().arrayForKey("items") as Array

Если возвращаемый объект из .arrayForKey() равен nil или не может быть приведен к массиву (например, его объекты не могут быть преобразованы в тип Swift), возникнет ошибка, поскольку он не может развернуть необязательное.

person Cai    schedule 25.06.2014

Поместите этот код в песочницу, и вы увидите, что значение «привет» добавлено правильно. Выяснение того, чем мой код отличается от вашего, будет для вас отличным опытом:

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
person Daniel T.    schedule 18.10.2014

Дело не в том, что ваш код синтаксически неверен, просто метод "arrayForKey" всегда возвращает неизменяемый массив, который вы не можете изменить.

Вы пытаетесь добавить, что изменяет длину, поэтому это не разрешено.

Вы можете проверить это в документации, вот выдержка для возвращаемого значения:

arrayForKey: возвращает массив, связанный с указанным ключом.

...

Возвращаемое значение Массив, связанный с указанным ключом, или nil, если ключ не существует или его значение не является объектом NSArray.

Особые замечания Возвращаемый массив и его содержимое неизменяемы, даже если значения, которые вы изначально установили, были изменяемыми.

person iQ.    schedule 11.07.2014

Если вы делаете Mix and Match (постепенно переходите с objc на swift)

Затем используйте

nsMutableArray.addObject(nsMutableDictionary)

Замена append, которую вы ищете, это addObject

Надеюсь, это поможет кому-то в будущем.

person jeet.chanchawat    schedule 28.04.2016

Даже если вы объявите что-то как var, ему все равно нужен тип, отличный от AnyObject. Я считаю, что Var - это просто ключевое слово, объявляющее, что следующий идентификатор (имя переменной) должен быть выведен путем его назначения.

Поскольку вам нужен изменяемый массив, попробуйте это

var itemsArray: NSMutableArray

or

var itemsArray = NSMutableArray()

Редактировать: Не знаю, почему я продолжаю опускать большие пальцы. Теперь, когда вопрос был обновлен, кажется, что я был прав. Когда ты позвонил

NSUserDefaults.standardUserDefaults().arrayForKey("items")

Тип возвращаемого значения — NSArray. Таким образом, для переменной itemsArray выводится тип NSArray, который не является изменяемым. Поэтому оберните его в изменяемый массив

var itemsArray: NSMutableArray = NSMutableArray(array:NSUserDefaults.standardUserDefaults().arrayForKey("items"))
person Literphor    schedule 09.06.2014
comment
Это массив Objective-C. Это не так, но Swing получил разные массивы. Поэтому, если они вам не нужны, вы должны использовать массивы Swift. - person Tomáš Linhart; 10.06.2014
comment
Я не уверен, что вы подразумеваете под массивом Objective-C. NSMutableArray является частью фреймворка iOS, поэтому я могу предположить, что быстрая адаптация фреймворка будет использовать быстрые массивы? - person Literphor; 10.06.2014
comment
Под массивом Objective-C я подразумеваю NSArray или NSMutableArray, которые являются частью фреймворка Foundation. Массивы Swift имеют тип Array‹T›, и они не связаны с массивами, найденными в структуре Foundation. - person Tomáš Linhart; 10.06.2014
comment
Хорошо, я понимаю, что вы говорите. Просто для уточнения, вы уверены, что базовая структура не была перестроена с использованием быстрых и быстрых массивов? - person Literphor; 10.06.2014
comment
NSAarray и NSMutableArray — это классы. массивы swift являются встроенным типом в Swift. Это похоже на разницу между Vector или ArrayList в Java и массивом Java. - person Paulw11; 10.06.2014
comment
@Paulw11Paulw11 - Да, очевидно, это классы, мой вопрос: насколько вы уверены, что эти классы не были перестроены с использованием быстрых массивов? - person Literphor; 11.06.2014
comment
Почему я опускаю палец? После того, как оригинальный постер обновил свой вопрос, кажется, что у меня есть правильное решение. Некоторое объяснение было бы неплохо. - person Literphor; 11.06.2014
comment
@Literphor Я сделал то, что вы предложили для NSMutableArray, и это не вызвало ошибок, однако я все еще получаю ту же ошибку, когда пытаюсь добавить элемент в массив. Не уверен, почему вы опускаете пальцы, ответ был полезным, просто не избавился от ошибок. Спасибо за вашу помощь! :) - person Jack Solomon; 11.06.2014
comment
@Literphor, в дополнение к моему предыдущему комментарию, вот новое сообщение об ошибке: «NSMutableArray» не имеет члена с именем «append»… - person Jack Solomon; 11.06.2014
comment
@JackSolomon Ну да, в NSMutableArray нет члена с именем append. Чтобы добавить к нему объект, вы используете метод addObject: или insterObject:atIndex: - person Literphor; 12.06.2014