Last active
April 30, 2025 01:10
-
-
Save pbk20191/a4aee4e6ed2d643f7a25fbb737837cd3 to your computer and use it in GitHub Desktop.
Objective-c proxy pattern using Pure Swift!
This file contains hidden or 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
import Foundation | |
import ObjectiveC | |
final class SwiftNSProxyObject<T:NSObjectProtocol>: NSProxy { | |
@nonobjc | |
var baseObject:T! | |
typealias MethodLookup = @convention(c) (AnyObject, Selector, Selector) -> (Unmanaged<NSObject>?) | |
@nonobjc | |
var methodTable:MethodLookup? | |
@nonobjc static var methodSelector: Selector { | |
Selector( "methodSignatureForSelector:") | |
} | |
@nonobjc class func create(_ baseObject:T) -> Self { | |
let proxy = alloc() | |
proxy.baseObject = baseObject | |
if let method = class_getInstanceMethod(type(of: baseObject), Self.methodSelector) { | |
let imp = method_getImplementation(method) | |
proxy.methodTable = unsafeBitCast(imp, to: MethodLookup.self) | |
} else { | |
proxy.methodTable = nil | |
} | |
return proxy | |
} | |
@objc(forwardingTargetForSelector:) | |
func forwardingTarget(for aSelector: Selector!) -> Any? { | |
#if !DEBUG | |
if baseObject.responds(to: aSelector) { | |
return baseObject | |
} | |
#endif | |
return nil | |
} | |
// @objc(resolveClassMethod:) | |
// class func resolveClassMethod(_ sel:Selector) -> Bool { | |
// false | |
// } | |
// | |
// @objc(resolveInstanceMethod:) | |
// class func resolveInstanceMethod(_ sel:Selector) -> Bool { | |
// return false | |
// } | |
// | |
// @objc(instancesRespondToSelector:) | |
// class func instancesRespond(_ sel:Selector) -> Bool { | |
// false | |
// } | |
@objc(conformsToProtocol:) | |
override func conforms(to aProtocol: Protocol) -> Bool { | |
return baseObject.conforms(to: aProtocol) | |
} | |
@objc(respondsToSelector:) | |
override func responds(to aSelector: Selector!) -> Bool { | |
return baseObject.responds(to: aSelector) | |
} | |
@available(swift, obsoleted: 1.0) | |
@objc(forwardInvocation:) | |
override func forwardInvocation(_ invocation: NSInvocation) { | |
invocation.invoke(withTarget: baseObject!) | |
} | |
@available(swift, obsoleted: 1.0) | |
@objc(methodSignatureForSelector:) | |
override func methodSignature(for selector: Selector) -> NSMethodSignature? { | |
guard let methodTable else { return nil } | |
let object = methodTable(self.baseObject, Self.methodSelector, selector)?.takeUnretainedValue() | |
let signature = object as? NSMethodSignature | |
return signature | |
} | |
@objc(isProxy) | |
override func isProxy() -> Bool { | |
return true | |
} | |
@objc(isEqual:) | |
override func isEqual(_ object: Any?) -> Bool { | |
return baseObject.isEqual(object) | |
} | |
@objc(hash) | |
override var hash:Int { | |
baseObject.hash | |
} | |
@objc(isKindOfClass:) | |
override func isKind(of aClass: AnyClass) -> Bool { | |
return baseObject.isKind(of: aClass) | |
} | |
@objc(isMemberOfClass:) | |
override func isMember(of aClass: AnyClass) -> Bool { | |
return baseObject.isMember(of: aClass) | |
} | |
} |
This file contains hidden or 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
import Foundation | |
import ObjectiveC | |
final class SwiftProxyObject<T:NSObjectProtocol> { | |
@nonobjc | |
let baseObject:T | |
typealias MethodLookup = @convention(c) (AnyObject, Selector, Selector) -> (Unmanaged<NSObject>?) | |
@nonobjc | |
let methodTable:MethodLookup? | |
@nonobjc static var methodSelector: Selector { | |
Selector( "methodSignatureForSelector:") | |
} | |
@nonobjc | |
init(baseObject: T) { | |
self.baseObject = baseObject | |
let type = type(of: baseObject) | |
if let method = class_getInstanceMethod(type, Self.methodSelector) { | |
let imp = method_getImplementation(method) | |
self.methodTable = unsafeBitCast(imp, to: MethodLookup.self) | |
} else { | |
self.methodTable = nil | |
} | |
} | |
@objc(forwardingTargetForSelector:) | |
func forwardingTarget(for aSelector: Selector!) -> Any? { | |
#if !DEBUG | |
if baseObject.responds(to: aSelector) { | |
return baseObject | |
} | |
#endif | |
return nil | |
} | |
// @objc(resolveClassMethod:) | |
// class func resolveClassMethod(_ sel:Selector) -> Bool { | |
// false | |
// } | |
// | |
// @objc(resolveInstanceMethod:) | |
// class func resolveInstanceMethod(_ sel:Selector) -> Bool { | |
// return false | |
// } | |
// | |
// @objc(instancesRespondToSelector:) | |
// class func instancesRespond(_ sel:Selector) -> Bool { | |
// false | |
// } | |
@objc(conformsToProtocol:) | |
func conforms(to aProtocol: Protocol) -> Bool { | |
return baseObject.conforms(to: aProtocol) | |
} | |
@objc(respondsToSelector:) | |
func responds(to aSelector: Selector!) -> Bool { | |
return baseObject.responds(to: aSelector) | |
} | |
@available(swift, obsoleted: 1.0) | |
@objc(forwardInvocation:) | |
func forwardInvocation(_ invocation: NSInvocation) { | |
invocation.invoke(withTarget: baseObject) | |
} | |
@available(swift, obsoleted: 1.0) | |
@objc(methodSignatureForSelector:) | |
func methodSignature(for selector: Selector!) -> NSMethodSignature! { | |
guard let methodTable else { return nil } | |
let object = methodTable(self.baseObject, Self.methodSelector, selector)?.takeUnretainedValue() | |
let signature = object as? NSMethodSignature | |
return signature | |
} | |
@objc(isProxy) | |
func isProxy() -> Bool { | |
return true | |
} | |
@objc(isEqual:) | |
func isEqual(_ object: Any?) -> Bool { | |
return baseObject.isEqual(object) | |
} | |
@objc(hash) | |
var hash:Int { | |
baseObject.hash | |
} | |
@objc(isKindOfClass:) | |
func isKind(of aClass: AnyClass) -> Bool { | |
return baseObject.isKind(of: aClass) | |
} | |
@objc(isMemberOfClass:) | |
func isMember(of aClass: AnyClass) -> Bool { | |
return baseObject.isMember(of: aClass) | |
} | |
@objc(self) | |
func `self`() -> NSObjectProtocol { | |
baseObject.`self`() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment