Swift:对泛型类的引用



这是代码,

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 中使用它。

如何在父级中存储泛型的引用,并在子级中初始化它(动态地,通过设置具体的测试类型,如对象或其他(

我终于成功地做了我想做的事!

一点也不完美,请随时评论架构改进(尤其是在asBaseProtocol((部分...

这是我的完整代码(Swift 3.0(

数据过滤器

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

父视图控制器类

class ParentViewController : UIViewController {
    public var dataFilter : DataFilter<FIRDataObject>? {
        didSet {
            dataFilter!.delegate = self
        }
    }
    // Some Functions using dataFilter
}

儿童视图控制器类

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

最新更新