Skip to content

Commit

Permalink
change(SabyAppleObjectiveCReflection): remove call
Browse files Browse the repository at this point in the history
  • Loading branch information
0xWOF committed Feb 13, 2024
1 parent a6900a9 commit d3dd9d9
Show file tree
Hide file tree
Showing 8 changed files with 191 additions and 466 deletions.
24 changes: 12 additions & 12 deletions Source/AppleFetcher/Implement/AppleAdsAttributionTokenFetcher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,24 +56,24 @@ private final class ClassAAAttribution {
let error = UnsafeMutablePointer<NSError?>.allocate(capacity: 1)
defer { error.deallocate() }

let result = classAAAttribution.call(
methodAttributionTokenWithError,
with: OpaquePointer(error),
return: .reference
)
let result = {
let function = unsafeBitCast(
methodAttributionTokenWithError.implementation,
to: (@convention(c)(AnyClass, Selector, OpaquePointer)->String).self
)
return function(
methodAttributionTokenWithError.anyClass,
methodAttributionTokenWithError.selector,
OpaquePointer(error)
)
}()

if let error = error.pointee {
throw error
}
guard let result = result as? String else {
throw AppleAdsAttributionTokenFetcherError.attributionTokenIsNotString
}

return result
}
}

public enum AppleAdsAttributionTokenFetcherError: Error {
case attributionTokenIsNotString
}

#endif
237 changes: 22 additions & 215 deletions Source/AppleObjectiveCReflection/NSObjectClassMethod.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,229 +15,36 @@ extension NSObjectClass {
}
}

/// Class method of NSObject
/// 1. Class: use Any or ActualType (Example: NSString\*)
/// 2. Value: use ActualType (Using Any can lead crash) (Example: int)
/// 3. Pointer: use OpaquePointer (Using Any can lead crash) (Example: NSError\*\*)
/// ```swift
/// let result = {
/// let function = unsafeBitCast(
/// classMethod.implementation,
/// to: (@convention(c)(AnyClass, Selector, ...)->...).self
/// )
/// return function(
/// classMethod.anyClass,
/// classMethod.selector,
/// ...
/// )
/// }()
/// ```
public final class NSObjectClassMethod {
let anyClass: AnyClass
let selector: Selector
let method: Method
public let anyClass: AnyClass
public let selector: Selector
public let implementation: IMP

fileprivate init?(anyClass: AnyClass, name: String) {
let selector = NSSelectorFromString(name)
guard let method = class_getClassMethod(anyClass, selector) else { return nil }
let implementation = method_getImplementation(method)

self.anyClass = anyClass
self.selector = selector
self.method = method
}
}

extension NSObjectClass {
/// Call class method with reflection
@discardableResult
public func call<Return>(
_ classMethod: NSObjectClassMethod,
return: NSObjectReturn<Return> = .void
) -> Return? {
guard anyClass == classMethod.anyClass else { return nil }

let implementation = method_getImplementation(classMethod.method)

switch `return` {
case .reference:
typealias Function = @convention(c)(AnyClass, Selector)->Any?
let function = unsafeBitCast(implementation, to: Function.self)
let result = function(anyClass, classMethod.selector)
return result as? Return
case .value(let type):
typealias Function = @convention(c)(AnyClass, Selector)->Unmanaged<AnyObject>
let function = unsafeBitCast(implementation, to: Function.self)
let result = function(anyClass, classMethod.selector)
return cast(result, to: type)
case .void:
typealias Function = @convention(c)(AnyClass, Selector)->Void
let function = unsafeBitCast(implementation, to: Function.self)
function(anyClass, classMethod.selector)
return () as? Return
}
}

/// Call class method with reflection
@discardableResult
public func call<Return>(
_ classMethod: NSObjectClassMethod,
with argument0: Any?,
return: NSObjectReturn<Return> = .void
) -> Return? {
guard anyClass == classMethod.anyClass else { return nil }

let implementation = method_getImplementation(classMethod.method)

switch `return` {
case .reference:
typealias Function = @convention(c)(AnyClass, Selector, Any?)->Any?
let function = unsafeBitCast(implementation, to: Function.self)
let result = function(anyClass, classMethod.selector, argument0)
return result as? Return
case .value(let type):
typealias Function = @convention(c)(AnyClass, Selector, Any?)->Unmanaged<AnyObject>
let function = unsafeBitCast(implementation, to: Function.self)
let result = function(anyClass, classMethod.selector, argument0)
return cast(result, to: type)
case .void:
typealias Function = @convention(c)(AnyClass, Selector, Any?)->Void
let function = unsafeBitCast(implementation, to: Function.self)
function(anyClass, classMethod.selector, argument0)
return () as? Return
}
}

/// Call class method with reflection
@discardableResult
public func call<Return>(
_ classMethod: NSObjectClassMethod,
with argument0: Any?,
with argument1: Any?,
return: NSObjectReturn<Return> = .void
) -> Return? {
guard anyClass == classMethod.anyClass else { return nil }

let implementation = method_getImplementation(classMethod.method)

switch `return` {
case .reference:
typealias Function = @convention(c)(AnyClass, Selector, Any?, Any?)->Any?
let function = unsafeBitCast(implementation, to: Function.self)
let result = function(anyClass, classMethod.selector, argument0, argument1)
return result as? Return
case .value(let type):
typealias Function = @convention(c)(AnyClass, Selector, Any?, Any?)->Unmanaged<AnyObject>
let function = unsafeBitCast(implementation, to: Function.self)
let result = function(anyClass, classMethod.selector, argument0, argument1)
return cast(result, to: type)
case .void:
typealias Function = @convention(c)(AnyClass, Selector, Any?, Any?)->Void
let function = unsafeBitCast(implementation, to: Function.self)
function(anyClass, classMethod.selector, argument0, argument1)
return () as? Return
}
}

/// Call class method with reflection
@discardableResult
public func call<Return>(
_ classMethod: NSObjectClassMethod,
with argument0: Any?,
with argument1: Any?,
with argument2: Any?,
return: NSObjectReturn<Return> = .void
) -> Return? {
guard anyClass == classMethod.anyClass else { return nil }

let implementation = method_getImplementation(classMethod.method)

switch `return` {
case .reference:
typealias Function = @convention(c)(AnyClass, Selector, Any?, Any?, Any?)->Any?
let function = unsafeBitCast(implementation, to: Function.self)
let result = function(anyClass, classMethod.selector, argument0, argument1, argument2)
return result as? Return
case .value(let type):
typealias Function = @convention(c)(AnyClass, Selector, Any?, Any?, Any?)->Unmanaged<AnyObject>
let function = unsafeBitCast(implementation, to: Function.self)
let result = function(anyClass, classMethod.selector, argument0, argument1, argument2)
return cast(result, to: type)
case .void:
typealias Function = @convention(c)(AnyClass, Selector, Any?, Any?, Any?)->Void
let function = unsafeBitCast(implementation, to: Function.self)
function(anyClass, classMethod.selector, argument0, argument1, argument2)
return () as? Return
}
}

/// Call class method with reflection
@discardableResult
public func call<Return>(
_ classMethod: NSObjectClassMethod,
with argument0: Any?,
with argument1: Any?,
with argument2: Any?,
with argument3: Any?,
return: NSObjectReturn<Return> = .void
) -> Return? {
guard anyClass == classMethod.anyClass else { return nil }

let implementation = method_getImplementation(classMethod.method)

switch `return` {
case .reference:
typealias Function = @convention(c)(AnyClass, Selector, Any?, Any?, Any?, Any?)->Any?
let function = unsafeBitCast(implementation, to: Function.self)
let result = function(anyClass, classMethod.selector, argument0, argument1, argument2, argument3)
return result as? Return
case .value(let type):
typealias Function = @convention(c)(AnyClass, Selector, Any?, Any?, Any?, Any?)->Unmanaged<AnyObject>
let function = unsafeBitCast(implementation, to: Function.self)
let result = function(anyClass, classMethod.selector, argument0, argument1, argument2, argument3)
return cast(result, to: type)
case .void:
typealias Function = @convention(c)(AnyClass, Selector, Any?, Any?, Any?, Any?)->Void
let function = unsafeBitCast(implementation, to: Function.self)
function(anyClass, classMethod.selector, argument0, argument1, argument2, argument3)
return () as? Return
}
}

/// Call class method with reflection
@discardableResult
public func call<Return>(
_ classMethod: NSObjectClassMethod,
with argument0: Any?,
with argument1: Any?,
with argument2: Any?,
with argument3: Any?,
with argument4: Any?,
return: NSObjectReturn<Return> = .void
) -> Return? {
guard anyClass == classMethod.anyClass else { return nil }

let implementation = method_getImplementation(classMethod.method)

switch `return` {
case .reference:
typealias Function = @convention(c)(AnyClass, Selector, Any?, Any?, Any?, Any?, Any?)->Any?
let function = unsafeBitCast(implementation, to: Function.self)
let result = function(anyClass, classMethod.selector, argument0, argument1, argument2, argument3, argument4)
return result as? Return
case .value(let type):
typealias Function = @convention(c)(AnyClass, Selector, Any?, Any?, Any?, Any?, Any?)->Unmanaged<AnyObject>
let function = unsafeBitCast(implementation, to: Function.self)
let result = function(anyClass, classMethod.selector, argument0, argument1, argument2, argument3, argument4)
return cast(result, to: type)
case .void:
typealias Function = @convention(c)(AnyClass, Selector, Any?, Any?, Any?, Any?, Any?)->Void
let function = unsafeBitCast(implementation, to: Function.self)
function(anyClass, classMethod.selector, argument0, argument1, argument2, argument3, argument4)
return () as? Return
}
}
}

extension NSObjectClass {
private func cast<Actual>(
_ value: Unmanaged<AnyObject>,
to type: Actual.Type
) -> Actual {
let raw = unsafeBitCast(value, to: Int.self)

switch MemoryLayout<Actual>.size {
case 1:
return unsafeBitCast(Int8(raw), to: type)
case 2:
return unsafeBitCast(Int16(raw), to: type)
case 4:
return unsafeBitCast(Int32(raw), to: type)
default:
return unsafeBitCast(Int64(raw), to: type)
}
self.implementation = implementation
}
}

Expand Down
Loading

0 comments on commit d3dd9d9

Please sign in to comment.