这是代码,
protocol TestType : AnyObject {
}
class Generic<TestType> : NSObject {
private let filterFunction : (TestType,String) -> Bool
init(filter: @escaping (TestType,String) -> Bool) {
filterFunction = filter
}
}
class Parent : UIViewController {
public var generic : Generic<TestType>!
}
class Child : Parent {
override func viewDidLoad() {
// ERROR THIS LINE
generic = Generic<Object>(filter: { (str1, str2) -> Bool in
return true
})
}
}
class Object : TestType {
}
错误是:
Cannot assign value of type 'Generic<Object>' to type 'Generic<TestType>!'
我尝试了许多东西,比如typealias,但是无法编译代码。
问题是我不想要Parent<TestType>
或Child<TestType>
类,因为我希望能够在IB中使用它。
如何在Parent中存储Generic的引用,并在Child中初始化它(动态地,通过设置具体的TestType,如Object或其他)
答案 0 :(得分:0)
我终于成功做了我想要的事情!
根本不完美,随意评论架构改进(特别是在asBaseProtocol()部分......)
这是我的完整代码( Swift 3.0 )
<强> DataFilter 强>
protocol DataFilterDelegate : class {
func didFilter()
func didUpdateItems()
}
class DataFilter<T> {
public weak var delegate : DataFilterDelegate?
private var items : [SelectableItem<T>]?
private var filteredItems : [SelectableItem<T>]?
var source: [SelectableItem<T>]? {
get {
if filteredItems != nil {
return filteredItems
}
return items
}
}
var filter : (T,String) -> Bool
var populateCell : (T) -> UITableViewCell
init(filter : @escaping (T,String) -> Bool, populateCell: @escaping (T) -> UITableViewCell) {
self.filter = filter
self.populateCell = populateCell
}
func updateItems(_ items: [T]) {
self.items = [SelectableItem<T>]()
for item in items {
self.items?.append(SelectableItem(item))
}
delegate?.didUpdateItems()
}
func filterItems(text : String) {
filteredItems = (text == "") ? nil : items?.filter { item in
filter(item.item, text)
}
delegate?.didFilter()
}
func selectedItems() -> [T]? {
guard let items = items else {
return nil
}
var selectedItems = [T]()
for item in items {
if item.isSelected {
selectedItems.append(item.item)
}
}
return selectedItems
}
}
extension DataFilter where T : FIRDataObject {
func asBaseProtocol() -> DataFilter<FIRDataObject> {
return DataFilter<FIRDataObject>(filter: filterAsBaseProtocol(), populateCell: populateCellAsBaseProtocol())
}
private func filterAsBaseProtocol() -> ((FIRDataObject,String) -> Bool) {
return { (object, text) -> Bool in
self.filter(object as! T, text)
}
}
private func populateCellAsBaseProtocol() -> ((FIRDataObject) -> UITableViewCell) {
return { (object) -> UITableViewCell in
self.populateCell(object as! T)
}
}
}
ParentViewController类
class ParentViewController : UIViewController {
public var dataFilter : DataFilter<FIRDataObject>? {
didSet {
dataFilter!.delegate = self
}
}
// Some Functions using dataFilter
}
ChildViewController类
class ChildViewController : Parent {
// Stored as a variable to not have to cast objects to the good type everytime I access dataFilter
private var patientDataFilter = DataFilter<Patient>(filter: { patient, text in
patient.firstname.contains(text) ||
patient.lastname.contains(text)
}
, populateCell: { patient in
let cell = UITableViewCell(style: .subtitle, reuseIdentifier: "Patient")
cell.textLabel?.text = patient.lastname + " " + patient.firstname
cell.detailTextLabel?.text = patient.postalCode + " " + patient.city
return cell
})
override func viewDidLoad() {
super.viewDidLoad()
dataFilter = patientDataFilter.asBaseProtocol()
}
func someFunc() {
let patient1 = patientDataFilter.source[0].item
// OR
let patient2 = dataFilter.source[0].item as! Patient
}
}