Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Custom URL Schemeを支える技術

Custom URL Schemeを支える技術

giginet

July 26, 2018
Tweet

More Decks by giginet

Other Decks in Programming

Transcript

  1. let url = URL(string: "pokedex://pokemons/25")! let components = url.pathComponents if

    url.scheme == "pokedex" { if url.host == "pokemons" { if components.count == 2, let pokedexID: Int = Int(components[1]) { presentPokemonDetailViewController(of: pokedexID) } else if ( ... ) { } else { // ... } } }
  2. let url = URL(string: "pokedex://pokemons/25")! let components = url.pathComponents if

    url.scheme == "pokedex" { if url.host == "pokemons" { if components.count == 2, let pokedexID: Int = Int(components[1]) { presentPokemonDetailViewController(of: pokedexID) } else if ( ... ) { } else { // ... } } }
  3. import Crossroad class AppDelegate: UIApplicationDelegate { let router: DefaultRouter =

    { let router = DefaultRouter(scheme: "scheme") router.register([ ("scheme://search", { _ in return true }), // ... ]) return router }() func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey: Any]) -> Bool { return router.openIfPossible(url, options: options) } }
  4. let router = DefaultRouter(scheme: "pokedex") router.register([ ("pokedex://pokemons", { context in

    let type: Type? = context.parameter(for: "type") presentPokedexListViewController(for: type) return true }), ("pokedex://pokemons/:pokedexID", { context in guard let pokedexID: Int = try? context.arguments(for: "pokedexID") else { return false } guard let pokemon = Pokedex.find(by: pokedexID) else { return false } presentPokemonDetailViewController(of: pokedexID) return true }), ]) router.openIfPossible(url)
  5. let router = DefaultRouter(scheme: "pokedex") router.register([ ("pokedex://pokemons", { context in

    let type: Type? = context.parameter(for: "type") presentPokedexListViewController(for: type) return true }), ("pokedex://pokemons/:pokedexID", { context in guard let pokedexID: Int = try? context.arguments(for: "pokedexID") else { return false } guard let pokemon = Pokedex.find(by: pokedexID) else { return false } presentPokemonDetailViewController(of: pokedexID) return true }), ]) router.openIfPossible(url) pokedex://pokemons/25 25
  6. public protocol Extractable { static func extract(from: String) -> Self?

    } extension Int: Extractable { public static func extract(from string: String) -> Int? { return Int(string) } } let pokedexID: Int? = try? context.arguments(for: "pokedexID")
  7. enum Type: String, Extractable { case normal // ϊʔϚϧλΠϓ case

    fire // ΄ͷ͓λΠϓ case water // ΈͣλΠϓ case grass // ͘͞λΠϓ // ... }
  8. public extension RawRepresentable where Self: Extractable, Self.RawValue == String {

    public static func extract(from string: String) -> Self? { return Self(rawValue: string) } }
  9. // match pokedex://pokemons?type=fire ("pokedex://pokemons", { context in let type: Type?

    = context.parameters(for: "type") // ϙέϞϯҰཡը໘Λදࣔ͢Δ presentPokemonListViewController(of: type) return true })
  10. extension Array: Extractable where Array.Element: Extractable { static func extract(from

    string: String) -> [Element]? { let components = string.split(separator: ",") return components .map { String($0) } .compactMap(Element.extract(from:)) } }
  11. @dynamicMemberLookup struct Container { let values: [String: Any] subscript<T>(dynamicMember member:

    String) -> T? { if let value = values[member] { return value as? T } } } let container = Container(values: ["name": "Pikachu"]) let name: String = container.name // Pikachu
  12. // match pokedex://pokemons/:pokedexID // before let pokedexID: Int? = try?

    context.arguments(for: "pokedexID") // after let pokedexID: Int? = context.arguments.pokedexID
  13. @dynamicMemberLookup public struct ArgumentContainer { private let arguments: [String: String]

    public func fetch<T: Extractable>(for key: String) throws -> T { if let argument = arguments[key] { if let value = T.extract(from: argument) { return value } } throw Error.parsingArgumentFailed } public subscript<T: Extractable>(dynamicMember member: String) -> T? { return try? fetch(for: member) } }