【问题标题】:Adding item to array in iOS with Swift使用 Swift 将项目添加到 iOS 中的数组
【发布时间】:2014-06-09 20:27:19
【问题描述】:

我正在尝试使用任何可能有效的方法(+=、追加、插入)向我的数组(声明为 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(){

    }

}

【问题讨论】:

  • 从错误看来itemsArray 是不可变的。是用let 还是var 定义的?
  • 看来您的问题的原因在于显示的代码之外。您能否显示更多代码,特别是 itemsArray 如何进入范围 - 它是 iVar 吗?从另一个函数收到?本地申报?
  • 我已经用完整的代码更新了我的答案:

标签: ios swift ios8 xcode6


【解决方案1】:

这很好用:

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

    itemsArray.append(item)
}

testSave("three", "today")
itemsArray

【讨论】:

  • 我已经用完整的代码更新了我的问题。你能解释一下我在哪里犯了错误吗?
  • NSUserDefaults.standardUserDefaults().arrayForKey("items") 是一个不可变数组。您需要将 itemsArray 实例化为可变数组,以便允许将项目附加到它。
【解决方案2】:

问题来了:

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

查看苹果的文档:

func arrayForKey(_ defaultName: String!) -> AnyObject[]!
  • 返回的数组及其内容是不可变的,即使 您最初设置的值是可变的。

但如果您 100% 确定“items”不是空的 NSArray,那么您可以将其向下转换为 Array,然后 .append() 将起作用:

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

如果来自.arrayForKey() 的返回对象是nil 或不能转换为数组(例如,它的对象不能转换为 Swift 类型),错误会上升,因为它不能解开可选项。

【讨论】:

    【解决方案3】:

    将此代码放入沙箱中,您将看到正确附加了值“hello”。弄清楚我的代码和你的代码有什么不同对你来说将是一个很好的学习体验:

    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
    

    【讨论】:

      【解决方案4】:

      并不是你的代码语法错误,只是方法“arrayForKey”总是返回一个你不能修改的不可变数组。

      您正在尝试追加,这会修改长度,因此不允许。

      您可以在文档中验证这一点,这里是返回值的摘录:

      arrayForKey:返回与指定键关联的数组。

      ...

      返回 Value 与指定键关联的数组,如果键为 nil 不存在或其值不是 NSArray 对象。

      特殊注意事项 返回的数组及其内容为 不可变,即使您最初设置的值是可变的。

      【讨论】:

        【解决方案5】:

        如果你在做 Mix and Match(逐渐从 objc 迁移到 swift)

        然后使用

        nsMutableArray.addObject(nsMutableDictionary)
        

        你要找的append的替换是addObject

        希望这对将来的人有所帮助。

        【讨论】:

          【解决方案6】:

          即使您将某些东西声明为 var,它仍然需要一个类型,而不是 AnyObject。我相信 Var 只是一个关键字,它声明以下标识符(变量名)将通过它的赋值来推断

          既然你想要一个可变数组试试这个

          var itemsArray: NSMutableArray
          

          var itemsArray = NSMutableArray()
          

          编辑:不知道为什么我一直不赞成。现在问题已经更新,看来我是对的。当你打电话时

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

          返回类型是 NSArray。因此,为变量 itemsArray 推断的类型是 NSArray,它是不可变的。因此将其包装在一个可变数组中

          var itemsArray: NSMutableArray = NSMutableArray(array:NSUserDefaults.standardUserDefaults().arrayForKey("items"))
          

          【讨论】:

          • 这是 Objective-C 数组。没错,但 Swing 有不同的数组。所以除非你需要它们,否则你应该使用 Swift 数组。
          • 我不确定你所说的 Objective-C 数组是什么意思。 NSMutableArray 是 iOS 框架的一部分,所以我想框架的 swift 适配会使用 swift 数组?
          • Objective-C 数组是指 NSArray 或 NSMutableArray ,它们是 Foundation 框架的一部分。 Swift 数组的类型为 Array,它们与 Foundation 框架中的数组无关。
          • 好的,我明白你在说什么。澄清一下,你确定基础框架没有用swift和swift数组重建吗?
          • @Paulw11 - 是的,显然它们是类,我的问题是你有多确定这些类不是使用 swift 数组重建的?
          猜你喜欢
          • 1970-01-01
          • 2020-09-28
          • 2020-07-01
          • 2015-02-21
          • 1970-01-01
          • 2017-10-23
          • 1970-01-01
          • 1970-01-01
          • 2021-04-09
          相关资源
          最近更新 更多