如何使用委托从数据源中删除对象

Posted

技术标签:

【中文标题】如何使用委托从数据源中删除对象【英文标题】:How to Use Delegation to Remove Object from Data Source 【发布时间】:2014-12-09 22:21:42 【问题描述】:

我正在编写我的第一个 ios 应用程序,并且正在学习协议和委托。该应用程序是一个基本的随机响应生成器。当用户摇动设备或点击屏幕时,随机响应应显示在标签中。

目前,我在导航控制器中嵌入了三个视图控制器:MainViewController.swiftSettingsViewController.swiftResponsesViewController.swift

我在MainViewController.swift 中有一个包含响应的数组。我已经成功地将数据传递给第三个视图控制器,即ResponsesViewController.swift,这是一个用于显示存储响应的表格视图。我已将我的第一个视图控制器 MainViewController 设置为我的第三个视图控制器 ResponsesViewController 的委托,并实现了我想从数据模型(responses 数组)中删除所选响应的方法。

我的问题是当我尝试删除一个回复时,我在控制台中收到了fatal error: Cannot index empty buffer。我使用println(responses.count) 确保将数组成功传递给第二个和第三个视图控制器。我在方法viewDidLoad()viewWillAppear()viewDidDisappear() 中的所有三个视图控制器中都放置了println(responses.count) 语句。这表明数据已成功传递,因为数组中有 3 个对象,每个 println() 语句。但是,在我的代表MainViewController.swift 中,当我尝试从数据模型中删除选定的响应时,我不断收到错误消息。我将println(responses.count) 放入此方法中,但它不断返回0 并因错误而崩溃。只有在委托中调用 func responsesViewController(controller: ResponsesViewController, didDeleteResponseAtIndexPath indexPath: NSIndexPath) 时才会发生这种情况 (MainViewController.swift)

这是我的代码:

MainViewController.swift

var responses: [Response] = []
let response1 = Response(text: "String 1")
let response2 = Response(text: "String 2")
let response3 = Response(text: "String 3")

override func viewDidLoad() 
    super.viewDidLoad()
    navigationController?.navigationBarHidden = true
    responses += [response1, response2, response3]


* delegate *
func responsesViewController(controller: ResponsesViewController, didDeleteResponseAtIndexPath indexPath: NSIndexPath) 
    responses.removeAtIndex(indexPath.row)

ResponsesViewController.swift

protocol DeleteResponseDelegate 
func responsesViewController(controller: ResponsesViewController, didDeleteResponseAtIndexPath indexPath: NSIndexPath)


override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) 
    if editingStyle == .Delete 
        delegate?.responsesViewController(self, didDeleteResponseAtIndexPath: indexPath)
        tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
        tableView.reloadData()
    

-编辑-

事实证明,我只需将数组从我的第三个视图控制器传递回我的第一个视图控制器即可解决我的问题。我显然对授权感到困惑。这是我更新的代码,我从数组中删除了该项目,然后将该数组传递回第一个视图控制器:

ResponsesViewController.swift

    override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) 
    if editingStyle == .Delete 
        responses.removeAtIndex(indexPath.row)
        let mainViewController = navigationController?.viewControllers.first as MainViewController
        mainViewController.responses = self.responses
        tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
        tableView.reloadData()
    

【问题讨论】:

对不起,如果我遗漏了什么,但响应是空的,不是吗?即响应1!=响应[0] @chris 我添加了将三个字符串对象插入数组的代码。 所以我收集你将数据传递给其他视图很好,你是如何将它传递回来的? 好问题。我假设 MainViewController 中的响应数组仍然包含创建它的对象。这是不正确的吗?数据是否跨视图控制器传输并且始终只有一个数组实例?这对我来说很有意义,为什么在尝试删除委托中的选定响应时它会是空的。 【参考方案1】:

来自您的评论 -

我假设 MainViewController 中的响应数组仍然 持有创建它的对象。这是不正确的吗?是否 数据跨视图控制器传输,并且只有一个实例 一直数组?

NSArray 也是如此,它是一个对象。 Swift 数组是结构体,结构体是值类型。赋值时会复制值类型。

事实上,Swift 中的所有基本类型——整数、浮点 数字、布尔值、字符串、数组和字典——是值类型, 并作为幕后结构实现。

所有结构和枚举在 Swift 中都是值类型。这表示 您创建的任何结构和枚举实例以及任何值 它们作为属性的类型——在传递时总是被复制 在你的代码中。”

摘自:Apple Inc. “Swift 编程语言”。电子书。 https://itun.es/au/jEUH0.l

【讨论】:

我现在明白,当数组被传递到下一个视图控制器时,它会被复制。但是,我仍然对此感到有些困惑。例如,假设我的初始视图控制器中的数组有 1 个值。然后我将它传递给第二个视图控制器,在其中添加第二个值。这是否意味着初始视图控制器中的数组仍然有一个值,而第二个视图控制器中的数组有两个值,直到我将该数据传递回我的初始视图控制器以便它可以同时具有两个值? 正确。当您传递一个对象时,它会传递对该对象的一个​​实例的引用。当您传递一个值类型(结构、数组、整数)时,该值将被复制,因此您最终会得到一个全新的数组,其中一个元素添加了第二个元素。这就是为什么使用模型对象比使用属性更好的设计

以上是关于如何使用委托从数据源中删除对象的主要内容,如果未能解决你的问题,请参考以下文章

如何从 iOS 应用程序中删除场景委托?

对象 A 如何等待对象 B 在其核心位置委托中完成获取位置数据,以便它可以使用数据?

如何将应用程序委托添加回 mainwindow.xib

如何使用 Hibernate 从 Sql 数据库中更新、删除对象?

如何从 MethodInfo 创建 Action 委托?

使用LINQLambda 表达式 委托快速比较两个集合,找出需要新增修改删除的对象