Last active
November 4, 2022 04:26
-
-
Save skyofdwarf/d76cf51ff79356010cfaa627fe62c6b3 to your computer and use it in GitHub Desktop.
WKWebView 스크립트메시지 함수 분리를 위한 프로토콜
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// DynamicDispatch.swift | |
// DynamicDispatch | |
// | |
// Created by YEONGJUNG KIM on 2021/08/25. | |
// | |
import Foundation | |
/// `DynamicDispatch`의 임의함수를 호출할 delegate | |
/// | |
/// - Note: delegate 함수 리턴값은 현재 Void, NSNumber(Bool표현을 위해)만 지원한다. | |
/// | |
/// ``` | |
/// enum SampleMessage: DynamicDispatch { | |
/// static var prefix: String = "MyMessage" | |
/// | |
/// case say_hello | |
/// case goodbye | |
/// } | |
/// | |
/// class MyDispatcher: DynamicDispatchDelegate { | |
/// @objc func MyMessage_say_hello(_ body: Any) -> NSNumber { return NSNumber(value: true) } | |
/// @objc func MyMessage_goodbye(_ body: Any) {} | |
/// | |
/// func test() { | |
/// SampleMessage(rawValue: "goodbye")?.run(on: self) | |
/// } | |
/// } | |
/// ``` | |
/// | |
public protocol DynamicDispatchDelegate: NSObjectProtocol { | |
// `func {prefix}_{rawValue}:`(_ body: Any) | |
// `func `{prefix}_{rawValue}:`(_ body: Any) -> NSNumber | |
} | |
/// 스크립트메시지에 해당하는 함수를 자동으로 호출하기 위한 로직 | |
/// - note: `{prefix}_{rawValue}:` 형식의 셀렉터를 생성하고, 해당 셀렉터를 `DynamicDispatchDelegate`로 호출한다. | |
public protocol DynamicDispatch: RawRepresentable where RawValue: StringProtocol { | |
/// DynamicDispatch prefix | |
static var prefix: String { get } | |
/// 각 case마다 prefix을 지정할 수 있다. nil인 경우, `DynamicDispatch.prefix`이 사용된다. | |
var prefix: String? { get } | |
} | |
public extension DynamicDispatch { | |
/// 기본 prefix | |
static var prefix: String { "dynamicDispatch" } | |
/// 기본 case prefix | |
var prefix: String? { nil } | |
/// prefix과 rawValue을 이용해 셀렉터를 생성해 호출한다. | |
/// - Note: 셀렉터의 리턴값 확인이 iOS 버전, 기기/시뮬에 따라 다를 수 있다. 리턴 값 사용 시 주의가 필요. | |
/// - Parameters: | |
/// - delegate: 함수 호출할 객체 | |
/// - body: 함수 호출 시 전달될 파라미터 | |
/// - Returns: 해당 셀렉터 호출결과, 셀렉터 호출 불가 시 false | |
@discardableResult | |
func run(on delegate: DynamicDispatchDelegate, body: Any) -> Bool { | |
let fixedMessage = self.rawValue.replacingOccurrences(of: "-", with: "_").lowercased() | |
let prefix = prefix ?? Self.prefix | |
let selector = Selector("\(prefix)_\(fixedMessage):") | |
print("Selector: `\(selector)`") | |
if delegate.responds(to: selector) { | |
if let result = delegate.perform(selector, with: body) { | |
// NOTE: void를 리턴하는 셀렉터라도 시뮬/기기에 따라 `if let`동작에 차이가 있다. | |
// 기기14.5: if let 통과 | |
// 시뮬: if let 미통과 | |
// 따라서 if let 후에도 현재 제한적으로 지원하는 NSNumber 리턴타입변환까지 확인한다. | |
return (result.takeUnretainedValue() as? NSNumber)?.boolValue ?? true | |
} else { | |
return true | |
} | |
} else { | |
print("No message delegate function: \(selector)") | |
return false | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment