swift 2.0中使用故事板的通用控制器 [英] Generic controller in swift 2.0 using storyboards

查看:98
本文介绍了swift 2.0中使用故事板的通用控制器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我有一个ProductListController,它扩展了扩展UIViewController的通用控制器。我已将ProductListController连接到故事板并创建了2个插座,但我总是收到此错误:

 由于未捕获的异常而终止应用程序' NSUnknownKeyException',原因:'[< UIViewController 0x7c158ca0> setValue:forUndefinedKey:]:这个类不是关键字的值,它是关键字searchBar的编码规范。'

我收到所有我的网点的这个错误,如果我从GenericListController中删除通用T它的作品。我想故事板不能用泛型加载超级。



我的代码:

  class GenericListController< T> :UIViewController {

var list:[T] = [T]()
var filteredlist:[T] = [T]()

func getData tableView:UITableView){
.....
}

func setData(list:[T],​​tableView:UITableView){
.....
}
$ b重写func viewDidLoad(){
super.viewDidLoad()
}
}

类ProductListController:GenericListController< ;产品型号GT&; {
@IBOutlet弱变量searchBar:UISearchBar!
@IBOutlet弱var tableView:UITableView!

覆盖func viewDidLoad(){
super.viewDidLoad()

getData(tableView)
}
}

- 编辑 -



我发现如果我扩展一个泛型类并尝试将该类添加到故事板xcode不会自动完成类名称(可能是因为它无法检测该类)

解决方案

这回答了为什么它不可能:在接口构建器中使用泛型类作为自定义视图


Interface Builder通过ObjC运行时与您的代码对话 。因此,IB可以只访问可在ObjC运行时中表示的代码功能。 ObjC不会做泛型


这提示可能的解决方法:
也许你可以在obj-c中创建一个通用的ViewController, c,然后IB会接受它?

您是否考虑过使用协议?这并不影响故事板。稍微改变一下代码,使其易于测试。这个缺点是你不能在协议中存储属性。所以你仍然需要复制粘贴这些。上面是它的工作原理。

 协议GenericListProtocol {
typealias T
var list:[T] { get set)
var filteredlist:[T] {get set}
func setData(list:[T])
}
扩展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] = []

覆盖func viewDidLoad(){
super.viewDidLoad()
setData(list)
}
}






更新:
允许对泛型类的属性进行一些访问。
将其更改为基本班级,以便在Playground中轻松测试。 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 =
}

协议GenericListProtocol {
typealias T = ProductModel
var list:[T] {get set}
var filteredlist:[T] {get set}
func setData(list:[T])
}

扩展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()


Im trying to create a GenericListController for my app.

I have a ProductListController that extend this generic controller which extends UIViewController. I have connected ProductListController to a storyboard and made 2 outlets, but i always receive this error:

 Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<UIViewController 0x7c158ca0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key searchBar.'

I receive this error for all my outlets, if i remove the generic T from GenericListController it works. I guess a storyboard cant load a super with generics. How can i make it work?

My code:

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)
     }
}

--EDIT--

I have found that if i extend an generic class and try to add the class to an storyboard xcode wont autocomplete the class name (probably because it cant detect the class)

解决方案

This answers why it is not possible : use a generic class as a custom view in interface builder

Interface Builder "talks" to your code through the ObjC runtime. As such, IB can can access only features of your code that are representable in the ObjC runtime. ObjC doesn't do generics

This hint at a possible work around : generics in obj-c Maybe you can create a generic ViewController in obj-c and then IB will accept it?

Have you considered using a protocol? This doesn't upset the storyboard. Changed the code a bit to make it easily testable. The downside of this is that you can't have stored properties in a protocol. So you would still need to copy paste those. Upside is that it works.

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)            
    }
}


Update: Allow some access to attributes to the generic class. Changed it to a basic class to easily test in a Playground. UIViewController stuff is in the code above.

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()

这篇关于swift 2.0中使用故事板的通用控制器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆