Skip to content

Instantly share code, notes, and snippets.

@JRHeaton
Created May 24, 2016 05:29
Show Gist options
  • Save JRHeaton/331ec5b0e03c2b6d9140ff5825c173ae to your computer and use it in GitHub Desktop.
Save JRHeaton/331ec5b0e03c2b6d9140ff5825c173ae to your computer and use it in GitHub Desktop.
Swift bug w/ generic class initializer
import UIKit
enum X: ErrorType {}
/**
error: declared closure result 'UICollectionView' is incompatible with contextual type '_'
createItemView: { () -> UICollectionView in
(it should be inferring LoadStateView.ItemView as the return type of this closure)
*/
let vc = LoadStateView<Int, X, UICollectionView, UIView>(
createItemView: { () -> UICollectionView in
return UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
},
createErrorView: .init,
displayItem: { view, item in
},
displayError: { view, error in
})
public protocol LoadStateDisplayable {
associatedtype StateItem
associatedtype StateError: ErrorType
func displayLoadState(state: LoadState<StateItem, StateError>)
}
public class LoadStateView<
Item,
Error: ErrorType,
ItemView: UIView,
ErrorView: UIView>: UIView, LoadStateDisplayable {
// Types
public typealias DisplayItemClosure = (ItemView, Item) -> ()
public typealias DisplayErrorClosure = (ErrorView, Error) -> ()
// Views
public let itemView: ItemView
public let loadingView: UIActivityIndicatorView
public let errorView: ErrorView
// Closures
public let displayItemClosure: DisplayItemClosure
public let displayErrorClosure: DisplayErrorClosure
public init(
@noescape createItemView: () -> ItemView,
@noescape createErrorView: () -> ErrorView,
displayItem: DisplayItemClosure,
displayError: DisplayErrorClosure) {
itemView = createItemView()
errorView = createErrorView()
displayItemClosure = displayItem
displayErrorClosure = displayError
loadingView = UIActivityIndicatorView()
super.init(frame: .zero)
addSubview(itemView)
addSubview(loadingView)
addSubview(errorView)
}
public func displayLoadState(state: LoadState<Item, Error>) {
if state.isLoading {
loadingView.startAnimating()
} else {
loadingView.stopAnimating()
}
itemView.hidden = !state.isLoaded
errorView.hidden = state.error == nil
switch state {
case .NotLoaded:
()
case .Loading:
()
case .Loaded(let item):
displayItemClosure(itemView, item)
case .Failure(let error):
displayErrorClosure(errorView, error)
}
}
}
public enum LoadState<Item, Error: ErrorType> {
case NotLoaded
case Loading
case Loaded(Item)
case Failure(Error)
public var item: Item? {
if case .Loaded(let item) = self {
return item
}
return nil
}
public var error: Error? {
if case .Failure(let error) = self {
return error
}
return nil
}
public var isLoading: Bool {
if case .Loading = self {
return true
}
return false
}
public var isLoaded: Bool {
if case .Loaded = self {
return true
}
return false
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment