背景
我设计了一个TableViewDataSource
类,为UITableViewDataSource
和UITableViewDelegate
提供了一个实现。您实例化TableViewSection
个对象,这些对象将传递给TableViewDataSource
,用于配置单元格,节标题,句柄选择,行插入等。
TableViewSection
对象有一个名为dataSource: [AnyObject]?
的属性,设置后用于计算节中的行数,并为单元配置块提供一个对象:
// get the section, dequeue a cell for that section, retrieve the item from the dataSource
// ...
tableSection.cellConfigurationBlock?(cell: AnyObject, item: AnyObject?, indexPath: NSIndexPath)
return cell
我想要做的是从我的viewModel
到tableSection.dataSource
分配对数组的引用,让我的viewModel
更新数组,然后更新表格视图。在Swift中,您不能通过引用传递数组。解决方法似乎是使用NSMutableArray
,但随之而来的是类型安全性的损失,以及从Swift到Foundation来回转换对象时的更大认知负担。
工作示例:
let kCellIdentifier = "SomeCellIdentifier"
class MyViewController: UITableViewController {
// Property declarations
@IBOutlet var tableDataSource: TableViewDataSource!
var viewModel: MyViewControllerViewModel = MyViewControllerViewModel()
override func viewDidLoad() {
super.viewDidLoad()
self.setupTableView()
self.refresh()
}
func setupTableView() {
var tableSection = TableViewSection(cellIdentifier: kCellIdentifier)
tableSection.dataSource = self.viewModel.collection
// tableSection configuration
// ...
self.tableDataSource.addSection(tableSection)
}
func refresh() {
self.viewModel
.refresh()
.subscribeNext({ result in
self.tableView.reloadData()
}, error: { error in
self.logger.error(error.localizedDescription)
})
}
}
refresh()
上的viewModel
方法点击了我的API服务,在响应时更新了它的collection
属性,并提供了next
RACSignal
事件的结果(RACSignal
是Reactive Cocoa提供的一个类,除了这一点之外真的是这样。)
我找到了一种解决方法,包括每次进行单次更新时或批量更新后重新分配数据源。
func refresh() {
self.viewModel
.refresh()
.subscribeNext({ result in
self.updateDataSource()
self.tableView.reloadData()
}, error: { error in
self.logger.error(error.localizedDescription)
})
}
func updateDataSource() {
self.tableDataSource.tableSectionForIndex(0)?.dataSource = viewModel.collection
}
此方法有效,但仅作为解决方法暂时使用。随着TableViewDataSource
的增长和变得越来越复杂,这种方法在命令式过程代码中变得越来越复杂,这与我在编写类时要实现的目标相反。
问题
是否有任何解决方法可以坚持使用原生的Swift Array
来实现相当于通过引用传递基础NSArray
或NSMutableArray
?
奖金问题
有人可以为我提供一些类/结构设计技巧,以实现纯Swift中的预期目标吗?
答案 0 :(得分:5)
简单的解决方案是将数组包装在一个类中。类实例通过引用传递,因此问题得到了有效解决:通过对类实例的任何引用对数组的更改会影响数组,如通过每个引用那样看到的类实例。
有问题的类可以非常轻量级 - 基本上,它只是作为一个包装数组的瘦包装器,客户端通过类实例直接访问数组 - 或者恰恰相反,你可以设计管理数组的类,即类故意提供类似于数组的API,以保护客户端免受底层实现的影响。这两种方法都可能是合适的;我当然都做到了。
这是第一种情况的例子。我的模型对象是属于UIDocument子类的数组。我的视图控制器是一个UITableViewController。用户将在表中查看,添加和编辑模型实体。因此,UITableViewController需要访问UIDocument的数组(恰好称为people
)。
在Objective-C中,我的UITableViewController只是对数组self.people
的引用,它是一个NSMutableArray。这只是一个指针,因此self.people
的更改也是对UIDocument people
的更改 - 它们是同一个对象。
在Swift中,我的UITableViewController包含对UIDocument对象self.doc
的引用。这个数组现在是一个Swift数组,内部是"内部"它,所以我可以称之为self.doc.people
。但是,重写太多了!相反,我创建了一个计算变量属性self.people
,它充当self.doc.people
的网关:
var doc : PeopleDocument!
var people : [Person] { // front end for the document's model object
get {
return self.doc.people
}
set (val) {
self.doc.people = val
}
}
哎呀,问题解决了。每当我说self.people.append(newPerson)
之类的内容时,我都会直接传递给UIDocument的模型对象people
,而我实际上是在追加它。因此,代码的外观和工作方式与Objective-C中的相同,完全不用担心。