2

我正在尝试以UITableViewControllerRealmResults<Object>作为模型构建一个泛型。

这些是我的简化课程:

领域对象:

import RealmSwift

class Test: Object {

  dynamic var name = ""

}

表视图单元:

import UIKit
import RealmSwift

class RealmCell: UITableViewCell {
  typealias Entity = Test // from above

  var object: Entity? {
    didSet {
      if let object = object {
        textLabel?.text = object.name
      }
    }
  }

}

表视图控制器:

import UIKit
import RealmSwift

class RealmTableViewController: UITableViewController {

  typealias TableCell = RealmCell // From example above            
  var objects = try! Realm().objects(TableCell.Entity.self) {
    didSet { tableView.reloadData() }
  }

  // MARK: - UITableViewDataSource

  override func numberOfSections(in tableView: UITableView) -> Int {
    return 1
  }

  override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return objects.count
  }

  override func tableView(_ tableView: UITableView,
                          cellForRowAt indexPath: IndexPath)
    -> UITableViewCell {

      let cell =
        tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableCell

      cell.object = objects[indexPath.row]

      return cell
  }
}

我想不出办法让 TableCell 类型别名为@IBInspectable。我一直在尝试使用NSClassFromString(_:)没有成功。

希望有人可以提供帮助。

4

1 回答 1

3

如果我理解正确,您基本上希望能够在 Interface Builder 中指定实体名称,是吗?即您希望能够从检查员中基本上选择您的自定义类?

如果是这样,那么不幸的是,这不是直接可能的。@IBInspectable 只能用于特定类型,如此处所述

您可以将 IBInspectable 属性添加到类声明、类扩展或类型类别中的任何属性:布尔值、整数或浮点数、字符串、本地化字符串、矩形、点、大小、颜色、范围和 nil。

但是,您可以将字符串属性指定为 IBInspectable(具有有意义的默认值),并在您的初始化程序中从中扣除类。这将留下错误的可能性,即错字,但它仍然可以工作。

另请参阅答案。

在您发表评论后进行编辑:在这种情况下,我担心这是不可能的(至少据我所知,可能存在一些我不知道的深层黑客,但这可能会丑陋得要命)。问题是 IB 中指定的内容只能在运行时评估,而 typealias 是在编译时定义的。

我认为您基本上想要的只是每个单元类应具有的功能的协议(以及通用视图控制器所依赖的)。你甚至不需要类型别名,因为协议本身就是一种类型。

然后可以基于IBInspectable-ed 字符串选择具体的单元类,协议甚至可以为此定义一个方法。

根据您场景的详细信息,您甚至可以为所有单元格编写一个公共超类。一个已经采用(部分)协议的协议(在这种情况下你甚至可以省略协议,但我建议使用一个以提高可读性)。

这显然假设您已经为通用单元格定义了视图控制器所需的所有功能,但这在任何情况下都是您面临的问题(即使您可以使用在运行时定义的类型别名)。


我查看了您的示例代码后的第二次编辑:

好的,我又看了一遍,希望现在可以更好地解释这一点。不幸的是,我不能直接添加到您的存储库,因为它没有编译(我缺少 Realm 框架/pod,即使我添加了我可能不会赢得任何东西,因为我不知道你到底用它做什么)。

正如评论中所说,我想说你不需要任何进一步的 IBInspectable 属性来设置一个类。这应该已经发生在您的故事板中,即您应该将给定原型单元的类值设置为您拥有的具体单元类之一。但是,您的泛型RealmTableViewController不需要知道该类。如果我对您的理解正确,您似乎想告诉它知识,可能是让它根据其具体特征正确准备细胞。不要那样做(我会马上了解你想做的事情viewDidLoad)。相反,定义一个所有单元都采用并且RealmTableViewController知道的协议。在您的tableView(_:cellForRowAt:)方法中,您在as! ...出列单元格时的一部分。协议应该定义每个具体类应该实现的准备方法,然后由RealmTableViewController.

这样,您的表格视图控制器保持通用,它并不真正了解它显示的单元格,这就是事情的意图。

现在到您(我认为)面临的问题:您想让控制器知道它使用哪种原型单元,以便它也可以准备特定的东西(例如,您也可以将其外包到协议中)。这是有问题的,因为您基本上是在尝试构建表格视图控制器的核心方面:它能够同时处理不同类型的单元。我从您的其他代码中得出了这一结论,inviewDidLoadobjects属性,最终似乎也取决于单元格的类。这与表架构本身的设计相冲突,而不仅仅是句法问题。但是,有一个解决方案:另一个协议,加上具体单元类的“伴侣”类。

对于您拥有的每个单元类,定义相应的类来处理您的视图控制器需要做的领域事情。也许对于某些单元格,您具有相同的对象,然后相应地编写它们(新类应该具有定义它对应于哪个单元格的属性)。定义一个所有人都采用的协议,并且至少有两种方法(也许使用更好的名称,这里已经很晚了......):doControllerStuffgetCellIdentifier.

然后你RealmTableViewController终于得到了一个 IBInspectable 如果设置了,控制器将伴随对象实例化到单元格(使用哪个具体类显然取决于 IBInspectable 的值)。如果同一个同伴处理多个单元,IBInspectable 还必须定义将使用哪个单元,即必须正确配置同伴。您可以使用某种字符串约定,或者甚至编写一个工厂类,将具体类从视图控制器中隐藏起来,并只将其返回一个类型为协议的正确对象。

无论如何,到目前为止,无论您基于该类做什么,都将其更改为methodviewDidLoaddoControllerStuff。如果在单元格/同伴中很常见,您甚至可能有一些超类和子类,这没关系。最后,在您的 `tableView(_:cellForRowAt:) 方法中,您不直接使用标识符,而是向伴随对象询问标识符。

不过这里有一点警告:您显然必须确保正确设置单元标识符的界面构建器值,即它与您在视图控制器实例中设置的 IBInspectable 匹配。不过,您可以围绕此编写一个 catch 并使用默认单元格,即简单地抛出一个异常。


这已经变得很长了,尽管如此,我希望它是可以理解的。我没有时间为这个或其他东西制作漂亮的图形,所以如果你还有问题,我建议我们用这个来聊天。:) 只要 ping 我,我们就会(尽管从明天开始我有点空闲)。

于 2017-05-15T12:20:55.093 回答