Skip to content

Instantly share code, notes, and snippets.

@bcse bcse/MyMenu.swift
Last active May 25, 2018

Embed
What would you like to do?
Generics class with delegate
import Foundation
import UIKit
public protocol MenuItem {}
public protocol MenuDelegate: AnyObject {
associatedtype Item: MenuItem
func menu(_ menu: Menu<Item, Self>, didSelect item: Item)
}
open class Menu<Item, Delegate>: UIView where Delegate: MenuDelegate, Delegate.Item == Item {
public weak var delegate: Delegate?
func tap(item: Item) {
delegate?.menu(self, didSelect: item)
}
}
// It's very strange that this class must be final. This is a no-go.
final class MyViewController: UIViewController, MenuDelegate {
enum MyItem: String, MenuItem {
case one = "one"
case two = "two"
case three = "three"
}
typealias Item = MyItem
// It's strange that user have to put its own class here, but this can be "fixed" by using typealias
var menu: Menu<Item, MyViewController>?
override func viewDidLoad() {
super.viewDidLoad()
menu = Menu<Item, MyViewController>(frame: view.bounds)
menu?.delegate = self
}
// MARK: MenuDelegate
func menu(_ menu: Menu<Item, MyViewController>, didSelect item: Item) {
switch item {
case .one:
break
case .two:
break
case .three:
break
}
}
}
import Foundation
import UIKit
public protocol MenuItem {}
public protocol MenuDelegate: AnyObject {
func menu<T>(_ menu: Menu<T>, didSelect item: T)
}
open class Menu<Item: MenuItem>: UIView {
public weak var delegate: MenuDelegate?
func tap(item: Item) {
delegate?.menu(self, didSelect: item)
}
}
class MyViewController: UIViewController {
enum MyItem: String, MenuItem {
case one = "one"
case two = "two"
case three = "three"
}
var menu: Menu<MyItem>?
override func viewDidLoad() {
super.viewDidLoad()
menu = Menu<MyItem>(frame: view.bounds)
menu?.delegate = self
}
}
extension MyViewController: MenuDelegate {
// It's a little strange that user have to use where clause to declare type of MenuItem
func menu<T>(_ menu: Menu<T>, didSelect item: T) where T: MenuItem {
// It's very strange that user have to cast item in every delegate function, not
// just declare the correct type in previous line.
guard let item = item as? MyItem else { return }
switch item {
case .one:
break
case .two:
break
case .three:
break
}
}
}
// No generics, but it feels more natural than MyMenu2
import Foundation
import UIKit
public protocol MenuItem {}
public protocol MenuDelegate: AnyObject {
func menu(_ menu: Menu, didSelect item: MenuItem)
}
open class Menu: UIView {
public weak var delegate: MenuDelegate?
func tap(item: MenuItem) {
delegate?.menu(self, didSelect: item)
}
}
class MyViewController: UIViewController {
enum MyItem: String, MenuItem {
case one = "one"
case two = "two"
case three = "three"
}
var menu: Menu?
override func viewDidLoad() {
super.viewDidLoad()
menu = Menu(frame: view.bounds)
menu?.delegate = self
}
}
extension MyViewController: MenuDelegate {
func menu(_ menu: Menu, didSelect item: MenuItem) {
// It's very strange that user have to cast item in every delegate function
guard let item = item as? MyItem else { return }
switch item {
case .one:
break
case .two:
break
case .three:
break
}
}
}
// No generics
import Foundation
import UIKit
public struct MenuItem: ExpressibleByStringLiteral, Equatable, Hashable {
public typealias StringLiteralType = String
let rawValue: StringLiteralType
public init(stringLiteral value: StringLiteralType) {
rawValue = value
}
}
public protocol MenuDelegate: AnyObject {
func menu(_ menu: Menu, didSelect item: MenuItem)
}
open class Menu: UIView {
public weak var delegate: MenuDelegate?
func tap(item: MenuItem) {
delegate?.menu(self, didSelect: item)
}
}
// It's strange to use extension for enum. It might cause confusion when creating multiple Menu.
extension MenuItem {
static let one: MenuItem = "one"
static let two: MenuItem = "two"
static let three: MenuItem = "three"
}
class MyViewController: UIViewController {
var menu: Menu?
override func viewDidLoad() {
super.viewDidLoad()
menu = Menu(frame: view.bounds)
menu?.delegate = self
}
}
extension MyViewController: MenuDelegate {
func menu(_ menu: Menu, didSelect item: MenuItem) {
switch item {
case .one:
break
case .two:
break
case .three:
break
default:
// It's a little strange that user always need to handle default case
break
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.