Ios swift 2.0中使用故事板的通用控制器
我正在尝试为我的应用程序创建GenericListController。Ios swift 2.0中使用故事板的通用控制器,ios,swift,generics,storyboard,swift2,Ios,Swift,Generics,Storyboard,Swift2,我正在尝试为我的应用程序创建GenericListController。 我有一个ProductListController,它扩展了这个扩展UIViewController的通用控制器。我已将ProductListController连接到情节提要并制作了2个插座,但我始终收到以下错误: Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<UIViewController 0x7c1
我有一个ProductListController,它扩展了这个扩展UIViewController的通用控制器。我已将ProductListController连接到情节提要并制作了2个插座,但我始终收到以下错误:
Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<UIViewController 0x7c158ca0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key searchBar.'
由于未捕获的异常“NSUnknownKeyException”而终止应用程序,原因:“[setValue:forUndefinedKey:]:此类不符合密钥搜索栏的键值编码。”
如果我从GenericListController中删除generic T,则我的所有插座都会收到此错误。我猜故事板无法加载带有泛型的超级脚本。我怎样才能让它工作
我的代码:
class GenericListController<T> : UIViewController {
var list : [T] = [T]()
var filteredlist : [T] = [T]()
func getData(tableView : UITableView) {
.....
}
func setData(list : [T], tableView : UITableView) {
.....
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
class ProductListController : GenericListController<ProductModel> {
@IBOutlet weak var searchBar: UISearchBar!
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
getData(tableView)
}
}
类GenericListController:UIViewController{
变量列表:[T]=[T]()
变量筛选器列表:[T]=[T]()
func getData(表视图:UITableView){
.....
}
func setData(列表:[T],表视图:UITableView){
.....
}
重写func viewDidLoad(){
super.viewDidLoad()
}
}
类ProductListController:GenericListController{
@ibvar搜索栏:UISearchBar!
@IBVAR表格视图:UITableView!
重写func viewDidLoad(){
super.viewDidLoad()
getData(tableView)
}
}
--编辑--
我发现,如果我扩展一个泛型类并尝试将该类添加到情节提要xcode中,则不会自动完成类名(可能是因为它无法检测到该类)这回答了为什么不可能: 接口生成器通过ObjC运行时与代码“对话”。因此,IB只能访问可在ObjC运行时表示的代码特性。ObjC不做泛型 这暗示了可能的解决方法: 也许您可以在obj-c中创建一个通用的ViewController,然后IB会接受它 你考虑过使用协议吗?这并没有打乱故事板。稍微修改了代码,使其易于测试。这样做的缺点是不能在协议中存储属性。所以你仍然需要复制粘贴它们。好的一面是它可以工作
protocol GenericListProtocol {
typealias T
var list : [T] { get set }
var filteredlist : [T] { get set }
func setData(list : [T])
}
extension GenericListProtocol {
func setData(list: [T]) {
list.forEach { item in print(item) }
}
}
class ProductModel {
var productID : Int = 0
init(id:Int) {
productID = id
}
}
class ProductListController: UIViewController, GenericListProtocol {
var list : [ProductModel] = [ProductModel(id: 1),ProductModel(id: 2),ProductModel(id: 3),ProductModel(id: 4)]
var filteredlist : [ProductModel] = []
override func viewDidLoad() {
super.viewDidLoad()
setData(list)
}
}
更新: 允许对泛型类的属性进行某些访问。 将其改为基础课程,以便在操场上轻松测试。UIViewController的内容在上面的代码中
class ProductModel {
var productID : Int = 0
init(id:Int) {
productID = id
}
}
class ProductA : ProductModel {
var aSpecificStuff : Float = 0
}
class ProductB : ProductModel {
var bSpecificStuff : String = ""
}
protocol GenericListProtocol {
typealias T = ProductModel
var list : [T] { get set }
var filteredlist : [T] { get set }
func setData(list : [T])
}
extension GenericListProtocol {
func setData(list: [T]) {
list.forEach { item in
guard let productItem = item as? ProductModel else {
return
}
print(productItem.productID)
}
}
}
class ProductListController: GenericListProtocol {
var list : [ProductA] = [ProductA(id: 1),ProductA(id: 2),ProductA(id: 3),ProductA(id: 4)]
var filteredlist : [ProductA] = []
init() {
setData(list)
}
}
var test = ProductListController()
我会在用户R menke和其他人的帮助下发布一些我存档的代码。 我的目标是拥有一个GenericListProtocol,它可以处理UISearchBarDelegate、UITableViewDelegate和我的getData方法(需要一个类型类才能正确解析json)
import Foundation
import UIKit
protocol GenericListProtocol : UISearchBarDelegate, UITableViewDelegate{
typealias T : MyModel // MyModel is a model i use for getId, getDate...
var list : [T] { get set }
var filteredlist : [T] { get set }
var searchActive : Bool { get set }
func setData(tableView : UITableView, myList : [T])
func setData()
func getData(tableView : UITableView, objectType : T, var myList : [T])
func filterContentForSearchText(searchText: String)
}
extension GenericListProtocol {
func setData(atableView : UITableView, myList : [T]) {
print("reloading tableView data")
atableView.reloadData()
}
func getData(tableView : UITableView, objectType : T, var myList : [T]) {
let dao: GenericDao<T> = GenericDao<T>()
let view : UIView = UIView()
let c: CallListListener<T> = CallListListener<T>(view: view, loadingLabel: "loading", save: true, name: "ProductModel")
c.onSuccess = { (onSuccess: JsonMessageList<T>) in
print("status " + onSuccess._meta!.status!) // this is from my ws
myList = onSuccess.records
self.setData(tableView, myList: myList)
}
c.onFinally = { (any: AnyObject) in
// tableView.stopPullToRefresh()
}
// my dao saves json list on NSUSER, so we check if its already downloaded
let savedList = c.getDefaultList()
if (savedList == nil) {
dao.getAll(c);
}
else {
myList = savedList!
print(String(myList.count))
self.setData(tableView, myList: myList)
}
}
func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
searchActive = true;
}
func searchBarTextDidEndEditing(searchBar: UISearchBar) {
searchActive = false;
}
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
searchActive = false;
}
func searchBarSearchButtonClicked(searchBar: UISearchBar) {
searchActive = false;
}
func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
print("searching")
self.filterContentForSearchText(searchText)
if(filteredlist.count == 0){
searchActive = false;
} else {
searchActive = true;
}
self.setData()
}
}
*GenericListController只是一个UIViewController,它有一些助手方法,如上面@r-menke所述: 接口生成器通过ObjC运行时与代码“对话”。因此,IB只能访问可在ObjC运行时表示的代码功能。ObjC不做泛型 这是真的, 然而,根据我的经验,我们可以绕过这个问题如下(YMMV) 我们可以在这里做一个人为的例子,看看它是如何失败的:
class C<T> {}
class D: C<String> {}
print(NSClassFromString("main.D"))
我们得到这个:
nil
可选(main.D)
嘿,哦!它是在第一次初始化后发现的
让我们把这个应用到故事板上。我现在正在一个应用程序中这样做(正确或错误)
正如您所期望的那样工作。在我的情况下,我的canvasconnector
声明如下:
class CanvasController: MyNSViewController<SomeGeneric1, SomeGeneric2>
class CanvasController:MyNSViewController
现在,我在iOS上遇到了一些问题,使用这种技术和一个通用的UITableView子类。我没有在iOS 9下尝试过,所以YMMV。但我目前在10.11下为一个我正在开发的应用程序做这件事,并且没有遇到任何重大问题。这并不是说我将来不会遇到任何问题,或者说这是适当的我不能说我知道这件事的全部后果。我所能说的是,目前,它似乎回避了这个问题
8月4日,我在上面提交了一份radr:#22133133我在open radr中没有看到它,但在bugreport.apple.com下,它至少在我的帐户下列出了,不管它值多少钱。作为一种解决方法,你可以在用故事板实例化它之前,将你的
ProductListController
加载到ObjC运行时(即AppDelegate?)
ProductListController.load()
干杯为什么需要在UIViewController中添加泛型模型?因为我的列表控制器的逻辑总是相同的,它只是更改了对象的类型。我将让productList、saleList、userList,所有它们共享相同的方法和逻辑。对于DetailsController、AddController也是如此。如果我不能使用泛型,我将不得不复制和删除它们将我的getData函数粘贴到我创建的每个新控制器中(其中我有需要类型的dao方法)。@sagits我想知道这一切有多有用,因为您无法访问泛型类型的任何属性(在本例中为ProductModel)。不是用你的方法,也不是用我的方法?你是否也在创建一个所有T都将遵循的基本类?因此,只需设计你的自定义UIViewController子类,这样它就可以处理你所有类型的列表。如果需要,你还可以进一步对它进行子类化,为每种类型的列表添加自定义位,同时仍然使用ut必须将它们“复制粘贴”到每个子类中。@sagits在不包含IB Outlet时会运行吗?我猜不会。原因如下。您好,我试图实现您的答案,但我不需要在t:MyModel(这个类包含getId方法)的地方运行,可能吗?我知道这看起来很奇怪,但我需要将确切的类类型传递给我的getData,这样它就可以从webservice解析json并返回类型化列表(这是实现其他泛型方法所必需的)@sagits我认为您使用泛型是错误的。当操作符合Y的对象中的X时,泛型是非常棒的。替换所有子类是没有用的。在您的情况下,子类仍然是可行的。但是用一种方法更新了答案
// do the initial throw away load
let _ = CanvasController(nibName: "", bundle: nil)
// Now lets load the storyboard
let sb = NSStoryboard(name: "Canvas", bundle: nil)
let canvas = sb.instantiateInitialController() as! CanvasController
myView.addSubView(canvas.view)
class CanvasController: MyNSViewController<SomeGeneric1, SomeGeneric2>
ProductListController.load()