Swift: Reference to a generic class - swift

Here's the code,
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 {
}
The error is:
Cannot assign value of type 'Generic<Object>' to type 'Generic<TestType>!'
I tried many things, like typealias, but can't compile the code.
The problem is that i don't want a Parent<TestType> or Child<TestType> class, since i want to be able to use it in IB.
How can i store a reference of Generic in the Parent, and initialize it in Child (dynamically, by setting the concrete TestType like Object or another)

I finally succeed doing what i wanted!
Not perfect at all, feel free to comment for architecture improvements (especially on the asBaseProtocol() part...)
Here's my complete code (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
class ParentViewController : UIViewController {
public var dataFilter : DataFilter<FIRDataObject>? {
didSet {
dataFilter!.delegate = self
}
}
// Some Functions using dataFilter
}
ChildViewController Class
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
}
}

Related

How to abstract singletons using a Property Wrapper on types?

In a protocol, I'd like to create a single instance from functions so I use a container to store the static instances like this:
protocol MyProtocol {
func networkService() -> NetworkService
}
extension MyProtocol {
func networkService() -> NetworkService {
if Singletons.networkService == nil {
Singletons.networkService = NetworkService(abc: 123)
}
return Singletons.networkService!
}
}
private enum Singletons {
static var networkService: NetworkService?
}
Later on, a type can conform to it and replace the default implementation, but also requires a single instance:
struct MyType: MyProtocol {
private static var networkService: NetworkService?
func networkService() -> NetworkService {
if Self.networkService == nil {
Self.networkService = NetworkService(abc: 555)
}
return Self.networkService!
}
}
What I'm hoping is to encapsulate this ceremony of creating the singleton by using a Property Wrapper, but on the type. I'd like to do something like this:
protocol MyProtocol {
func networkService() -> NetworkService
}
extension MyProtocol {
func networkService() -> NetworkService {
#Singleton
NetworkService(abc: 123)
}
}
////
struct MyType: MyProtocol {
func networkService() -> NetworkService {
#Singleton
NetworkService(abc: 555)
}
}
Is there a way to achieve this or something similar?
Here is my first attempt:
struct Single {
private static var instances = [String: Any]()
static func make<T>(_ instance: () -> T) -> T {
let key = String(describing: type(of: T.self))
guard let value = instances[key] as? T else {
let resolved = instance()
instances[key] = resolved
return resolved
}
return value
}
}
protocol NetworkService {}
struct NetworkDefaultService: NetworkService {
let id = UUID().uuidString
init() {
print("Network Default: \(id)")
}
}
struct NetworkMockService: NetworkService {
let id = UUID().uuidString
init() {
print("Network Mock: \(id)")
}
}
protocol LocationService {}
class LocationDefaultService: LocationService {
let id = UUID().uuidString
init() {
print("Location Default: \(id)")
}
}
protocol NonSingleService {}
struct NonSingleDefaultService: NonSingleService {
let id = UUID().uuidString
init() {
print("Non-Single Default: \(id)")
}
}
protocol Context {
func networkService() -> NetworkService
func locationService() -> LocationService
func nonSingleService() -> NonSingleService
}
extension Context {
func networkService() -> NetworkService {
Single.make {
NetworkDefaultService()
}
}
func locationService() -> LocationService {
Single.make {
LocationDefaultService()
}
}
}
struct AppContext: Context {
func networkService() -> NetworkService {
Single.make {
NetworkMockService()
}
}
func nonSingleService() -> NonSingleService {
NonSingleDefaultService()
}
}
let context = AppContext()
context.networkService()
context.networkService()
context.locationService()
context.locationService()
context.nonSingleService()
context.nonSingleService()
This prints:
Network Mock: 48CBDE3A-26D2-4767-A6AA-F846F8863A52
Location Default: 4846953B-93F6-4025-A970-DA5B47470652
Non-Single Default: 957979D8-9F3E-428E-BD87-B9F45D56B755
Non-Single Default: 816D2886-D606-4558-A842-295C833AE4C8

Referring to own type in Swift?

When in a class, how to refer to the class itself when declaring closure parameters?
In the example below, what type to place in place of Self so that when constructing Foo, the closure parameter also becomes Foo and similarly for AnotherFoo?
class FooBase {
init(completionHandler: (_ myself : Self)) {
// ...
self.completionHandler = completionHandler
}
var completionHandler : ((_ :Self) -> Void)?
func strategyMethod() { ... }
}
class Foo : FooBase {
// ...
override func strategyMethod() {
// do stuff
completionHandler?(self)
}
}
class AnotherFoo : FooBase {
// ...
override func strategyMethod() {
// do other stuff
completionHandler?(self)
}
}
func useFoos {
let foo = Foo(completionHandler: {(me : Foo) in
// ...
})
let anotherFoo = AnotherFoo(completionHandler: {(me : AnotherFoo) in
// ...
})
}
I don't think Swift allows you to do what you want, but you can get close.
Use FooBase as the type, but in the closures you pass to the init functions, cast to the type that you know the parameter is:
class FooBase {
init(completionHandler: #escaping (_ myself : FooBase) -> Void) {
// ...
self.completionHandler = completionHandler
}
var completionHandler : ((_ myself:FooBase) -> Void)?
func strategyMethod() {
}
}
class Foo : FooBase {
// ...
override func strategyMethod() {
// do stuff
completionHandler?(self)
}
}
class AnotherFoo : FooBase {
// ...
override func strategyMethod() {
// do other stuff
completionHandler?(self)
}
}
func useFoos() {
let foo = Foo(completionHandler: {(myself_in : FooBase) in
// This cast should always succeed when the closure is used as intended
if let myself = myself_in as? Foo {
// ...
}
})
let anotherFoo = AnotherFoo(completionHandler: {(myself_in : FooBase) in
// This cast should always succeed when the closure is used as intended
if let myself = myself_in as? AnotherFoo {
// ...
}
})
}

How do I using Generic as parameter and return specific object without casting?

Does function can return specific object, when I input a specific class.
My problem:
I don't know how to return a object. take a look following code and thanks
class MyViewControler {
}
class MySplitViewController: NSSplitViewControler {
override func viewDidLoad() {
/*
* get specific object
*/
let vc = viewController(for: MyViewControler.self)
}
}
extension NSSplitViewController {
public func viewController<T>(for anClass: T) -> T.object {
guard let tClass = anClass as? AnyClass else { return nil }
var vc: NSViewController?
if let idx = self.splitViewItems.index(where: { $0.viewController.classForCoder == tClass} ) {
vc = self.splitViewItems[idx].viewController
}
}
/*
* I don't know how to return a specific object
*/
return vc
}
The signature of a method taking a type and returning an
(optional) instance of that type would be:
public func viewController<T>(for aClass: T.Type) -> T?
or, if you want to restrict it to subclasses of NSViewController:
public func viewController<T: NSViewController>(for aClass: T.Type) -> T?
The implementation can be simplified with optional binding:
extension NSSplitViewController {
public func viewController<T: NSViewController>(for aClass: T.Type) -> T? {
for item in self.splitViewItems {
if let vc = item.viewController as? T {
return vc
}
}
return nil
}
}
Or as a "one-liner":
extension NSSplitViewController {
public func viewController<T: NSViewController>(for aClass: T.Type) -> T? {
return self.splitViewItems.lazy.flatMap { $0.viewController as? T }.first
}
}

Swift find superview of given class with generics

I guess I'm struggling with generics. I want to create simple UIView extension to find recursively a superview of class passed in the function param. I want the function to return optional containing obviously either nil, or object visible as instance of provided class.
extension UIView {
func superviewOfClass<T>(ofClass: T.Type) -> T? {
var currentView: UIView? = self
while currentView != nil {
if currentView is T {
break
} else {
currentView = currentView?.superview
}
}
return currentView as? T
}
}
Any help much appreciated.
Swift 3/4
This is a more concise way:
extension UIView {
func superview<T>(of type: T.Type) -> T? {
return superview as? T ?? superview.compactMap { $0.superview(of: type) }
}
func subview<T>(of type: T.Type) -> T? {
return subviews.compactMap { $0 as? T ?? $0.subview(of: type) }.first
}
}
Usage:
let tableView = someView.superview(of: UITableView.self)
let tableView = someView.subview(of: UITableView.self)
No need to pass in the type of the class you want (at least in Swift 4.1)…
extension UIView {
func firstSubview<T: UIView>() -> T? {
return subviews.compactMap { $0 as? T ?? $0.firstSubview() as? T }.first
}
}
I'm using this.
// Lookup view ancestry for any `UIScrollView`.
if let scrollView = view.searchViewAnchestors(for: UIScrollView.self) {
print("Found scrollView: \(scrollView)")
}
Extension is really a single statement.
extension UIView {
func searchViewAnchestors<ViewType: UIView>(for viewType: ViewType.Type) -> ViewType? {
if let matchingView = self.superview as? ViewType {
return matchingView
} else {
return superview?.searchViewAnchestors(for: viewType)
}
}
}
With this alternative implementation below, you can actually let the call site determine what type to look for, but I found it somewhat unconventional.
extension UIView {
func searchInViewAnchestors<ViewType: UIView>() -> ViewType? {
if let matchingView = self.superview as? ViewType {
return matchingView
} else {
return superview?.searchInViewAnchestors()
}
}
}
You can call it like this.
if let scrollView: UIScrollView = view.searchInViewAnchestors() {
print("Found scrollView: \(scrollView)")
}

Swift Generic issue

I am following this Generic tutorial from Apple https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Generics.html.
But in the end of tutorial. I got some problem with this:
var myStack = Stack<String>()
myStack.push("a")
myStack.push("b")
myStack.push("c")
var arrayOfStrings = ["a", "b", "c"]
if allItemsMatch(myStack, arrayOfStrings) {
print("All items match.")
} else {
print("Not all items match.")
}
at the line if allItemsMatch(myStack, arrayOfStrings), it says:
Cannot invoke 'allItemsMatch' with an argument list of type
'(Stack< String>, [String])'
Here is my code:
import UIKit
struct Stack<Element> {
var items = [Element]()
mutating func push(item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
}
extension Stack {
var topItem: Element? {
return items.isEmpty ? nil : items[items.count - 1]
}
mutating func append(item: Element) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> Element {
return items[i]
}
}
func findIndex<T: Equatable>(array: [T], _ valueToFind: T) -> Int? {
for (index, value) in array.enumerate() {
if value == valueToFind {
return index
}
}
return nil
}
let doubleIndex = findIndex([3.14159, 0.1, 0.25], 9.3)
let stringIndex = findIndex(["Mike", "Malcolm", "Andrea"], "Andrea")
protocol Container {
associatedtype ItemType
mutating func append(item: ItemType)
var count: Int { get }
subscript(i: Int) -> ItemType { get }
}
extension Array: Container {}
func allItemsMatch< C1: Container, C2: Container where C1.ItemType == C2.ItemType, C1.ItemType: Equatable> (someContainer: C1, _ anotherContainer: C2) -> Bool {
if someContainer.count != anotherContainer.count {
return false
}
for i in 0..<someContainer.count {
if someContainer[i] != anotherContainer[i] {
return false
}
}
return true
}
var myStack = Stack<String>()
myStack.push("a")
myStack.push("b")
myStack.push("c")
var arrayOfStrings = ["a", "b", "c"]
if allItemsMatch(myStack, arrayOfStrings) {
print("All items match.")
} else {
print("Not all items match.")
}
Am I missing somewhere?
You never explicitly conform your Stack<Element> struct to your Container protocol. Therefore Swift's strict type safety will prevent you from passing it into a parameter that expects something that conforms to the Container protocol (even if it implicitly conforms).
You can explicitly conform your Stack to Container via an extension. For example:
extension Stack:Container {}