Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/120.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios swift 2.0中使用故事板的通用控制器_Ios_Swift_Generics_Storyboard_Swift2 - Fatal编程技术网

Ios swift 2.0中使用故事板的通用控制器

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

我正在尝试为我的应用程序创建GenericListController。

我有一个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()