From c88cc49e6c6cb78283541c70b033bce18ff620d3 Mon Sep 17 00:00:00 2001 From: Benjamin Deckys Date: Thu, 27 Jul 2023 23:46:54 +0900 Subject: [PATCH 1/4] Add Interception Functionality --- Package.swift | 15 +- Sources/CombineCocoa/CombineCocoa.h | 13 - .../DelegateProxy/DelegateProxy.swift | 4 +- Sources/CombineCocoa/Exports.swift | 8 + .../NSObject+Association.swift | 167 ++++++ .../NSObject+Interseption.swift | 518 ++++++++++++++++++ .../NSObject+ObjCRuntime.swift | 19 + .../ObjC+Constants.swift | 56 ++ .../ObjC+Messages.swift | 60 ++ .../ObjC+Runtime.swift | 35 ++ .../ObjC+RuntimeSubclassing.swift | 166 ++++++ .../ObjC+Selector.swift | 53 ++ .../Synchronizing.swift | 17 + .../CombineCocoaRuntime/ObjcDelegateProxy.m | 219 ++++++++ .../CombineCocoaRuntime/ObjcRuntimeAliases.m | 21 + .../include/ObjcDelegateProxy.h | 1 + .../include/ObjcRuntimeAliases.h | 17 + .../include/module.modulemap | 2 +- Sources/Runtime/ObjcDelegateProxy.m | 220 -------- 19 files changed, 1373 insertions(+), 238 deletions(-) delete mode 100644 Sources/CombineCocoa/CombineCocoa.h create mode 100644 Sources/CombineCocoa/Exports.swift create mode 100644 Sources/CombineCocoaInterception/NSObject+Association.swift create mode 100644 Sources/CombineCocoaInterception/NSObject+Interseption.swift create mode 100644 Sources/CombineCocoaInterception/NSObject+ObjCRuntime.swift create mode 100644 Sources/CombineCocoaInterception/ObjC+Constants.swift create mode 100644 Sources/CombineCocoaInterception/ObjC+Messages.swift create mode 100644 Sources/CombineCocoaInterception/ObjC+Runtime.swift create mode 100644 Sources/CombineCocoaInterception/ObjC+RuntimeSubclassing.swift create mode 100644 Sources/CombineCocoaInterception/ObjC+Selector.swift create mode 100644 Sources/CombineCocoaInterception/Synchronizing.swift create mode 100644 Sources/CombineCocoaRuntime/ObjcDelegateProxy.m create mode 100644 Sources/CombineCocoaRuntime/ObjcRuntimeAliases.m rename Sources/{Runtime => CombineCocoaRuntime}/include/ObjcDelegateProxy.h (94%) create mode 100644 Sources/CombineCocoaRuntime/include/ObjcRuntimeAliases.h rename Sources/{Runtime => CombineCocoaRuntime}/include/module.modulemap (66%) delete mode 100644 Sources/Runtime/ObjcDelegateProxy.m diff --git a/Package.swift b/Package.swift index 564f05a..65b005b 100644 --- a/Package.swift +++ b/Package.swift @@ -9,7 +9,18 @@ let package = Package( ], dependencies: [], targets: [ - .target(name: "CombineCocoa", dependencies: ["Runtime"]), - .target(name: "Runtime", dependencies: []) + .target( + name: "CombineCocoa", + dependencies: [ + "CombineCocoaInterception", + "CombineCocoaRuntime" + ]), + .target( + name: "CombineCocoaInterception", + dependencies: [ + .target(name: "CombineCocoaRuntime") + ] + ), + .target(name: "CombineCocoaRuntime") ] ) diff --git a/Sources/CombineCocoa/CombineCocoa.h b/Sources/CombineCocoa/CombineCocoa.h deleted file mode 100644 index dd8db20..0000000 --- a/Sources/CombineCocoa/CombineCocoa.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// CombineCocoa.h -// CombineCocoa -// -// Created by Joan Disho on 25/09/2019. -// Copyright © 2020 Combine Community. All rights reserved. -// - -#import -#import - -FOUNDATION_EXPORT double CombineCocoaVersionNumber; -FOUNDATION_EXPORT const unsigned char CombineCocoaVersionString[]; diff --git a/Sources/CombineCocoa/DelegateProxy/DelegateProxy.swift b/Sources/CombineCocoa/DelegateProxy/DelegateProxy.swift index d3aae10..7a73454 100644 --- a/Sources/CombineCocoa/DelegateProxy/DelegateProxy.swift +++ b/Sources/CombineCocoa/DelegateProxy/DelegateProxy.swift @@ -10,8 +10,8 @@ import Foundation import Combine -#if canImport(Runtime) -import Runtime +#if canImport(CombineCocoaRuntime) +import CombineCocoaRuntime #endif @available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) diff --git a/Sources/CombineCocoa/Exports.swift b/Sources/CombineCocoa/Exports.swift new file mode 100644 index 0000000..8f0ad2b --- /dev/null +++ b/Sources/CombineCocoa/Exports.swift @@ -0,0 +1,8 @@ +// +// Exports.swift +// +// +// Created by Benjamin Deckys on 2023/07/27. +// + +@_exported import CombineCocoaInterception diff --git a/Sources/CombineCocoaInterception/NSObject+Association.swift b/Sources/CombineCocoaInterception/NSObject+Association.swift new file mode 100644 index 0000000..a22b384 --- /dev/null +++ b/Sources/CombineCocoaInterception/NSObject+Association.swift @@ -0,0 +1,167 @@ +// +// NSObject+Association.swift +// CombineCocoa +// +// Created by Maxim Krouk on 22.06.21. +// Copyright © 2020 Combine Community. All rights reserved. +// + +import Foundation + +#if canImport(CombineCocoaRuntime) + import CombineCocoaRuntime +#endif + +internal struct AssociationKey { + fileprivate let address: UnsafeRawPointer + fileprivate let `default`: Value! + + /// Create an ObjC association key. + /// + /// - warning: The key must be uniqued. + /// + /// - parameters: + /// - default: The default value, or `nil` to trap on undefined value. It is + /// ignored if `Value` is an optional. + init(default: Value? = nil) { + self.address = UnsafeRawPointer( + UnsafeMutablePointer.allocate(capacity: 1) + ) + self.default = `default` + } + + /// Create an ObjC association key from a `StaticString`. + /// + /// - precondition: `key` has a pointer representation. + /// + /// - parameters: + /// - default: The default value, or `nil` to trap on undefined value. It is + /// ignored if `Value` is an optional. + init(_ key: StaticString, default: Value? = nil) { + assert(key.hasPointerRepresentation) + self.address = UnsafeRawPointer(key.utf8Start) + self.default = `default` + } + + /// Create an ObjC association key from a `Selector`. + /// + /// - parameters: + /// - default: The default value, or `nil` to trap on undefined value. It is + /// ignored if `Value` is an optional. + init(_ key: Selector, default: Value? = nil) { + self.address = UnsafeRawPointer(key.utf8Start) + self.default = `default` + } +} + +internal struct Associations { + fileprivate let base: Base + + init(_ base: Base) { + self.base = base + } +} + +extension NSObjectProtocol { + /// Retrieve the associated value for the specified key. If the value does not + /// exist, `initial` would be called and the returned value would be + /// associated subsequently. + /// + /// - parameters: + /// - key: An optional key to differentiate different values. + /// - initial: The action that supples an initial value. + /// + /// - returns: The associated value for the specified key. + internal func associatedValue( + forKey key: StaticString = #function, + initial: (Self) -> T + ) -> T { + let key = AssociationKey(key) + + if let value = associations.value(forKey: key) { + return value + } + + let value = initial(self) + associations.setValue(value, forKey: key) + + return value + } +} + +extension NSObjectProtocol { + @nonobjc internal var associations: Associations { + return Associations(self) + } +} + +extension Associations { + /// Retrieve the associated value for the specified key. + /// + /// - parameters: + /// - key: The key. + /// + /// - returns: The associated value, or the default value if no value has been + /// associated with the key. + internal func value( + forKey key: AssociationKey + ) -> Value { + return (objc_getAssociatedObject(base, key.address) as! Value?) ?? key.default + } + + /// Retrieve the associated value for the specified key. + /// + /// - parameters: + /// - key: The key. + /// + /// - returns: The associated value, or `nil` if no value is associated with + /// the key. + internal func value( + forKey key: AssociationKey + ) -> Value? { + return objc_getAssociatedObject(base, key.address) as! Value? + } + + /// Set the associated value for the specified key. + /// + /// - parameters: + /// - value: The value to be associated. + /// - key: The key. + internal func setValue( + _ value: Value, + forKey key: AssociationKey + ) { + objc_setAssociatedObject(base, key.address, value, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + + /// Set the associated value for the specified key. + /// + /// - parameters: + /// - value: The value to be associated. + /// - key: The key. + internal func setValue( + _ value: Value?, + forKey key: AssociationKey + ) { + objc_setAssociatedObject(base, key.address, value, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } +} + +/// Set the associated value for the specified key. +/// +/// - parameters: +/// - value: The value to be associated. +/// - key: The key. +/// - address: The address of the object. +internal func unsafeSetAssociatedValue( + _ value: Value?, + forKey key: AssociationKey, + forObjectAt address: UnsafeRawPointer +) { + _combinecocoa_objc_setAssociatedObject( + address, + key.address, + value, + .OBJC_ASSOCIATION_RETAIN_NONATOMIC + ) +} diff --git a/Sources/CombineCocoaInterception/NSObject+Interseption.swift b/Sources/CombineCocoaInterception/NSObject+Interseption.swift new file mode 100644 index 0000000..fbe353f --- /dev/null +++ b/Sources/CombineCocoaInterception/NSObject+Interseption.swift @@ -0,0 +1,518 @@ +// +// NSObject+Interseption.swift +// CombineCocoa +// +// Created by Maxim Krouk on 22.06.21. +// Copyright © 2020 Combine Community. All rights reserved. +// + +#if canImport(Combine) +import Combine +import Foundation + +#if canImport(CombineCocoaRuntime) + import CombineCocoaRuntime +#endif + +/// Whether the runtime subclass has already been prepared for method +/// interception. +private let interceptedKey = AssociationKey(default: false) + +/// Holds the method signature cache of the runtime subclass. +private let signatureCacheKey = AssociationKey() + +/// Holds the method selector cache of the runtime subclass. +private let selectorCacheKey = AssociationKey() + +internal let noImplementation: IMP = unsafeBitCast(Int(0), to: IMP.self) + +extension NSObject { + /// Create a publisher which sends a `next` event at the end of every + /// invocation of `selector` on the object. + /// + /// It completes when the object deinitializes. + /// + /// - note: Observers to the resulting publisher should not call the method + /// specified by the selector. + /// + /// - parameters: + /// - selector: The selector to observe. + /// + /// - returns: A trigger publisher. + @available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) + public func publisher(for selector: Selector) -> AnyPublisher<(), Never> { + return intercept(selector).map { (_: AnyObject) in }.eraseToAnyPublisher() + } + + /// Create a publisher which sends a `next` event, containing an array of + /// bridged arguments, at the end of every invocation of `selector` on the + /// object. + /// + /// It completes when the object deinitializes. + /// + /// - note: Observers to the resulting publisher should not call the method + /// specified by the selector. + /// + /// - parameters: + /// - selector: The selector to observe. + /// + /// - returns: A publisher that sends an array of bridged arguments. + @available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) + public func intercept(_ selector: Selector) -> AnyPublisher<[Any?], Never> { + return intercept(selector).map(unpackInvocation).eraseToAnyPublisher() + } + + /// Setup the method interception. + /// + /// - parameters: + /// - object: The object to be intercepted. + /// - selector: The selector of the method to be intercepted. + /// + /// - returns: A publisher that sends the corresponding `NSInvocation` after + /// every invocation of the method. + @available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) + @nonobjc fileprivate func intercept(_ selector: Selector) -> AnyPublisher { + guard let method = class_getInstanceMethod(objcClass, selector) else { + fatalError( + "Selector `\(selector)` does not exist in class `\(String(describing: objcClass))`." + ) + } + + let typeEncoding = method_getTypeEncoding(method)! + assert(checkTypeEncoding(typeEncoding)) + + return synchronized(self) { + let alias = selector.alias + let stateKey = AssociationKey(alias) + let interopAlias = selector.interopAlias + + if let state = associations.value(forKey: stateKey) { + return state.subject.eraseToAnyPublisher() + } + + let subclass: AnyClass = swizzleClass(self) + let subclassAssociations = Associations(subclass as AnyObject) + + synchronized(subclass) { + let isSwizzled = subclassAssociations.value(forKey: interceptedKey) + + let signatureCache: SignatureCache + let selectorCache: SelectorCache + + if isSwizzled { + signatureCache = subclassAssociations.value(forKey: signatureCacheKey) + selectorCache = subclassAssociations.value(forKey: selectorCacheKey) + } + else { + signatureCache = SignatureCache() + selectorCache = SelectorCache() + + subclassAssociations.setValue(signatureCache, forKey: signatureCacheKey) + subclassAssociations.setValue(selectorCache, forKey: selectorCacheKey) + subclassAssociations.setValue(true, forKey: interceptedKey) + + enableMessageForwarding(subclass, selectorCache) + setupMethodSignatureCaching(subclass, signatureCache) + } + + selectorCache.cache(selector) + + if signatureCache[selector] == nil { + let signature = NSMethodSignature.objcSignature(withObjCTypes: typeEncoding) + signatureCache[selector] = signature + } + + // If an immediate implementation of the selector is found in the + // runtime subclass the first time the selector is intercepted, + // preserve the implementation. + // + // Example: KVO setters if the instance is swizzled by KVO before RAC + // does. + if !class_respondsToSelector(subclass, interopAlias) { + let immediateImpl = class_getImmediateMethod(subclass, selector) + .flatMap(method_getImplementation) + .flatMap { $0 != _combinecocoa_objc_msgForward ? $0 : nil } + + if let impl = immediateImpl { + let succeeds = class_addMethod(subclass, interopAlias, impl, typeEncoding) + precondition( + succeeds, + "RAC attempts to swizzle a selector that has message forwarding enabled with a runtime injected implementation. This is unsupported in the current version." + ) + } + } + } + + let state = InterceptingState() + associations.setValue(state, forKey: stateKey) + + // Start forwarding the messages of the selector. + _ = class_replaceMethod(subclass, selector, _combinecocoa_objc_msgForward, typeEncoding) + + return state.subject.eraseToAnyPublisher() + } + } +} + +/// Swizzle `realClass` to enable message forwarding for method interception. +/// +/// - parameters: +/// - realClass: The runtime subclass to be swizzled. +@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) +private func enableMessageForwarding(_ realClass: AnyClass, _ selectorCache: SelectorCache) { + let perceivedClass: AnyClass = class_getSuperclass(realClass)! + + typealias ForwardInvocationImpl = @convention(block) (Unmanaged, AnyObject) -> Void + let newForwardInvocation: ForwardInvocationImpl = { objectRef, invocation in + let selector = invocation.selector! + let alias = selectorCache.alias(for: selector) + let interopAlias = selectorCache.interopAlias(for: selector) + + defer { + let stateKey = AssociationKey(alias) + if let state = objectRef.takeUnretainedValue().associations.value(forKey: stateKey) { + state.subject.send(invocation) + } + } + + let method = class_getInstanceMethod(perceivedClass, selector) + let typeEncoding: String + + if let runtimeTypeEncoding = method.flatMap(method_getTypeEncoding) { + typeEncoding = String(cString: runtimeTypeEncoding) + } + else { + let methodSignature = (objectRef.takeUnretainedValue() as AnyObject) + .objcMethodSignature(for: selector) + let encodings = (0.., Selector, AnyObject) -> + Void + let forwardInvocationImpl = class_getMethodImplementation( + perceivedClass, + ObjCSelector.forwardInvocation + ) + let forwardInvocation = unsafeBitCast(forwardInvocationImpl, to: SuperForwardInvocation.self) + forwardInvocation(objectRef, ObjCSelector.forwardInvocation, invocation) + } + + _ = class_replaceMethod( + realClass, + ObjCSelector.forwardInvocation, + imp_implementationWithBlock(newForwardInvocation as Any), + ObjCMethodEncoding.forwardInvocation + ) +} + +/// Swizzle `realClass` to accelerate the method signature retrieval, using a +/// signature cache that covers all known intercepted selectors of `realClass`. +/// +/// - parameters: +/// - realClass: The runtime subclass to be swizzled. +/// - signatureCache: The method signature cache. +private func setupMethodSignatureCaching(_ realClass: AnyClass, _ signatureCache: SignatureCache) { + let perceivedClass: AnyClass = class_getSuperclass(realClass)! + + let newMethodSignatureForSelector: + @convention(block) (Unmanaged, Selector) -> AnyObject? = { objectRef, selector in + if let signature = signatureCache[selector] { + return signature + } + + typealias SuperMethodSignatureForSelector = @convention(c) ( + Unmanaged, Selector, Selector + ) -> AnyObject? + let impl = class_getMethodImplementation( + perceivedClass, + ObjCSelector.methodSignatureForSelector + ) + let methodSignatureForSelector = unsafeBitCast(impl, to: SuperMethodSignatureForSelector.self) + return methodSignatureForSelector( + objectRef, + ObjCSelector.methodSignatureForSelector, + selector + ) + } + + _ = class_replaceMethod( + realClass, + ObjCSelector.methodSignatureForSelector, + imp_implementationWithBlock(newMethodSignatureForSelector as Any), + ObjCMethodEncoding.methodSignatureForSelector + ) +} + +/// The state of an intercepted method specific to an instance. +@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) +private final class InterceptingState { + let subject = PassthroughSubject() +} + +private final class SelectorCache { + private var map: [Selector: (main: Selector, interop: Selector)] = [:] + + init() {} + + /// Cache the aliases of the specified selector in the cache. + /// + /// - warning: Any invocation of this method must be synchronized against the + /// runtime subclass. + @discardableResult + func cache(_ selector: Selector) -> (main: Selector, interop: Selector) { + if let pair = map[selector] { + return pair + } + + let aliases = (selector.alias, selector.interopAlias) + map[selector] = aliases + + return aliases + } + + /// Get the alias of the specified selector. + /// + /// - parameters: + /// - selector: The selector alias. + func alias(for selector: Selector) -> Selector { + if let (main, _) = map[selector] { + return main + } + + return selector.alias + } + + /// Get the secondary alias of the specified selector. + /// + /// - parameters: + /// - selector: The selector alias. + func interopAlias(for selector: Selector) -> Selector { + if let (_, interop) = map[selector] { + return interop + } + + return selector.interopAlias + } +} + +// The signature cache for classes that have been swizzled for method +// interception. +// +// Read-copy-update is used here, since the cache has multiple readers but only +// one writer. +private final class SignatureCache { + // `Dictionary` takes 8 bytes for the reference to its storage and does CoW. + // So it should not encounter any corrupted, partially updated state. + private var map: [Selector: AnyObject] = [:] + + init() {} + + /// Get or set the signature for the specified selector. + /// + /// - warning: Any invocation of the setter must be synchronized against the + /// runtime subclass. + /// + /// - parameters: + /// - selector: The method signature. + subscript(selector: Selector) -> AnyObject? { + get { + return map[selector] + } + set { + if map[selector] == nil { + map[selector] = newValue + } + } + } +} + +/// Assert that the method does not contain types that cannot be intercepted. +/// +/// - parameters: +/// - types: The type encoding C string of the method. +/// +/// - returns: `true`. +private func checkTypeEncoding(_ types: UnsafePointer) -> Bool { + // Some types, including vector types, are not encoded. In these cases the + // signature starts with the size of the argument frame. + assert( + types.pointee < Int8(UInt8(ascii: "1")) || types.pointee > Int8(UInt8(ascii: "9")), + "unknown method return type not supported in type encoding: \(String(cString: types))" + ) + + assert(types.pointee != Int8(UInt8(ascii: "(")), "union method return type not supported") + assert(types.pointee != Int8(UInt8(ascii: "{")), "struct method return type not supported") + assert(types.pointee != Int8(UInt8(ascii: "[")), "array method return type not supported") + + assert(types.pointee != Int8(UInt8(ascii: "j")), "complex method return type not supported") + + return true +} + +/// Extract the arguments of an `NSInvocation` as an array of objects. +/// +/// - parameters: +/// - invocation: The `NSInvocation` to unpack. +/// +/// - returns: An array of objects. +private func unpackInvocation(_ invocation: AnyObject) -> [Any?] { + let invocation = invocation as AnyObject + let methodSignature = invocation.objcMethodSignature! + let count = methodSignature.objcNumberOfArguments! + + var bridged = [Any?]() + bridged.reserveCapacity(Int(count - 2)) + + // Ignore `self` and `_cmd` at index 0 and 1. + for position in 2..(_ type: U.Type) -> U { + let pointer = UnsafeMutableRawPointer.allocate( + byteCount: MemoryLayout.size, + alignment: MemoryLayout.alignment + ) + defer { + pointer.deallocate() + } + + invocation.objcCopy(to: pointer, forArgumentAt: Int(position)) + return pointer.assumingMemoryBound(to: type).pointee + } + + let value: Any? + + switch encoding { + case .char: + value = NSNumber(value: extract(CChar.self)) + case .int: + value = NSNumber(value: extract(CInt.self)) + case .short: + value = NSNumber(value: extract(CShort.self)) + case .long: + value = NSNumber(value: extract(CLong.self)) + case .longLong: + value = NSNumber(value: extract(CLongLong.self)) + case .unsignedChar: + value = NSNumber(value: extract(CUnsignedChar.self)) + case .unsignedInt: + value = NSNumber(value: extract(CUnsignedInt.self)) + case .unsignedShort: + value = NSNumber(value: extract(CUnsignedShort.self)) + case .unsignedLong: + value = NSNumber(value: extract(CUnsignedLong.self)) + case .unsignedLongLong: + value = NSNumber(value: extract(CUnsignedLongLong.self)) + case .float: + value = NSNumber(value: extract(CFloat.self)) + case .double: + value = NSNumber(value: extract(CDouble.self)) + case .bool: + value = NSNumber(value: extract(CBool.self)) + case .object: + value = extract((AnyObject?).self) + case .type: + value = extract((AnyClass?).self) + case .selector: + value = extract((Selector?).self) + case .undefined: + var size = 0 + var alignment = 0 + NSGetSizeAndAlignment(rawEncoding, &size, &alignment) + let buffer = UnsafeMutableRawPointer.allocate(byteCount: size, alignment: alignment) + defer { buffer.deallocate() } + + invocation.objcCopy(to: buffer, forArgumentAt: Int(position)) + value = NSValue(bytes: buffer, objCType: rawEncoding) + } + + bridged.append(value) + } + + return bridged +} +#endif diff --git a/Sources/CombineCocoaInterception/NSObject+ObjCRuntime.swift b/Sources/CombineCocoaInterception/NSObject+ObjCRuntime.swift new file mode 100644 index 0000000..fbc4a3a --- /dev/null +++ b/Sources/CombineCocoaInterception/NSObject+ObjCRuntime.swift @@ -0,0 +1,19 @@ +// +// NSObject+ObjCRuntime.swift +// CombineCocoa +// +// Created by Maxim Krouk on 22.06.21. +// Copyright © 2020 Combine Community. All rights reserved. +// + +import Foundation + +extension NSObject { + /// The class of the instance reported by the ObjC `-class:` message. + /// + /// - note: `type(of:)` might return the runtime subclass, while this property + /// always returns the original class. + @nonobjc internal var objcClass: AnyClass { + return (self as AnyObject).objcClass + } +} diff --git a/Sources/CombineCocoaInterception/ObjC+Constants.swift b/Sources/CombineCocoaInterception/ObjC+Constants.swift new file mode 100644 index 0000000..d761421 --- /dev/null +++ b/Sources/CombineCocoaInterception/ObjC+Constants.swift @@ -0,0 +1,56 @@ +// +// ObjC+Constants.swift +// CombineCocoa +// +// Created by Maxim Krouk on 22.06.21. +// Copyright © 2020 Combine Community. All rights reserved. +// + +import Foundation + +// Unavailable selectors in Swift. +internal enum ObjCSelector { + static let forwardInvocation = Selector((("forwardInvocation:"))) + static let methodSignatureForSelector = Selector((("methodSignatureForSelector:"))) + static let getClass = Selector((("class"))) +} + +// Method encoding of the unavailable selectors. +internal enum ObjCMethodEncoding { + static let forwardInvocation = extract("v@:@") + static let methodSignatureForSelector = extract("v@::") + static let getClass = extract("#@:") + + private static func extract(_ string: StaticString) -> UnsafePointer { + return UnsafeRawPointer(string.utf8Start).assumingMemoryBound(to: CChar.self) + } +} + +/// Objective-C type encoding. +/// +/// The enum does not cover all options, but only those that are expressive in +/// Swift. +internal enum ObjCTypeEncoding: Int8 { + case char = 99 + case int = 105 + case short = 115 + case long = 108 + case longLong = 113 + + case unsignedChar = 67 + case unsignedInt = 73 + case unsignedShort = 83 + case unsignedLong = 76 + case unsignedLongLong = 81 + + case float = 102 + case double = 100 + + case bool = 66 + + case object = 64 + case type = 35 + case selector = 58 + + case undefined = -1 +} diff --git a/Sources/CombineCocoaInterception/ObjC+Messages.swift b/Sources/CombineCocoaInterception/ObjC+Messages.swift new file mode 100644 index 0000000..253d495 --- /dev/null +++ b/Sources/CombineCocoaInterception/ObjC+Messages.swift @@ -0,0 +1,60 @@ +// +// ObjC+Messages.swift +// CombineCocoa +// +// Created by Maxim Krouk on 22.06.21. +// Copyright © 2020 Combine Community. All rights reserved. +// + +// Unavailable classes like `NSInvocation` can still be passed into Swift as +// `AnyClass` and `AnyObject`, and receive messages as `AnyClass` and +// `AnyObject` existentials. +// +// These `@objc` protocols host the method signatures so that they can be used +// with `AnyObject`. + +import Foundation + +internal let NSInvocation: AnyClass = NSClassFromString("NSInvocation")! +internal let NSMethodSignature: AnyClass = NSClassFromString("NSMethodSignature")! + +// Signatures defined in `@objc` protocols would be available for ObjC message +// sending via `AnyObject`. +@objc internal protocol ObjCClassReporting { + // An alias for `-class`, which is unavailable in Swift. + @objc(class) + var objcClass: AnyClass! { get } + + @objc(methodSignatureForSelector:) + func objcMethodSignature(for selector: Selector) -> AnyObject +} + +// Methods of `NSInvocation`. +@objc internal protocol ObjCInvocation { + @objc(setSelector:) + func objcSetSelector(_ selector: Selector) + + @objc(methodSignature) + var objcMethodSignature: AnyObject { get } + + @objc(getArgument:atIndex:) + func objcCopy(to buffer: UnsafeMutableRawPointer?, forArgumentAt index: Int) + + @objc(invoke) + func objcInvoke() + + @objc(invocationWithMethodSignature:) + static func objcInvocation(withMethodSignature signature: AnyObject) -> AnyObject +} + +// Methods of `NSMethodSignature`. +@objc internal protocol ObjCMethodSignature { + @objc(numberOfArguments) + var objcNumberOfArguments: UInt { get } + + @objc(getArgumentTypeAtIndex:) + func objcArgumentType(at index: UInt) -> UnsafePointer + + @objc(signatureWithObjCTypes:) + static func objcSignature(withObjCTypes typeEncoding: UnsafePointer) -> AnyObject +} diff --git a/Sources/CombineCocoaInterception/ObjC+Runtime.swift b/Sources/CombineCocoaInterception/ObjC+Runtime.swift new file mode 100644 index 0000000..acd30f5 --- /dev/null +++ b/Sources/CombineCocoaInterception/ObjC+Runtime.swift @@ -0,0 +1,35 @@ +// +// ObjC+Runtime.swift +// CombineCocoa +// +// Created by Maxim Krouk on 22.06.21. +// Copyright © 2020 Combine Community. All rights reserved. +// + +import Foundation + +/// Search in `class` for any method that matches the supplied selector without +/// propagating to the ancestors. +/// +/// - parameters: +/// - class: The class to search the method in. +/// - selector: The selector of the method. +/// +/// - returns: The matching method, or `nil` if none is found. +internal func class_getImmediateMethod(_ `class`: AnyClass, _ selector: Selector) -> Method? { + var total: UInt32 = 0 + + if let methods = class_copyMethodList(`class`, &total) { + defer { free(methods) } + + for index in 0..(default: nil) + +extension NSObject { + /// Swizzle the given selectors. + /// + /// - warning: The swizzling **does not** apply on a per-instance basis. In + /// other words, repetitive swizzling of the same selector would + /// overwrite previous swizzling attempts, despite a different + /// instance being supplied. + /// + /// - parameters: + /// - pairs: Tuples of selectors and the respective implementions to be + /// swapped in. + /// - key: An association key which determines if the swizzling has already + /// been performed. + internal func swizzle(_ pairs: (Selector, Any)..., key hasSwizzledKey: AssociationKey) { + let subclass: AnyClass = swizzleClass(self) + + synchronized(subclass) { + let subclassAssociations = Associations(subclass as AnyObject) + + if !subclassAssociations.value(forKey: hasSwizzledKey) { + subclassAssociations.setValue(true, forKey: hasSwizzledKey) + + for (selector, body) in pairs { + let method = class_getInstanceMethod(subclass, selector)! + let typeEncoding = method_getTypeEncoding(method)! + + if method_getImplementation(method) == _combinecocoa_objc_msgForward { + let succeeds = class_addMethod( + subclass, + selector.interopAlias, + imp_implementationWithBlock(body), + typeEncoding + ) + precondition( + succeeds, + "RAC attempts to swizzle a selector that has message forwarding enabled with a runtime injected implementation. This is unsupported in the current version." + ) + } + else { + let succeeds = class_addMethod( + subclass, + selector, + imp_implementationWithBlock(body), + typeEncoding + ) + precondition( + succeeds, + "RAC attempts to swizzle a selector that has already a runtime injected implementation. This is unsupported in the current version." + ) + } + } + } + } + } +} + +/// ISA-swizzle the class of the supplied instance. +/// +/// - note: If the instance has already been isa-swizzled, the swizzling happens +/// in place in the runtime subclass created by external parties. +/// +/// - warning: The swizzling **does not** apply on a per-instance basis. In +/// other words, repetitive swizzling of the same selector would +/// overwrite previous swizzling attempts, despite a different +/// instance being supplied. +/// +/// - parameters: +/// - instance: The instance to be swizzled. +/// +/// - returns: The runtime subclass of the perceived class of the instance. +internal func swizzleClass(_ instance: NSObject) -> AnyClass { + if let knownSubclass = instance.associations.value(forKey: knownRuntimeSubclassKey) { + return knownSubclass + } + + let perceivedClass: AnyClass = instance.objcClass + let realClass: AnyClass = object_getClass(instance)! + let realClassAssociations = Associations(realClass as AnyObject) + + if perceivedClass != realClass { + // If the class is already lying about what it is, it's probably a KVO + // dynamic subclass or something else that we shouldn't subclass at runtime. + synchronized(realClass) { + let isSwizzled = realClassAssociations.value(forKey: runtimeSubclassedKey) + if !isSwizzled { + replaceGetClass(in: realClass, decoy: perceivedClass) + realClassAssociations.setValue(true, forKey: runtimeSubclassedKey) + } + } + + return realClass + } + else { + let name = subclassName(of: perceivedClass) + let subclass: AnyClass = name.withCString { cString in + if let existingClass = objc_getClass(cString) as! AnyClass? { + return existingClass + } + else { + let subclass: AnyClass = objc_allocateClassPair(perceivedClass, cString, 0)! + replaceGetClass(in: subclass, decoy: perceivedClass) + objc_registerClassPair(subclass) + return subclass + } + } + + object_setClass(instance, subclass) + instance.associations.setValue(subclass, forKey: knownRuntimeSubclassKey) + return subclass + } +} + +private func subclassName(of class: AnyClass) -> String { + return String(cString: class_getName(`class`)).appending("_RACSwift") +} + +/// Swizzle the `-class` and `+class` methods. +/// +/// - parameters: +/// - class: The class to swizzle. +/// - perceivedClass: The class to be reported by the methods. +private func replaceGetClass(in class: AnyClass, decoy perceivedClass: AnyClass) { + let getClass: @convention(block) (UnsafeRawPointer?) -> AnyClass = { _ in + return perceivedClass + } + + let impl = imp_implementationWithBlock(getClass as Any) + + _ = class_replaceMethod( + `class`, + ObjCSelector.getClass, + impl, + ObjCMethodEncoding.getClass + ) + + _ = class_replaceMethod( + object_getClass(`class`), + ObjCSelector.getClass, + impl, + ObjCMethodEncoding.getClass + ) +} +#endif diff --git a/Sources/CombineCocoaInterception/ObjC+Selector.swift b/Sources/CombineCocoaInterception/ObjC+Selector.swift new file mode 100644 index 0000000..4ee73c3 --- /dev/null +++ b/Sources/CombineCocoaInterception/ObjC+Selector.swift @@ -0,0 +1,53 @@ +// +// ObjC+Selector.swift +// CombineCocoa +// +// Created by Maxim Krouk on 22.06.21. +// Copyright © 2020 Combine Community. All rights reserved. +// + +import Foundation + +extension Selector { + /// `self` as a pointer. It is uniqued across instances, similar to + /// `StaticString`. + internal var utf8Start: UnsafePointer { + return unsafeBitCast(self, to: UnsafePointer.self) + } + + /// An alias of `self`, used in method interception. + internal var alias: Selector { + return prefixing("rac0_") + } + + /// An alias of `self`, used in method interception specifically for + /// preserving (if found) an immediate implementation of `self` in the + /// runtime subclass. + internal var interopAlias: Selector { + return prefixing("rac1_") + } + + /// An alias of `self`, used for delegate proxies. + internal var delegateProxyAlias: Selector { + return prefixing("rac2_") + } + + internal func prefixing(_ prefix: StaticString) -> Selector { + let length = Int(strlen(utf8Start)) + let prefixedLength = length + prefix.utf8CodeUnitCount + + let asciiPrefix = UnsafeRawPointer(prefix.utf8Start).assumingMemoryBound(to: Int8.self) + + let cString = UnsafeMutablePointer.allocate(capacity: prefixedLength + 1) + defer { + cString.deinitialize(count: prefixedLength + 1) + cString.deallocate() + } + + cString.initialize(from: asciiPrefix, count: prefix.utf8CodeUnitCount) + (cString + prefix.utf8CodeUnitCount).initialize(from: utf8Start, count: length) + (cString + prefixedLength).initialize(to: Int8(UInt8(ascii: "\0"))) + + return sel_registerName(cString) + } +} diff --git a/Sources/CombineCocoaInterception/Synchronizing.swift b/Sources/CombineCocoaInterception/Synchronizing.swift new file mode 100644 index 0000000..72d3d5f --- /dev/null +++ b/Sources/CombineCocoaInterception/Synchronizing.swift @@ -0,0 +1,17 @@ +// +// Synchronizing.swift +// CombineCocoa +// +// Created by Maxim Krouk on 22.06.21. +// Copyright © 2020 Combine Community. All rights reserved. +// + +import Foundation + +internal func synchronized(_ token: AnyObject, execute: () throws -> Result) rethrows + -> Result +{ + objc_sync_enter(token) + defer { objc_sync_exit(token) } + return try execute() +} diff --git a/Sources/CombineCocoaRuntime/ObjcDelegateProxy.m b/Sources/CombineCocoaRuntime/ObjcDelegateProxy.m new file mode 100644 index 0000000..44963c8 --- /dev/null +++ b/Sources/CombineCocoaRuntime/ObjcDelegateProxy.m @@ -0,0 +1,219 @@ +// +// ObjcDelegateProxy.m +// CombineCocoa +// +// Created by Joan Disho & Shai Mishali on 25/09/2019. +// Copyright © 2020 Combine Community. All rights reserved. +// + +#import +#import "include/ObjcDelegateProxy.h" +#import + +#define OBJECT_VALUE(object) [NSValue valueWithNonretainedObject:(object)] + +static NSMutableDictionary *> *allSelectors; + +@implementation ObjcDelegateProxy + +- (NSSet *)selectors { + return allSelectors[OBJECT_VALUE(self.class)]; +} + ++ (void)initialize +{ + @synchronized (ObjcDelegateProxy.class) { + if (!allSelectors) { + allSelectors = [NSMutableDictionary new]; + } + allSelectors[OBJECT_VALUE(self)] = [self selectorsOfClass:self + withEncodedReturnType:[NSString stringWithFormat:@"%s", @encode(void)]]; + } +} + +- (BOOL)respondsToSelector:(SEL _Nonnull)aSelector { + return [super respondsToSelector:aSelector] || [self canRespondToSelector:aSelector]; +} + +- (BOOL)canRespondToSelector:(SEL _Nonnull)selector { + for (id current in allSelectors[OBJECT_VALUE(self.class)]) { + if (selector == (SEL) [current pointerValue]) { + return true; + } + } + + return false; +} + +- (void)interceptedSelector:(SEL _Nonnull)selector arguments:(NSArray * _Nonnull)arguments {} + +- (void)forwardInvocation:(NSInvocation *)anInvocation +{ + NSArray * _Nonnull arguments = unpackInvocation(anInvocation); + [self interceptedSelector:anInvocation.selector arguments:arguments]; +} + +NSArray * _Nonnull unpackInvocation(NSInvocation * _Nonnull invocation) { + NSUInteger numberOfArguments = invocation.methodSignature.numberOfArguments; + NSMutableArray *arguments = [NSMutableArray arrayWithCapacity:numberOfArguments - 2]; + + // Ignore `self` and `_cmd` at index 0 and 1. + for (NSUInteger index = 2; index < numberOfArguments; ++index) { + const char *argumentType = [invocation.methodSignature getArgumentTypeAtIndex:index]; + + // Skip const type qualifier. + if (argumentType[0] == 'r') { + argumentType++; + } + +#define isArgumentType(type) \ +strcmp(argumentType, @encode(type)) == 0 + +#define extractTypeAndSetValue(type, value) \ +type argument = 0; \ +[invocation getArgument:&argument atIndex:index]; \ +value = @(argument); \ + + id _Nonnull value; + + if (isArgumentType(id) || isArgumentType(Class) || isArgumentType(void (^)(void))) { + __unsafe_unretained id argument = nil; + [invocation getArgument:&argument atIndex:index]; + value = argument; + } + else if (isArgumentType(char)) { + extractTypeAndSetValue(char, value); + } + else if (isArgumentType(short)) { + extractTypeAndSetValue(short, value); + } + else if (isArgumentType(int)) { + extractTypeAndSetValue(int, value); + } + else if (isArgumentType(long)) { + extractTypeAndSetValue(long, value); + } + else if (isArgumentType(long long)) { + extractTypeAndSetValue(long long, value); + } + else if (isArgumentType(unsigned char)) { + extractTypeAndSetValue(unsigned char, value); + } + else if (isArgumentType(unsigned short)) { + extractTypeAndSetValue(unsigned short, value); + } + else if (isArgumentType(unsigned int)) { + extractTypeAndSetValue(unsigned int, value); + } + else if (isArgumentType(unsigned long)) { + extractTypeAndSetValue(unsigned long, value); + } + else if (isArgumentType(unsigned long long)) { + extractTypeAndSetValue(unsigned long long, value); + } + else if (isArgumentType(float)) { + extractTypeAndSetValue(float, value); + } + else if (isArgumentType(double)) { + extractTypeAndSetValue(double, value); + } + else if (isArgumentType(BOOL)) { + extractTypeAndSetValue(BOOL, value); + } + else if (isArgumentType(const char *)) { + extractTypeAndSetValue(const char *, value); + } + else { + NSUInteger size = 0; + NSGetSizeAndAlignment(argumentType, &size, NULL); + NSCParameterAssert(size > 0); + uint8_t data[size]; + [invocation getArgument:&data atIndex:index]; + + value = [NSValue valueWithBytes:&data objCType:argumentType]; + } + + [arguments addObject:value]; + } + + return arguments; +} + ++ (NSSet *) selectorsOfClass: (Class _Nonnull __unsafe_unretained) class + withEncodedReturnType: (NSString *) encodedReturnType { + unsigned int protocolsCount = 0; + Protocol * __unsafe_unretained _Nonnull * _Nullable protocolPointer = class_copyProtocolList(class, &protocolsCount); + + NSMutableSet *allSelectors = [[self selectorsOfProtocolPointer:protocolPointer + count:protocolsCount + andEncodedReturnType:encodedReturnType] mutableCopy]; + + Class _Nonnull __unsafe_unretained superclass = class_getSuperclass(class); + + if(superclass != nil) { + NSSet *superclassSelectors = [self selectorsOfClass:superclass + withEncodedReturnType:encodedReturnType]; + [allSelectors unionSet:superclassSelectors]; + } + + free(protocolPointer); + + return allSelectors; +} + ++ (NSSet *) selectorsOfProtocol: (Protocol * __unsafe_unretained) protocol + andEncodedReturnType: (NSString *) encodedReturnType { + unsigned int protocolMethodCount = 0; + struct objc_method_description * _Nullable methodDescriptions = protocol_copyMethodDescriptionList(protocol, false, true, &protocolMethodCount); + + // Protocol pointers + unsigned int protocolsCount = 0; + Protocol * __unsafe_unretained _Nonnull * _Nullable protocols = protocol_copyProtocolList(protocol, &protocolsCount); + + NSMutableSet *allSelectors = [NSMutableSet new]; + + // Protocol methods + for (NSInteger idx = 0; idx < protocolMethodCount; idx++) { + struct objc_method_description description = methodDescriptions[idx]; + + if ([self encodedMethodReturnTypeForMethod:description] == encodedReturnType) { + [allSelectors addObject: [NSValue valueWithPointer:description.name]]; + } + } + + if (protocols != nil) { + [allSelectors unionSet: [self selectorsOfProtocolPointer:protocols + count:protocolsCount + andEncodedReturnType:encodedReturnType]]; + } + + free(methodDescriptions); + free(protocols); + + return allSelectors; +} + ++ (NSSet *) selectorsOfProtocolPointer: (Protocol * __unsafe_unretained * _Nullable) pointer + count: (NSInteger) count + andEncodedReturnType: (NSString *) encodedReturnType { + NSMutableSet *allSelectors = [NSMutableSet new]; + + for (NSInteger i = 0; i < count; i++) { + Protocol * __unsafe_unretained _Nullable protocol = pointer[i]; + + if (protocol == nil) { continue; } + [allSelectors unionSet:[self selectorsOfProtocol:protocol + andEncodedReturnType:encodedReturnType]]; + } + + return allSelectors; +} + ++ (NSString *)encodedMethodReturnTypeForMethod: (struct objc_method_description) method { + return [[NSString alloc] initWithBytes:method.types + length:1 + encoding:NSASCIIStringEncoding]; +} + + +@end diff --git a/Sources/CombineCocoaRuntime/ObjcRuntimeAliases.m b/Sources/CombineCocoaRuntime/ObjcRuntimeAliases.m new file mode 100644 index 0000000..6c5dd98 --- /dev/null +++ b/Sources/CombineCocoaRuntime/ObjcRuntimeAliases.m @@ -0,0 +1,21 @@ +// +// ObjcRuntimeAliases.m +// +// +// Created by Benjamin Deckys on 2023/07/27. +// + +#import +#import + +const IMP _combinecocoa_objc_msgForward = _objc_msgForward; + +void _combinecocoa_objc_setAssociatedObject( + const void* object, + const void* key, + id value, + objc_AssociationPolicy policy + ) { + __unsafe_unretained id obj = (__bridge typeof(obj)) object; + objc_setAssociatedObject(obj, key, value, policy); +} diff --git a/Sources/Runtime/include/ObjcDelegateProxy.h b/Sources/CombineCocoaRuntime/include/ObjcDelegateProxy.h similarity index 94% rename from Sources/Runtime/include/ObjcDelegateProxy.h rename to Sources/CombineCocoaRuntime/include/ObjcDelegateProxy.h index a7d7d2f..62d5668 100644 --- a/Sources/Runtime/include/ObjcDelegateProxy.h +++ b/Sources/CombineCocoaRuntime/include/ObjcDelegateProxy.h @@ -7,6 +7,7 @@ // #import +#import @interface ObjcDelegateProxy: NSObject diff --git a/Sources/CombineCocoaRuntime/include/ObjcRuntimeAliases.h b/Sources/CombineCocoaRuntime/include/ObjcRuntimeAliases.h new file mode 100644 index 0000000..93aa744 --- /dev/null +++ b/Sources/CombineCocoaRuntime/include/ObjcRuntimeAliases.h @@ -0,0 +1,17 @@ +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +extern const IMP _combinecocoa_objc_msgForward; + +/// A trampoline of `objc_setAssociatedObject` that is made to circumvent the +/// reference counting calls in the imported version in Swift. +void _combinecocoa_objc_setAssociatedObject( + const void* object, + const void* key, + id _Nullable value, + objc_AssociationPolicy policy +); + +NS_ASSUME_NONNULL_END diff --git a/Sources/Runtime/include/module.modulemap b/Sources/CombineCocoaRuntime/include/module.modulemap similarity index 66% rename from Sources/Runtime/include/module.modulemap rename to Sources/CombineCocoaRuntime/include/module.modulemap index e628955..4986328 100644 --- a/Sources/Runtime/include/module.modulemap +++ b/Sources/CombineCocoaRuntime/include/module.modulemap @@ -1,4 +1,4 @@ -module Runtime { +module CombineCocoaRuntime { umbrella header "ObjcDelegateProxy.h" export * } diff --git a/Sources/Runtime/ObjcDelegateProxy.m b/Sources/Runtime/ObjcDelegateProxy.m deleted file mode 100644 index 9ae5624..0000000 --- a/Sources/Runtime/ObjcDelegateProxy.m +++ /dev/null @@ -1,220 +0,0 @@ -// -// ObjcDelegateProxy.m -// CombineCocoa -// -// Created by Joan Disho & Shai Mishali on 25/09/2019. -// Copyright © 2020 Combine Community. All rights reserved. -// - -#import -#import "include/ObjcDelegateProxy.h" -#import - -#define OBJECT_VALUE(object) [NSValue valueWithNonretainedObject:(object)] - -static NSMutableDictionary *> *allSelectors; - -@implementation ObjcDelegateProxy - -- (NSSet *)selectors { - return allSelectors[OBJECT_VALUE(self.class)]; -} - -+ (void)initialize -{ - @synchronized (ObjcDelegateProxy.class) { - if (!allSelectors) { - allSelectors = [NSMutableDictionary new]; - } - allSelectors[OBJECT_VALUE(self)] = [self selectorsOfClass:self - withEncodedReturnType:[NSString stringWithFormat:@"%s", @encode(void)]]; - } -} - -- (BOOL)respondsToSelector:(SEL _Nonnull)aSelector { - return [super respondsToSelector:aSelector] || [self canRespondToSelector:aSelector]; -} - -- (BOOL)canRespondToSelector:(SEL _Nonnull)selector { - for (id current in allSelectors[OBJECT_VALUE(self.class)]) { - if (selector == (SEL) [current pointerValue]) { - return true; - } - } - - return false; -} - -- (void)interceptedSelector:(SEL _Nonnull)selector arguments:(NSArray * _Nonnull)arguments {} - -- (void)forwardInvocation:(NSInvocation *)anInvocation -{ - NSArray * _Nonnull arguments = unpackInvocation(anInvocation); - [self interceptedSelector:anInvocation.selector arguments:arguments]; -} - -NSArray * _Nonnull unpackInvocation(NSInvocation * _Nonnull invocation) { - NSUInteger numberOfArguments = invocation.methodSignature.numberOfArguments; - NSMutableArray *arguments = [NSMutableArray arrayWithCapacity:numberOfArguments - 2]; - - // Ignore `self` and `_cmd` at index 0 and 1. - for (NSUInteger index = 2; index < numberOfArguments; ++index) { - const char *argumentType = [invocation.methodSignature getArgumentTypeAtIndex:index]; - - // Skip const type qualifier. - if (argumentType[0] == 'r') { - argumentType++; - } - - #define isArgumentType(type) \ - strcmp(argumentType, @encode(type)) == 0 - - #define extractTypeAndSetValue(type, value) \ - type argument = 0; \ - [invocation getArgument:&argument atIndex:index]; \ - value = @(argument); \ - - id _Nonnull value; - - if (isArgumentType(id) || isArgumentType(Class) || isArgumentType(void (^)(void))) { - __unsafe_unretained id argument = nil; - [invocation getArgument:&argument atIndex:index]; - value = argument; - } - else if (isArgumentType(char)) { - extractTypeAndSetValue(char, value); - } - else if (isArgumentType(short)) { - extractTypeAndSetValue(short, value); - } - else if (isArgumentType(int)) { - extractTypeAndSetValue(int, value); - } - else if (isArgumentType(long)) { - extractTypeAndSetValue(long, value); - } - else if (isArgumentType(long long)) { - extractTypeAndSetValue(long long, value); - } - else if (isArgumentType(unsigned char)) { - extractTypeAndSetValue(unsigned char, value); - } - else if (isArgumentType(unsigned short)) { - extractTypeAndSetValue(unsigned short, value); - } - else if (isArgumentType(unsigned int)) { - extractTypeAndSetValue(unsigned int, value); - } - else if (isArgumentType(unsigned long)) { - extractTypeAndSetValue(unsigned long, value); - } - else if (isArgumentType(unsigned long long)) { - extractTypeAndSetValue(unsigned long long, value); - } - else if (isArgumentType(float)) { - extractTypeAndSetValue(float, value); - } - else if (isArgumentType(double)) { - extractTypeAndSetValue(double, value); - } - else if (isArgumentType(BOOL)) { - extractTypeAndSetValue(BOOL, value); - } - else if (isArgumentType(const char *)) { - extractTypeAndSetValue(const char *, value); - } - else { - NSUInteger size = 0; - NSGetSizeAndAlignment(argumentType, &size, NULL); - NSCParameterAssert(size > 0); - uint8_t data[size]; - [invocation getArgument:&data atIndex:index]; - - value = [NSValue valueWithBytes:&data objCType:argumentType]; - } - - [arguments addObject:value]; - } - - return arguments; -} - -+ (NSSet *) selectorsOfClass: (Class _Nonnull __unsafe_unretained) class - withEncodedReturnType: (NSString *) encodedReturnType { - unsigned int protocolsCount = 0; - Protocol * __unsafe_unretained _Nonnull * _Nullable protocolPointer = class_copyProtocolList(class, &protocolsCount); - - NSMutableSet *allSelectors = [[self selectorsOfProtocolPointer:protocolPointer - count:protocolsCount - andEncodedReturnType:encodedReturnType] mutableCopy]; - - Class _Nonnull __unsafe_unretained superclass = class_getSuperclass(class); - - if(superclass != nil) { - NSSet *superclassSelectors = [self selectorsOfClass:superclass - withEncodedReturnType:encodedReturnType]; - [allSelectors unionSet:superclassSelectors]; - } - - free(protocolPointer); - - return allSelectors; -} - -+ (NSSet *) selectorsOfProtocol: (Protocol * __unsafe_unretained) protocol - andEncodedReturnType: (NSString *) encodedReturnType { - unsigned int protocolMethodCount = 0; - struct objc_method_description * _Nullable methodDescriptions = protocol_copyMethodDescriptionList(protocol, false, true, &protocolMethodCount); - - // Protocol pointers - unsigned int protocolsCount = 0; - Protocol * __unsafe_unretained _Nonnull * _Nullable protocols = protocol_copyProtocolList(protocol, &protocolsCount); - - NSMutableSet *allSelectors = [NSMutableSet new]; - - // Protocol methods - for (NSInteger idx = 0; idx < protocolMethodCount; idx++) { - struct objc_method_description description = methodDescriptions[idx]; - - if ([self encodedMethodReturnTypeForMethod:description] == encodedReturnType) { - [allSelectors addObject: [NSValue valueWithPointer:description.name]]; - } - } - - if (protocols != nil) { - [allSelectors unionSet: [self selectorsOfProtocolPointer:protocols - count:protocolsCount - andEncodedReturnType:encodedReturnType]]; - } - - free(methodDescriptions); - free(protocols); - - return allSelectors; -} - -+ (NSSet *) selectorsOfProtocolPointer: (Protocol * __unsafe_unretained * _Nullable) pointer - count: (NSInteger) count - andEncodedReturnType: (NSString *) encodedReturnType { - NSMutableSet *allSelectors = [NSMutableSet new]; - - for (NSInteger i = 0; i < count; i++) { - Protocol * __unsafe_unretained _Nullable protocol = pointer[i]; - - if (protocol == nil) { continue; } - [allSelectors unionSet:[self selectorsOfProtocol:protocol - andEncodedReturnType:encodedReturnType]]; - } - - return allSelectors; -} - -+ (NSString *)encodedMethodReturnTypeForMethod: (struct objc_method_description) method { - return [[NSString alloc] initWithBytes:method.types - length:1 - encoding:NSASCIIStringEncoding]; -} - - -@end - From 4ffcdb600e37767567b9f6352b44660e7c4d5322 Mon Sep 17 00:00:00 2001 From: Benjamin Deckys Date: Fri, 28 Jul 2023 00:23:02 +0900 Subject: [PATCH 2/4] Reconfig --- CombineCocoa.podspec | 8 +- .../CombineCocoa_Info.plist | 26 - CombineCocoa.xcodeproj/Runtime_Info.plist | 25 - CombineCocoa.xcodeproj/project.pbxproj | 606 ------------------ .../contents.xcworkspacedata | 7 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/WorkspaceSettings.xcsettings | 8 - .../xcschemes/CombineCocoa-Package.xcscheme | 32 - Package.swift | 39 +- Sources/CombineCocoa/Exports.swift | 8 - .../Interception}/NSObject+Association.swift | 0 .../Interception}/NSObject+Interseption.swift | 0 .../Interception}/NSObject+ObjCRuntime.swift | 0 .../Interception}/ObjC+Constants.swift | 0 .../Interception}/ObjC+Messages.swift | 0 .../Interception}/ObjC+Runtime.swift | 0 .../ObjC+RuntimeSubclassing.swift | 0 .../Interception}/ObjC+Selector.swift | 0 .../Interception}/Synchronizing.swift | 0 19 files changed, 22 insertions(+), 745 deletions(-) delete mode 100644 CombineCocoa.xcodeproj/CombineCocoa_Info.plist delete mode 100644 CombineCocoa.xcodeproj/Runtime_Info.plist delete mode 100644 CombineCocoa.xcodeproj/project.pbxproj delete mode 100644 CombineCocoa.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 CombineCocoa.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 CombineCocoa.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings delete mode 100644 CombineCocoa.xcodeproj/xcshareddata/xcschemes/CombineCocoa-Package.xcscheme delete mode 100644 Sources/CombineCocoa/Exports.swift rename Sources/{CombineCocoaInterception => CombineCocoa/Interception}/NSObject+Association.swift (100%) rename Sources/{CombineCocoaInterception => CombineCocoa/Interception}/NSObject+Interseption.swift (100%) rename Sources/{CombineCocoaInterception => CombineCocoa/Interception}/NSObject+ObjCRuntime.swift (100%) rename Sources/{CombineCocoaInterception => CombineCocoa/Interception}/ObjC+Constants.swift (100%) rename Sources/{CombineCocoaInterception => CombineCocoa/Interception}/ObjC+Messages.swift (100%) rename Sources/{CombineCocoaInterception => CombineCocoa/Interception}/ObjC+Runtime.swift (100%) rename Sources/{CombineCocoaInterception => CombineCocoa/Interception}/ObjC+RuntimeSubclassing.swift (100%) rename Sources/{CombineCocoaInterception => CombineCocoa/Interception}/ObjC+Selector.swift (100%) rename Sources/{CombineCocoaInterception => CombineCocoa/Interception}/Synchronizing.swift (100%) diff --git a/CombineCocoa.podspec b/CombineCocoa.podspec index 4756533..55e83f4 100644 --- a/CombineCocoa.podspec +++ b/CombineCocoa.podspec @@ -1,14 +1,14 @@ Pod::Spec.new do |s| s.name = "CombineCocoa" - s.version = "0.4.1" + s.version = "0.4.2" s.summary = "CombineCocoa provided basic publisher bridges for UIControls in UIKit" s.description = <<-DESC Combine publisher bridges for Cocoa Controls (UIControl) in UIKit DESC - s.homepage = "https://github.com/freak4pc/CombineCocoa" + s.homepage = "https://github.com/viewdidappear/CombineCocoa" s.license = 'MIT' s.author = { "Shai Mishali" => "freak4pc@gmail.com" } - s.source = { :git => "https://github.com/freak4pc/CombineCocoa.git", :tag => s.version.to_s } + s.source = { :git => "https://github.com/viewdidappear/CombineCocoa.git", :tag => s.version.to_s } s.requires_arc = true @@ -17,4 +17,4 @@ Pod::Spec.new do |s| s.source_files = 'Sources/**/*.{swift,h,m}' s.frameworks = ['Combine', 'Foundation'] s.swift_version = '5.0' - end \ No newline at end of file + end diff --git a/CombineCocoa.xcodeproj/CombineCocoa_Info.plist b/CombineCocoa.xcodeproj/CombineCocoa_Info.plist deleted file mode 100644 index e122590..0000000 --- a/CombineCocoa.xcodeproj/CombineCocoa_Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 0.2.1 - CFBundleSignature - ???? - CFBundleVersion - 0.2.1 - NSPrincipalClass - - - diff --git a/CombineCocoa.xcodeproj/Runtime_Info.plist b/CombineCocoa.xcodeproj/Runtime_Info.plist deleted file mode 100644 index 57ada9f..0000000 --- a/CombineCocoa.xcodeproj/Runtime_Info.plist +++ /dev/null @@ -1,25 +0,0 @@ - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - diff --git a/CombineCocoa.xcodeproj/project.pbxproj b/CombineCocoa.xcodeproj/project.pbxproj deleted file mode 100644 index 10633da..0000000 --- a/CombineCocoa.xcodeproj/project.pbxproj +++ /dev/null @@ -1,606 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - OBJ_101 /* ObjcDelegateProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_38 /* ObjcDelegateProxy.m */; }; - OBJ_62 /* AnimatedAssignSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_10 /* AnimatedAssignSubscriber.swift */; }; - OBJ_63 /* CombineControlEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_11 /* CombineControlEvent.swift */; }; - OBJ_64 /* CombineControlProperty.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_12 /* CombineControlProperty.swift */; }; - OBJ_65 /* CombineControlTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_13 /* CombineControlTarget.swift */; }; - OBJ_66 /* NSTextStorage+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_15 /* NSTextStorage+Combine.swift */; }; - OBJ_67 /* UIBarButtonItem+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_16 /* UIBarButtonItem+Combine.swift */; }; - OBJ_68 /* UIButton+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_17 /* UIButton+Combine.swift */; }; - OBJ_69 /* UICollectionView+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_18 /* UICollectionView+Combine.swift */; }; - OBJ_70 /* UIControl+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_19 /* UIControl+Combine.swift */; }; - OBJ_71 /* UIDatePicker+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_20 /* UIDatePicker+Combine.swift */; }; - OBJ_72 /* UIGestureRecognizer+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_21 /* UIGestureRecognizer+Combine.swift */; }; - OBJ_73 /* UIPageControl+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_22 /* UIPageControl+Combine.swift */; }; - OBJ_74 /* UIRefreshControl+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_23 /* UIRefreshControl+Combine.swift */; }; - OBJ_75 /* UIScrollView+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_24 /* UIScrollView+Combine.swift */; }; - OBJ_76 /* UISearchBar+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_25 /* UISearchBar+Combine.swift */; }; - OBJ_77 /* UISegmentedControl+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_26 /* UISegmentedControl+Combine.swift */; }; - OBJ_78 /* UISlider+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_27 /* UISlider+Combine.swift */; }; - OBJ_79 /* UIStepper+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_28 /* UIStepper+Combine.swift */; }; - OBJ_80 /* UISwitch+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_29 /* UISwitch+Combine.swift */; }; - OBJ_81 /* UITableView+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_30 /* UITableView+Combine.swift */; }; - OBJ_82 /* UITextField+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_31 /* UITextField+Combine.swift */; }; - OBJ_83 /* UITextView+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_32 /* UITextView+Combine.swift */; }; - OBJ_84 /* DelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_34 /* DelegateProxy.swift */; }; - OBJ_85 /* DelegateProxyPublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_35 /* DelegateProxyPublisher.swift */; }; - OBJ_86 /* DelegateProxyType.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_36 /* DelegateProxyType.swift */; }; - OBJ_88 /* Runtime.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = "CombineCocoa::Runtime::Product" /* Runtime.framework */; }; - OBJ_96 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_6 /* Package.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 61B996BE25EA62D200D6F6ED /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = OBJ_1 /* Project object */; - proxyType = 1; - remoteGlobalIDString = "CombineCocoa::Runtime"; - remoteInfo = Runtime; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - "CombineCocoa::CombineCocoa::Product" /* CombineCocoa.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = CombineCocoa.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - "CombineCocoa::Runtime::Product" /* Runtime.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Runtime.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - OBJ_10 /* AnimatedAssignSubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnimatedAssignSubscriber.swift; sourceTree = ""; }; - OBJ_11 /* CombineControlEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CombineControlEvent.swift; sourceTree = ""; }; - OBJ_12 /* CombineControlProperty.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CombineControlProperty.swift; sourceTree = ""; }; - OBJ_13 /* CombineControlTarget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CombineControlTarget.swift; sourceTree = ""; }; - OBJ_15 /* NSTextStorage+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSTextStorage+Combine.swift"; sourceTree = ""; }; - OBJ_16 /* UIBarButtonItem+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIBarButtonItem+Combine.swift"; sourceTree = ""; }; - OBJ_17 /* UIButton+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIButton+Combine.swift"; sourceTree = ""; }; - OBJ_18 /* UICollectionView+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UICollectionView+Combine.swift"; sourceTree = ""; }; - OBJ_19 /* UIControl+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIControl+Combine.swift"; sourceTree = ""; }; - OBJ_20 /* UIDatePicker+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDatePicker+Combine.swift"; sourceTree = ""; }; - OBJ_21 /* UIGestureRecognizer+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIGestureRecognizer+Combine.swift"; sourceTree = ""; }; - OBJ_22 /* UIPageControl+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIPageControl+Combine.swift"; sourceTree = ""; }; - OBJ_23 /* UIRefreshControl+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIRefreshControl+Combine.swift"; sourceTree = ""; }; - OBJ_24 /* UIScrollView+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIScrollView+Combine.swift"; sourceTree = ""; }; - OBJ_25 /* UISearchBar+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UISearchBar+Combine.swift"; sourceTree = ""; }; - OBJ_26 /* UISegmentedControl+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UISegmentedControl+Combine.swift"; sourceTree = ""; }; - OBJ_27 /* UISlider+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UISlider+Combine.swift"; sourceTree = ""; }; - OBJ_28 /* UIStepper+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIStepper+Combine.swift"; sourceTree = ""; }; - OBJ_29 /* UISwitch+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UISwitch+Combine.swift"; sourceTree = ""; }; - OBJ_30 /* UITableView+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableView+Combine.swift"; sourceTree = ""; }; - OBJ_31 /* UITextField+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITextField+Combine.swift"; sourceTree = ""; }; - OBJ_32 /* UITextView+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITextView+Combine.swift"; sourceTree = ""; }; - OBJ_34 /* DelegateProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DelegateProxy.swift; sourceTree = ""; }; - OBJ_35 /* DelegateProxyPublisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DelegateProxyPublisher.swift; sourceTree = ""; }; - OBJ_36 /* DelegateProxyType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DelegateProxyType.swift; sourceTree = ""; }; - OBJ_38 /* ObjcDelegateProxy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ObjcDelegateProxy.m; sourceTree = ""; }; - OBJ_40 /* ObjcDelegateProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ObjcDelegateProxy.h; sourceTree = ""; }; - OBJ_41 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; name = module.modulemap; path = /Users/hsncr/Desktop/workspace/CombineCocoa/Sources/Runtime/include/module.modulemap; sourceTree = ""; }; - OBJ_46 /* Example */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Example; sourceTree = SOURCE_ROOT; }; - OBJ_47 /* Resources */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Resources; sourceTree = SOURCE_ROOT; }; - OBJ_48 /* scripts */ = {isa = PBXFileReference; lastKnownFileType = folder; path = scripts; sourceTree = SOURCE_ROOT; }; - OBJ_49 /* CODE_OF_CONDUCT.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CODE_OF_CONDUCT.md; sourceTree = ""; }; - OBJ_50 /* codecov.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = codecov.yml; sourceTree = ""; }; - OBJ_51 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; - OBJ_52 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; - OBJ_53 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; - OBJ_54 /* Gemfile */ = {isa = PBXFileReference; lastKnownFileType = text; path = Gemfile; sourceTree = ""; }; - OBJ_55 /* Gemfile.lock */ = {isa = PBXFileReference; lastKnownFileType = text; path = Gemfile.lock; sourceTree = ""; }; - OBJ_56 /* CombineCocoa.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = CombineCocoa.podspec; sourceTree = ""; }; - OBJ_6 /* Package.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; - OBJ_9 /* CombineCocoa.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CombineCocoa.h; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - OBJ_102 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - OBJ_87 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 0; - files = ( - OBJ_88 /* Runtime.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - OBJ_14 /* Controls */ = { - isa = PBXGroup; - children = ( - OBJ_15 /* NSTextStorage+Combine.swift */, - OBJ_16 /* UIBarButtonItem+Combine.swift */, - OBJ_17 /* UIButton+Combine.swift */, - OBJ_18 /* UICollectionView+Combine.swift */, - OBJ_19 /* UIControl+Combine.swift */, - OBJ_20 /* UIDatePicker+Combine.swift */, - OBJ_21 /* UIGestureRecognizer+Combine.swift */, - OBJ_22 /* UIPageControl+Combine.swift */, - OBJ_23 /* UIRefreshControl+Combine.swift */, - OBJ_24 /* UIScrollView+Combine.swift */, - OBJ_25 /* UISearchBar+Combine.swift */, - OBJ_26 /* UISegmentedControl+Combine.swift */, - OBJ_27 /* UISlider+Combine.swift */, - OBJ_28 /* UIStepper+Combine.swift */, - OBJ_29 /* UISwitch+Combine.swift */, - OBJ_30 /* UITableView+Combine.swift */, - OBJ_31 /* UITextField+Combine.swift */, - OBJ_32 /* UITextView+Combine.swift */, - ); - path = Controls; - sourceTree = ""; - }; - OBJ_33 /* DelegateProxy */ = { - isa = PBXGroup; - children = ( - OBJ_34 /* DelegateProxy.swift */, - OBJ_35 /* DelegateProxyPublisher.swift */, - OBJ_36 /* DelegateProxyType.swift */, - ); - path = DelegateProxy; - sourceTree = ""; - }; - OBJ_37 /* Runtime */ = { - isa = PBXGroup; - children = ( - OBJ_38 /* ObjcDelegateProxy.m */, - OBJ_39 /* include */, - ); - name = Runtime; - path = Sources/Runtime; - sourceTree = SOURCE_ROOT; - }; - OBJ_39 /* include */ = { - isa = PBXGroup; - children = ( - OBJ_40 /* ObjcDelegateProxy.h */, - OBJ_41 /* module.modulemap */, - ); - path = include; - sourceTree = ""; - }; - OBJ_42 /* Tests */ = { - isa = PBXGroup; - children = ( - ); - name = Tests; - sourceTree = SOURCE_ROOT; - }; - OBJ_43 /* Products */ = { - isa = PBXGroup; - children = ( - "CombineCocoa::Runtime::Product" /* Runtime.framework */, - "CombineCocoa::CombineCocoa::Product" /* CombineCocoa.framework */, - ); - name = Products; - sourceTree = BUILT_PRODUCTS_DIR; - }; - OBJ_5 /* */ = { - isa = PBXGroup; - children = ( - OBJ_6 /* Package.swift */, - OBJ_7 /* Sources */, - OBJ_42 /* Tests */, - OBJ_43 /* Products */, - OBJ_46 /* Example */, - OBJ_47 /* Resources */, - OBJ_48 /* scripts */, - OBJ_49 /* CODE_OF_CONDUCT.md */, - OBJ_50 /* codecov.yml */, - OBJ_51 /* LICENSE */, - OBJ_52 /* Makefile */, - OBJ_53 /* README.md */, - OBJ_54 /* Gemfile */, - OBJ_55 /* Gemfile.lock */, - OBJ_56 /* CombineCocoa.podspec */, - ); - name = ""; - sourceTree = ""; - }; - OBJ_7 /* Sources */ = { - isa = PBXGroup; - children = ( - OBJ_8 /* CombineCocoa */, - OBJ_37 /* Runtime */, - ); - name = Sources; - sourceTree = SOURCE_ROOT; - }; - OBJ_8 /* CombineCocoa */ = { - isa = PBXGroup; - children = ( - OBJ_9 /* CombineCocoa.h */, - OBJ_10 /* AnimatedAssignSubscriber.swift */, - OBJ_11 /* CombineControlEvent.swift */, - OBJ_12 /* CombineControlProperty.swift */, - OBJ_13 /* CombineControlTarget.swift */, - OBJ_14 /* Controls */, - OBJ_33 /* DelegateProxy */, - ); - name = CombineCocoa; - path = Sources/CombineCocoa; - sourceTree = SOURCE_ROOT; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - "CombineCocoa::CombineCocoa" /* CombineCocoa */ = { - isa = PBXNativeTarget; - buildConfigurationList = OBJ_58 /* Build configuration list for PBXNativeTarget "CombineCocoa" */; - buildPhases = ( - OBJ_61 /* Sources */, - OBJ_87 /* Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - OBJ_89 /* PBXTargetDependency */, - ); - name = CombineCocoa; - productName = CombineCocoa; - productReference = "CombineCocoa::CombineCocoa::Product" /* CombineCocoa.framework */; - productType = "com.apple.product-type.framework"; - }; - "CombineCocoa::Runtime" /* Runtime */ = { - isa = PBXNativeTarget; - buildConfigurationList = OBJ_97 /* Build configuration list for PBXNativeTarget "Runtime" */; - buildPhases = ( - OBJ_100 /* Sources */, - OBJ_102 /* Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runtime; - productName = Runtime; - productReference = "CombineCocoa::Runtime::Product" /* Runtime.framework */; - productType = "com.apple.product-type.framework"; - }; - "CombineCocoa::SwiftPMPackageDescription" /* CombineCocoaPackageDescription */ = { - isa = PBXNativeTarget; - buildConfigurationList = OBJ_92 /* Build configuration list for PBXNativeTarget "CombineCocoaPackageDescription" */; - buildPhases = ( - OBJ_95 /* Sources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = CombineCocoaPackageDescription; - productName = CombineCocoaPackageDescription; - productType = "com.apple.product-type.framework"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - OBJ_1 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftMigration = 9999; - LastUpgradeCheck = 9999; - }; - buildConfigurationList = OBJ_2 /* Build configuration list for PBXProject "CombineCocoa" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - ); - mainGroup = OBJ_5 /* */; - productRefGroup = OBJ_43 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - "CombineCocoa::CombineCocoa" /* CombineCocoa */, - "CombineCocoa::SwiftPMPackageDescription" /* CombineCocoaPackageDescription */, - "CombineCocoa::Runtime" /* Runtime */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXSourcesBuildPhase section */ - OBJ_100 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 0; - files = ( - OBJ_101 /* ObjcDelegateProxy.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - OBJ_61 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 0; - files = ( - OBJ_62 /* AnimatedAssignSubscriber.swift in Sources */, - OBJ_63 /* CombineControlEvent.swift in Sources */, - OBJ_64 /* CombineControlProperty.swift in Sources */, - OBJ_65 /* CombineControlTarget.swift in Sources */, - OBJ_66 /* NSTextStorage+Combine.swift in Sources */, - OBJ_67 /* UIBarButtonItem+Combine.swift in Sources */, - OBJ_68 /* UIButton+Combine.swift in Sources */, - OBJ_69 /* UICollectionView+Combine.swift in Sources */, - OBJ_70 /* UIControl+Combine.swift in Sources */, - OBJ_71 /* UIDatePicker+Combine.swift in Sources */, - OBJ_72 /* UIGestureRecognizer+Combine.swift in Sources */, - OBJ_73 /* UIPageControl+Combine.swift in Sources */, - OBJ_74 /* UIRefreshControl+Combine.swift in Sources */, - OBJ_75 /* UIScrollView+Combine.swift in Sources */, - OBJ_76 /* UISearchBar+Combine.swift in Sources */, - OBJ_77 /* UISegmentedControl+Combine.swift in Sources */, - OBJ_78 /* UISlider+Combine.swift in Sources */, - OBJ_79 /* UIStepper+Combine.swift in Sources */, - OBJ_80 /* UISwitch+Combine.swift in Sources */, - OBJ_81 /* UITableView+Combine.swift in Sources */, - OBJ_82 /* UITextField+Combine.swift in Sources */, - OBJ_83 /* UITextView+Combine.swift in Sources */, - OBJ_84 /* DelegateProxy.swift in Sources */, - OBJ_85 /* DelegateProxyPublisher.swift in Sources */, - OBJ_86 /* DelegateProxyType.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - OBJ_95 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 0; - files = ( - OBJ_96 /* Package.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - OBJ_89 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = "CombineCocoa::Runtime" /* Runtime */; - targetProxy = 61B996BE25EA62D200D6F6ED /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin XCBuildConfiguration section */ - OBJ_3 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ENABLE_OBJC_ARC = YES; - COMBINE_HIDPI_IMAGES = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_NS_ASSERTIONS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "$(inherited)", - "SWIFT_PACKAGE=1", - "DEBUG=1", - ); - MACOSX_DEPLOYMENT_TARGET = 10.10; - ONLY_ACTIVE_ARCH = YES; - OTHER_SWIFT_FLAGS = "$(inherited) -DXcode"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = macosx; - SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator"; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) SWIFT_PACKAGE DEBUG"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - USE_HEADERMAP = NO; - }; - name = Debug; - }; - OBJ_4 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ENABLE_OBJC_ARC = YES; - COMBINE_HIDPI_IMAGES = YES; - COPY_PHASE_STRIP = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GCC_OPTIMIZATION_LEVEL = s; - GCC_PREPROCESSOR_DEFINITIONS = ( - "$(inherited)", - "SWIFT_PACKAGE=1", - ); - MACOSX_DEPLOYMENT_TARGET = 10.10; - OTHER_SWIFT_FLAGS = "$(inherited) -DXcode"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = macosx; - SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator"; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) SWIFT_PACKAGE"; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - USE_HEADERMAP = NO; - }; - name = Release; - }; - OBJ_59 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ENABLE_TESTABILITY = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PLATFORM_DIR)/Developer/Library/Frameworks", - ); - HEADER_SEARCH_PATHS = ( - "$(inherited)", - "$(SRCROOT)/Sources/Runtime/include", - ); - INFOPLIST_FILE = CombineCocoa.xcodeproj/CombineCocoa_Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; - MACOSX_DEPLOYMENT_TARGET = 10.10; - OTHER_CFLAGS = "$(inherited)"; - OTHER_LDFLAGS = "$(inherited)"; - OTHER_SWIFT_FLAGS = "$(inherited) -Xcc -fmodule-map-file=$(SRCROOT)/Sources/Runtime/include/module.modulemap"; - PRODUCT_BUNDLE_IDENTIFIER = CombineCocoa; - PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)"; - SWIFT_INCLUDE_PATHS = "$(SRCROOT)/Sources/Runtime/include"; - SWIFT_VERSION = 5.0; - TARGET_NAME = CombineCocoa; - TVOS_DEPLOYMENT_TARGET = 9.0; - WATCHOS_DEPLOYMENT_TARGET = 2.0; - }; - name = Debug; - }; - OBJ_60 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ENABLE_TESTABILITY = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PLATFORM_DIR)/Developer/Library/Frameworks", - ); - HEADER_SEARCH_PATHS = ( - "$(inherited)", - "$(SRCROOT)/Sources/Runtime/include", - ); - INFOPLIST_FILE = CombineCocoa.xcodeproj/CombineCocoa_Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; - MACOSX_DEPLOYMENT_TARGET = 10.10; - OTHER_CFLAGS = "$(inherited)"; - OTHER_LDFLAGS = "$(inherited)"; - OTHER_SWIFT_FLAGS = "$(inherited) -Xcc -fmodule-map-file=$(SRCROOT)/Sources/Runtime/include/module.modulemap"; - PRODUCT_BUNDLE_IDENTIFIER = CombineCocoa; - PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)"; - SWIFT_INCLUDE_PATHS = "$(SRCROOT)/Sources/Runtime/include"; - SWIFT_VERSION = 5.0; - TARGET_NAME = CombineCocoa; - TVOS_DEPLOYMENT_TARGET = 9.0; - WATCHOS_DEPLOYMENT_TARGET = 2.0; - }; - name = Release; - }; - OBJ_93 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - LD = /usr/bin/true; - OTHER_SWIFT_FLAGS = "-swift-version 5 -I $(TOOLCHAIN_DIR)/usr/lib/swift/pm/4_2 -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk -package-description-version 5.1.0"; - SWIFT_VERSION = 5.0; - }; - name = Debug; - }; - OBJ_94 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - LD = /usr/bin/true; - OTHER_SWIFT_FLAGS = "-swift-version 5 -I $(TOOLCHAIN_DIR)/usr/lib/swift/pm/4_2 -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk -package-description-version 5.1.0"; - SWIFT_VERSION = 5.0; - }; - name = Release; - }; - OBJ_98 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - DEFINES_MODULE = NO; - ENABLE_TESTABILITY = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PLATFORM_DIR)/Developer/Library/Frameworks", - ); - HEADER_SEARCH_PATHS = ( - "$(inherited)", - "$(SRCROOT)/Sources/Runtime/include", - ); - INFOPLIST_FILE = CombineCocoa.xcodeproj/Runtime_Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; - MACOSX_DEPLOYMENT_TARGET = 10.10; - OTHER_CFLAGS = "$(inherited)"; - OTHER_LDFLAGS = "$(inherited)"; - OTHER_SWIFT_FLAGS = "$(inherited)"; - PRODUCT_BUNDLE_IDENTIFIER = Runtime; - PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)"; - TARGET_NAME = Runtime; - TVOS_DEPLOYMENT_TARGET = 9.0; - WATCHOS_DEPLOYMENT_TARGET = 2.0; - }; - name = Debug; - }; - OBJ_99 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - DEFINES_MODULE = NO; - ENABLE_TESTABILITY = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PLATFORM_DIR)/Developer/Library/Frameworks", - ); - HEADER_SEARCH_PATHS = ( - "$(inherited)", - "$(SRCROOT)/Sources/Runtime/include", - ); - INFOPLIST_FILE = CombineCocoa.xcodeproj/Runtime_Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; - MACOSX_DEPLOYMENT_TARGET = 10.10; - OTHER_CFLAGS = "$(inherited)"; - OTHER_LDFLAGS = "$(inherited)"; - OTHER_SWIFT_FLAGS = "$(inherited)"; - PRODUCT_BUNDLE_IDENTIFIER = Runtime; - PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)"; - TARGET_NAME = Runtime; - TVOS_DEPLOYMENT_TARGET = 9.0; - WATCHOS_DEPLOYMENT_TARGET = 2.0; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - OBJ_2 /* Build configuration list for PBXProject "CombineCocoa" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - OBJ_3 /* Debug */, - OBJ_4 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - OBJ_58 /* Build configuration list for PBXNativeTarget "CombineCocoa" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - OBJ_59 /* Debug */, - OBJ_60 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - OBJ_92 /* Build configuration list for PBXNativeTarget "CombineCocoaPackageDescription" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - OBJ_93 /* Debug */, - OBJ_94 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - OBJ_97 /* Build configuration list for PBXNativeTarget "Runtime" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - OBJ_98 /* Debug */, - OBJ_99 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = OBJ_1 /* Project object */; -} diff --git a/CombineCocoa.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/CombineCocoa.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index fe1aa71..0000000 --- a/CombineCocoa.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - \ No newline at end of file diff --git a/CombineCocoa.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/CombineCocoa.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d9810..0000000 --- a/CombineCocoa.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/CombineCocoa.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/CombineCocoa.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index a72dc2b..0000000 --- a/CombineCocoa.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded - - - \ No newline at end of file diff --git a/CombineCocoa.xcodeproj/xcshareddata/xcschemes/CombineCocoa-Package.xcscheme b/CombineCocoa.xcodeproj/xcshareddata/xcschemes/CombineCocoa-Package.xcscheme deleted file mode 100644 index 52033b0..0000000 --- a/CombineCocoa.xcodeproj/xcshareddata/xcschemes/CombineCocoa-Package.xcscheme +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/Package.swift b/Package.swift index 65b005b..60d232b 100644 --- a/Package.swift +++ b/Package.swift @@ -1,26 +1,23 @@ -// swift-tools-version:5.1 +// swift-tools-version:5.3 import PackageDescription let package = Package( - name: "CombineCocoa", - platforms: [.iOS(.v10)], - products: [ - .library(name: "CombineCocoa", targets: ["CombineCocoa"]), - ], - dependencies: [], - targets: [ - .target( - name: "CombineCocoa", - dependencies: [ - "CombineCocoaInterception", - "CombineCocoaRuntime" - ]), - .target( - name: "CombineCocoaInterception", - dependencies: [ - .target(name: "CombineCocoaRuntime") - ] - ), + name: "CombineCocoa", + products: [ + .library( + name: "CombineCocoa", + type: .static, + targets: ["CombineCocoa"] + ) + ], + dependencies: [], + targets: [ + .target( + name: "CombineCocoa", + dependencies: [ .target(name: "CombineCocoaRuntime") - ] + ] + ), + .target(name: "CombineCocoaRuntime"), + ] ) diff --git a/Sources/CombineCocoa/Exports.swift b/Sources/CombineCocoa/Exports.swift deleted file mode 100644 index 8f0ad2b..0000000 --- a/Sources/CombineCocoa/Exports.swift +++ /dev/null @@ -1,8 +0,0 @@ -// -// Exports.swift -// -// -// Created by Benjamin Deckys on 2023/07/27. -// - -@_exported import CombineCocoaInterception diff --git a/Sources/CombineCocoaInterception/NSObject+Association.swift b/Sources/CombineCocoa/Interception/NSObject+Association.swift similarity index 100% rename from Sources/CombineCocoaInterception/NSObject+Association.swift rename to Sources/CombineCocoa/Interception/NSObject+Association.swift diff --git a/Sources/CombineCocoaInterception/NSObject+Interseption.swift b/Sources/CombineCocoa/Interception/NSObject+Interseption.swift similarity index 100% rename from Sources/CombineCocoaInterception/NSObject+Interseption.swift rename to Sources/CombineCocoa/Interception/NSObject+Interseption.swift diff --git a/Sources/CombineCocoaInterception/NSObject+ObjCRuntime.swift b/Sources/CombineCocoa/Interception/NSObject+ObjCRuntime.swift similarity index 100% rename from Sources/CombineCocoaInterception/NSObject+ObjCRuntime.swift rename to Sources/CombineCocoa/Interception/NSObject+ObjCRuntime.swift diff --git a/Sources/CombineCocoaInterception/ObjC+Constants.swift b/Sources/CombineCocoa/Interception/ObjC+Constants.swift similarity index 100% rename from Sources/CombineCocoaInterception/ObjC+Constants.swift rename to Sources/CombineCocoa/Interception/ObjC+Constants.swift diff --git a/Sources/CombineCocoaInterception/ObjC+Messages.swift b/Sources/CombineCocoa/Interception/ObjC+Messages.swift similarity index 100% rename from Sources/CombineCocoaInterception/ObjC+Messages.swift rename to Sources/CombineCocoa/Interception/ObjC+Messages.swift diff --git a/Sources/CombineCocoaInterception/ObjC+Runtime.swift b/Sources/CombineCocoa/Interception/ObjC+Runtime.swift similarity index 100% rename from Sources/CombineCocoaInterception/ObjC+Runtime.swift rename to Sources/CombineCocoa/Interception/ObjC+Runtime.swift diff --git a/Sources/CombineCocoaInterception/ObjC+RuntimeSubclassing.swift b/Sources/CombineCocoa/Interception/ObjC+RuntimeSubclassing.swift similarity index 100% rename from Sources/CombineCocoaInterception/ObjC+RuntimeSubclassing.swift rename to Sources/CombineCocoa/Interception/ObjC+RuntimeSubclassing.swift diff --git a/Sources/CombineCocoaInterception/ObjC+Selector.swift b/Sources/CombineCocoa/Interception/ObjC+Selector.swift similarity index 100% rename from Sources/CombineCocoaInterception/ObjC+Selector.swift rename to Sources/CombineCocoa/Interception/ObjC+Selector.swift diff --git a/Sources/CombineCocoaInterception/Synchronizing.swift b/Sources/CombineCocoa/Interception/Synchronizing.swift similarity index 100% rename from Sources/CombineCocoaInterception/Synchronizing.swift rename to Sources/CombineCocoa/Interception/Synchronizing.swift From d90f4774b9da07f483f21b7d624809d62b9aec3b Mon Sep 17 00:00:00 2001 From: Benjamin Deckys Date: Fri, 28 Jul 2023 00:43:27 +0900 Subject: [PATCH 3/4] Restructure Project --- CombineCocoa.podspec | 8 +- .../CombineCocoa_Info.plist | 26 + CombineCocoa.xcodeproj/Runtime_Info.plist | 25 + CombineCocoa.xcodeproj/project.pbxproj | 606 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../xcschemes/CombineCocoa-Package.xcscheme | 73 +++ Package.swift | 30 +- Sources/CombineCocoa/CombineCocoa.h | 13 + .../DelegateProxy/DelegateProxy.swift | 4 +- .../Interception/NSObject+Association.swift | 4 +- .../Interception/NSObject+Interseption.swift | 4 +- .../ObjC+RuntimeSubclassing.swift | 4 +- .../CombineCocoaRuntime/ObjcDelegateProxy.m | 219 ------- Sources/Runtime/ObjcDelegateProxy.m | 220 +++++++ .../ObjcRuntimeAliases.m | 0 .../include/ObjcDelegateProxy.h | 0 .../include/ObjcRuntimeAliases.h | 0 .../include/module.modulemap | 2 +- 20 files changed, 1010 insertions(+), 251 deletions(-) create mode 100644 CombineCocoa.xcodeproj/CombineCocoa_Info.plist create mode 100644 CombineCocoa.xcodeproj/Runtime_Info.plist create mode 100644 CombineCocoa.xcodeproj/project.pbxproj create mode 100644 CombineCocoa.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 CombineCocoa.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 CombineCocoa.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 CombineCocoa.xcodeproj/xcshareddata/xcschemes/CombineCocoa-Package.xcscheme create mode 100644 Sources/CombineCocoa/CombineCocoa.h delete mode 100644 Sources/CombineCocoaRuntime/ObjcDelegateProxy.m create mode 100644 Sources/Runtime/ObjcDelegateProxy.m rename Sources/{CombineCocoaRuntime => Runtime}/ObjcRuntimeAliases.m (100%) rename Sources/{CombineCocoaRuntime => Runtime}/include/ObjcDelegateProxy.h (100%) rename Sources/{CombineCocoaRuntime => Runtime}/include/ObjcRuntimeAliases.h (100%) rename Sources/{CombineCocoaRuntime => Runtime}/include/module.modulemap (66%) diff --git a/CombineCocoa.podspec b/CombineCocoa.podspec index 55e83f4..4756533 100644 --- a/CombineCocoa.podspec +++ b/CombineCocoa.podspec @@ -1,14 +1,14 @@ Pod::Spec.new do |s| s.name = "CombineCocoa" - s.version = "0.4.2" + s.version = "0.4.1" s.summary = "CombineCocoa provided basic publisher bridges for UIControls in UIKit" s.description = <<-DESC Combine publisher bridges for Cocoa Controls (UIControl) in UIKit DESC - s.homepage = "https://github.com/viewdidappear/CombineCocoa" + s.homepage = "https://github.com/freak4pc/CombineCocoa" s.license = 'MIT' s.author = { "Shai Mishali" => "freak4pc@gmail.com" } - s.source = { :git => "https://github.com/viewdidappear/CombineCocoa.git", :tag => s.version.to_s } + s.source = { :git => "https://github.com/freak4pc/CombineCocoa.git", :tag => s.version.to_s } s.requires_arc = true @@ -17,4 +17,4 @@ Pod::Spec.new do |s| s.source_files = 'Sources/**/*.{swift,h,m}' s.frameworks = ['Combine', 'Foundation'] s.swift_version = '5.0' - end + end \ No newline at end of file diff --git a/CombineCocoa.xcodeproj/CombineCocoa_Info.plist b/CombineCocoa.xcodeproj/CombineCocoa_Info.plist new file mode 100644 index 0000000..e122590 --- /dev/null +++ b/CombineCocoa.xcodeproj/CombineCocoa_Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 0.2.1 + CFBundleSignature + ???? + CFBundleVersion + 0.2.1 + NSPrincipalClass + + + diff --git a/CombineCocoa.xcodeproj/Runtime_Info.plist b/CombineCocoa.xcodeproj/Runtime_Info.plist new file mode 100644 index 0000000..57ada9f --- /dev/null +++ b/CombineCocoa.xcodeproj/Runtime_Info.plist @@ -0,0 +1,25 @@ + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/CombineCocoa.xcodeproj/project.pbxproj b/CombineCocoa.xcodeproj/project.pbxproj new file mode 100644 index 0000000..10633da --- /dev/null +++ b/CombineCocoa.xcodeproj/project.pbxproj @@ -0,0 +1,606 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + OBJ_101 /* ObjcDelegateProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_38 /* ObjcDelegateProxy.m */; }; + OBJ_62 /* AnimatedAssignSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_10 /* AnimatedAssignSubscriber.swift */; }; + OBJ_63 /* CombineControlEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_11 /* CombineControlEvent.swift */; }; + OBJ_64 /* CombineControlProperty.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_12 /* CombineControlProperty.swift */; }; + OBJ_65 /* CombineControlTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_13 /* CombineControlTarget.swift */; }; + OBJ_66 /* NSTextStorage+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_15 /* NSTextStorage+Combine.swift */; }; + OBJ_67 /* UIBarButtonItem+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_16 /* UIBarButtonItem+Combine.swift */; }; + OBJ_68 /* UIButton+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_17 /* UIButton+Combine.swift */; }; + OBJ_69 /* UICollectionView+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_18 /* UICollectionView+Combine.swift */; }; + OBJ_70 /* UIControl+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_19 /* UIControl+Combine.swift */; }; + OBJ_71 /* UIDatePicker+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_20 /* UIDatePicker+Combine.swift */; }; + OBJ_72 /* UIGestureRecognizer+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_21 /* UIGestureRecognizer+Combine.swift */; }; + OBJ_73 /* UIPageControl+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_22 /* UIPageControl+Combine.swift */; }; + OBJ_74 /* UIRefreshControl+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_23 /* UIRefreshControl+Combine.swift */; }; + OBJ_75 /* UIScrollView+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_24 /* UIScrollView+Combine.swift */; }; + OBJ_76 /* UISearchBar+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_25 /* UISearchBar+Combine.swift */; }; + OBJ_77 /* UISegmentedControl+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_26 /* UISegmentedControl+Combine.swift */; }; + OBJ_78 /* UISlider+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_27 /* UISlider+Combine.swift */; }; + OBJ_79 /* UIStepper+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_28 /* UIStepper+Combine.swift */; }; + OBJ_80 /* UISwitch+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_29 /* UISwitch+Combine.swift */; }; + OBJ_81 /* UITableView+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_30 /* UITableView+Combine.swift */; }; + OBJ_82 /* UITextField+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_31 /* UITextField+Combine.swift */; }; + OBJ_83 /* UITextView+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_32 /* UITextView+Combine.swift */; }; + OBJ_84 /* DelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_34 /* DelegateProxy.swift */; }; + OBJ_85 /* DelegateProxyPublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_35 /* DelegateProxyPublisher.swift */; }; + OBJ_86 /* DelegateProxyType.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_36 /* DelegateProxyType.swift */; }; + OBJ_88 /* Runtime.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = "CombineCocoa::Runtime::Product" /* Runtime.framework */; }; + OBJ_96 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_6 /* Package.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 61B996BE25EA62D200D6F6ED /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = OBJ_1 /* Project object */; + proxyType = 1; + remoteGlobalIDString = "CombineCocoa::Runtime"; + remoteInfo = Runtime; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + "CombineCocoa::CombineCocoa::Product" /* CombineCocoa.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = CombineCocoa.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + "CombineCocoa::Runtime::Product" /* Runtime.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Runtime.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + OBJ_10 /* AnimatedAssignSubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnimatedAssignSubscriber.swift; sourceTree = ""; }; + OBJ_11 /* CombineControlEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CombineControlEvent.swift; sourceTree = ""; }; + OBJ_12 /* CombineControlProperty.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CombineControlProperty.swift; sourceTree = ""; }; + OBJ_13 /* CombineControlTarget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CombineControlTarget.swift; sourceTree = ""; }; + OBJ_15 /* NSTextStorage+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSTextStorage+Combine.swift"; sourceTree = ""; }; + OBJ_16 /* UIBarButtonItem+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIBarButtonItem+Combine.swift"; sourceTree = ""; }; + OBJ_17 /* UIButton+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIButton+Combine.swift"; sourceTree = ""; }; + OBJ_18 /* UICollectionView+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UICollectionView+Combine.swift"; sourceTree = ""; }; + OBJ_19 /* UIControl+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIControl+Combine.swift"; sourceTree = ""; }; + OBJ_20 /* UIDatePicker+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDatePicker+Combine.swift"; sourceTree = ""; }; + OBJ_21 /* UIGestureRecognizer+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIGestureRecognizer+Combine.swift"; sourceTree = ""; }; + OBJ_22 /* UIPageControl+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIPageControl+Combine.swift"; sourceTree = ""; }; + OBJ_23 /* UIRefreshControl+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIRefreshControl+Combine.swift"; sourceTree = ""; }; + OBJ_24 /* UIScrollView+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIScrollView+Combine.swift"; sourceTree = ""; }; + OBJ_25 /* UISearchBar+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UISearchBar+Combine.swift"; sourceTree = ""; }; + OBJ_26 /* UISegmentedControl+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UISegmentedControl+Combine.swift"; sourceTree = ""; }; + OBJ_27 /* UISlider+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UISlider+Combine.swift"; sourceTree = ""; }; + OBJ_28 /* UIStepper+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIStepper+Combine.swift"; sourceTree = ""; }; + OBJ_29 /* UISwitch+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UISwitch+Combine.swift"; sourceTree = ""; }; + OBJ_30 /* UITableView+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableView+Combine.swift"; sourceTree = ""; }; + OBJ_31 /* UITextField+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITextField+Combine.swift"; sourceTree = ""; }; + OBJ_32 /* UITextView+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITextView+Combine.swift"; sourceTree = ""; }; + OBJ_34 /* DelegateProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DelegateProxy.swift; sourceTree = ""; }; + OBJ_35 /* DelegateProxyPublisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DelegateProxyPublisher.swift; sourceTree = ""; }; + OBJ_36 /* DelegateProxyType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DelegateProxyType.swift; sourceTree = ""; }; + OBJ_38 /* ObjcDelegateProxy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ObjcDelegateProxy.m; sourceTree = ""; }; + OBJ_40 /* ObjcDelegateProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ObjcDelegateProxy.h; sourceTree = ""; }; + OBJ_41 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; name = module.modulemap; path = /Users/hsncr/Desktop/workspace/CombineCocoa/Sources/Runtime/include/module.modulemap; sourceTree = ""; }; + OBJ_46 /* Example */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Example; sourceTree = SOURCE_ROOT; }; + OBJ_47 /* Resources */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Resources; sourceTree = SOURCE_ROOT; }; + OBJ_48 /* scripts */ = {isa = PBXFileReference; lastKnownFileType = folder; path = scripts; sourceTree = SOURCE_ROOT; }; + OBJ_49 /* CODE_OF_CONDUCT.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CODE_OF_CONDUCT.md; sourceTree = ""; }; + OBJ_50 /* codecov.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = codecov.yml; sourceTree = ""; }; + OBJ_51 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; + OBJ_52 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; + OBJ_53 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + OBJ_54 /* Gemfile */ = {isa = PBXFileReference; lastKnownFileType = text; path = Gemfile; sourceTree = ""; }; + OBJ_55 /* Gemfile.lock */ = {isa = PBXFileReference; lastKnownFileType = text; path = Gemfile.lock; sourceTree = ""; }; + OBJ_56 /* CombineCocoa.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = CombineCocoa.podspec; sourceTree = ""; }; + OBJ_6 /* Package.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; + OBJ_9 /* CombineCocoa.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CombineCocoa.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + OBJ_102 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + OBJ_87 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 0; + files = ( + OBJ_88 /* Runtime.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + OBJ_14 /* Controls */ = { + isa = PBXGroup; + children = ( + OBJ_15 /* NSTextStorage+Combine.swift */, + OBJ_16 /* UIBarButtonItem+Combine.swift */, + OBJ_17 /* UIButton+Combine.swift */, + OBJ_18 /* UICollectionView+Combine.swift */, + OBJ_19 /* UIControl+Combine.swift */, + OBJ_20 /* UIDatePicker+Combine.swift */, + OBJ_21 /* UIGestureRecognizer+Combine.swift */, + OBJ_22 /* UIPageControl+Combine.swift */, + OBJ_23 /* UIRefreshControl+Combine.swift */, + OBJ_24 /* UIScrollView+Combine.swift */, + OBJ_25 /* UISearchBar+Combine.swift */, + OBJ_26 /* UISegmentedControl+Combine.swift */, + OBJ_27 /* UISlider+Combine.swift */, + OBJ_28 /* UIStepper+Combine.swift */, + OBJ_29 /* UISwitch+Combine.swift */, + OBJ_30 /* UITableView+Combine.swift */, + OBJ_31 /* UITextField+Combine.swift */, + OBJ_32 /* UITextView+Combine.swift */, + ); + path = Controls; + sourceTree = ""; + }; + OBJ_33 /* DelegateProxy */ = { + isa = PBXGroup; + children = ( + OBJ_34 /* DelegateProxy.swift */, + OBJ_35 /* DelegateProxyPublisher.swift */, + OBJ_36 /* DelegateProxyType.swift */, + ); + path = DelegateProxy; + sourceTree = ""; + }; + OBJ_37 /* Runtime */ = { + isa = PBXGroup; + children = ( + OBJ_38 /* ObjcDelegateProxy.m */, + OBJ_39 /* include */, + ); + name = Runtime; + path = Sources/Runtime; + sourceTree = SOURCE_ROOT; + }; + OBJ_39 /* include */ = { + isa = PBXGroup; + children = ( + OBJ_40 /* ObjcDelegateProxy.h */, + OBJ_41 /* module.modulemap */, + ); + path = include; + sourceTree = ""; + }; + OBJ_42 /* Tests */ = { + isa = PBXGroup; + children = ( + ); + name = Tests; + sourceTree = SOURCE_ROOT; + }; + OBJ_43 /* Products */ = { + isa = PBXGroup; + children = ( + "CombineCocoa::Runtime::Product" /* Runtime.framework */, + "CombineCocoa::CombineCocoa::Product" /* CombineCocoa.framework */, + ); + name = Products; + sourceTree = BUILT_PRODUCTS_DIR; + }; + OBJ_5 /* */ = { + isa = PBXGroup; + children = ( + OBJ_6 /* Package.swift */, + OBJ_7 /* Sources */, + OBJ_42 /* Tests */, + OBJ_43 /* Products */, + OBJ_46 /* Example */, + OBJ_47 /* Resources */, + OBJ_48 /* scripts */, + OBJ_49 /* CODE_OF_CONDUCT.md */, + OBJ_50 /* codecov.yml */, + OBJ_51 /* LICENSE */, + OBJ_52 /* Makefile */, + OBJ_53 /* README.md */, + OBJ_54 /* Gemfile */, + OBJ_55 /* Gemfile.lock */, + OBJ_56 /* CombineCocoa.podspec */, + ); + name = ""; + sourceTree = ""; + }; + OBJ_7 /* Sources */ = { + isa = PBXGroup; + children = ( + OBJ_8 /* CombineCocoa */, + OBJ_37 /* Runtime */, + ); + name = Sources; + sourceTree = SOURCE_ROOT; + }; + OBJ_8 /* CombineCocoa */ = { + isa = PBXGroup; + children = ( + OBJ_9 /* CombineCocoa.h */, + OBJ_10 /* AnimatedAssignSubscriber.swift */, + OBJ_11 /* CombineControlEvent.swift */, + OBJ_12 /* CombineControlProperty.swift */, + OBJ_13 /* CombineControlTarget.swift */, + OBJ_14 /* Controls */, + OBJ_33 /* DelegateProxy */, + ); + name = CombineCocoa; + path = Sources/CombineCocoa; + sourceTree = SOURCE_ROOT; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + "CombineCocoa::CombineCocoa" /* CombineCocoa */ = { + isa = PBXNativeTarget; + buildConfigurationList = OBJ_58 /* Build configuration list for PBXNativeTarget "CombineCocoa" */; + buildPhases = ( + OBJ_61 /* Sources */, + OBJ_87 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + OBJ_89 /* PBXTargetDependency */, + ); + name = CombineCocoa; + productName = CombineCocoa; + productReference = "CombineCocoa::CombineCocoa::Product" /* CombineCocoa.framework */; + productType = "com.apple.product-type.framework"; + }; + "CombineCocoa::Runtime" /* Runtime */ = { + isa = PBXNativeTarget; + buildConfigurationList = OBJ_97 /* Build configuration list for PBXNativeTarget "Runtime" */; + buildPhases = ( + OBJ_100 /* Sources */, + OBJ_102 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runtime; + productName = Runtime; + productReference = "CombineCocoa::Runtime::Product" /* Runtime.framework */; + productType = "com.apple.product-type.framework"; + }; + "CombineCocoa::SwiftPMPackageDescription" /* CombineCocoaPackageDescription */ = { + isa = PBXNativeTarget; + buildConfigurationList = OBJ_92 /* Build configuration list for PBXNativeTarget "CombineCocoaPackageDescription" */; + buildPhases = ( + OBJ_95 /* Sources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = CombineCocoaPackageDescription; + productName = CombineCocoaPackageDescription; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + OBJ_1 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftMigration = 9999; + LastUpgradeCheck = 9999; + }; + buildConfigurationList = OBJ_2 /* Build configuration list for PBXProject "CombineCocoa" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = OBJ_5 /* */; + productRefGroup = OBJ_43 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + "CombineCocoa::CombineCocoa" /* CombineCocoa */, + "CombineCocoa::SwiftPMPackageDescription" /* CombineCocoaPackageDescription */, + "CombineCocoa::Runtime" /* Runtime */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + OBJ_100 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 0; + files = ( + OBJ_101 /* ObjcDelegateProxy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + OBJ_61 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 0; + files = ( + OBJ_62 /* AnimatedAssignSubscriber.swift in Sources */, + OBJ_63 /* CombineControlEvent.swift in Sources */, + OBJ_64 /* CombineControlProperty.swift in Sources */, + OBJ_65 /* CombineControlTarget.swift in Sources */, + OBJ_66 /* NSTextStorage+Combine.swift in Sources */, + OBJ_67 /* UIBarButtonItem+Combine.swift in Sources */, + OBJ_68 /* UIButton+Combine.swift in Sources */, + OBJ_69 /* UICollectionView+Combine.swift in Sources */, + OBJ_70 /* UIControl+Combine.swift in Sources */, + OBJ_71 /* UIDatePicker+Combine.swift in Sources */, + OBJ_72 /* UIGestureRecognizer+Combine.swift in Sources */, + OBJ_73 /* UIPageControl+Combine.swift in Sources */, + OBJ_74 /* UIRefreshControl+Combine.swift in Sources */, + OBJ_75 /* UIScrollView+Combine.swift in Sources */, + OBJ_76 /* UISearchBar+Combine.swift in Sources */, + OBJ_77 /* UISegmentedControl+Combine.swift in Sources */, + OBJ_78 /* UISlider+Combine.swift in Sources */, + OBJ_79 /* UIStepper+Combine.swift in Sources */, + OBJ_80 /* UISwitch+Combine.swift in Sources */, + OBJ_81 /* UITableView+Combine.swift in Sources */, + OBJ_82 /* UITextField+Combine.swift in Sources */, + OBJ_83 /* UITextView+Combine.swift in Sources */, + OBJ_84 /* DelegateProxy.swift in Sources */, + OBJ_85 /* DelegateProxyPublisher.swift in Sources */, + OBJ_86 /* DelegateProxyType.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + OBJ_95 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 0; + files = ( + OBJ_96 /* Package.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + OBJ_89 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = "CombineCocoa::Runtime" /* Runtime */; + targetProxy = 61B996BE25EA62D200D6F6ED /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + OBJ_3 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_ARC = YES; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_NS_ASSERTIONS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "SWIFT_PACKAGE=1", + "DEBUG=1", + ); + MACOSX_DEPLOYMENT_TARGET = 10.10; + ONLY_ACTIVE_ARCH = YES; + OTHER_SWIFT_FLAGS = "$(inherited) -DXcode"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) SWIFT_PACKAGE DEBUG"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + USE_HEADERMAP = NO; + }; + name = Debug; + }; + OBJ_4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_ARC = YES; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_OPTIMIZATION_LEVEL = s; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "SWIFT_PACKAGE=1", + ); + MACOSX_DEPLOYMENT_TARGET = 10.10; + OTHER_SWIFT_FLAGS = "$(inherited) -DXcode"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) SWIFT_PACKAGE"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + USE_HEADERMAP = NO; + }; + name = Release; + }; + OBJ_59 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)/Sources/Runtime/include", + ); + INFOPLIST_FILE = CombineCocoa.xcodeproj/CombineCocoa_Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; + MACOSX_DEPLOYMENT_TARGET = 10.10; + OTHER_CFLAGS = "$(inherited)"; + OTHER_LDFLAGS = "$(inherited)"; + OTHER_SWIFT_FLAGS = "$(inherited) -Xcc -fmodule-map-file=$(SRCROOT)/Sources/Runtime/include/module.modulemap"; + PRODUCT_BUNDLE_IDENTIFIER = CombineCocoa; + PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)"; + SWIFT_INCLUDE_PATHS = "$(SRCROOT)/Sources/Runtime/include"; + SWIFT_VERSION = 5.0; + TARGET_NAME = CombineCocoa; + TVOS_DEPLOYMENT_TARGET = 9.0; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = Debug; + }; + OBJ_60 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)/Sources/Runtime/include", + ); + INFOPLIST_FILE = CombineCocoa.xcodeproj/CombineCocoa_Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; + MACOSX_DEPLOYMENT_TARGET = 10.10; + OTHER_CFLAGS = "$(inherited)"; + OTHER_LDFLAGS = "$(inherited)"; + OTHER_SWIFT_FLAGS = "$(inherited) -Xcc -fmodule-map-file=$(SRCROOT)/Sources/Runtime/include/module.modulemap"; + PRODUCT_BUNDLE_IDENTIFIER = CombineCocoa; + PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)"; + SWIFT_INCLUDE_PATHS = "$(SRCROOT)/Sources/Runtime/include"; + SWIFT_VERSION = 5.0; + TARGET_NAME = CombineCocoa; + TVOS_DEPLOYMENT_TARGET = 9.0; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = Release; + }; + OBJ_93 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + LD = /usr/bin/true; + OTHER_SWIFT_FLAGS = "-swift-version 5 -I $(TOOLCHAIN_DIR)/usr/lib/swift/pm/4_2 -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk -package-description-version 5.1.0"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + OBJ_94 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + LD = /usr/bin/true; + OTHER_SWIFT_FLAGS = "-swift-version 5 -I $(TOOLCHAIN_DIR)/usr/lib/swift/pm/4_2 -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk -package-description-version 5.1.0"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + OBJ_98 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + DEFINES_MODULE = NO; + ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)/Sources/Runtime/include", + ); + INFOPLIST_FILE = CombineCocoa.xcodeproj/Runtime_Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; + MACOSX_DEPLOYMENT_TARGET = 10.10; + OTHER_CFLAGS = "$(inherited)"; + OTHER_LDFLAGS = "$(inherited)"; + OTHER_SWIFT_FLAGS = "$(inherited)"; + PRODUCT_BUNDLE_IDENTIFIER = Runtime; + PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)"; + TARGET_NAME = Runtime; + TVOS_DEPLOYMENT_TARGET = 9.0; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = Debug; + }; + OBJ_99 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + DEFINES_MODULE = NO; + ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)/Sources/Runtime/include", + ); + INFOPLIST_FILE = CombineCocoa.xcodeproj/Runtime_Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; + MACOSX_DEPLOYMENT_TARGET = 10.10; + OTHER_CFLAGS = "$(inherited)"; + OTHER_LDFLAGS = "$(inherited)"; + OTHER_SWIFT_FLAGS = "$(inherited)"; + PRODUCT_BUNDLE_IDENTIFIER = Runtime; + PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)"; + TARGET_NAME = Runtime; + TVOS_DEPLOYMENT_TARGET = 9.0; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + OBJ_2 /* Build configuration list for PBXProject "CombineCocoa" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_3 /* Debug */, + OBJ_4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + OBJ_58 /* Build configuration list for PBXNativeTarget "CombineCocoa" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_59 /* Debug */, + OBJ_60 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + OBJ_92 /* Build configuration list for PBXNativeTarget "CombineCocoaPackageDescription" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_93 /* Debug */, + OBJ_94 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + OBJ_97 /* Build configuration list for PBXNativeTarget "Runtime" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_98 /* Debug */, + OBJ_99 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = OBJ_1 /* Project object */; +} diff --git a/CombineCocoa.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/CombineCocoa.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..fe1aa71 --- /dev/null +++ b/CombineCocoa.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/CombineCocoa.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/CombineCocoa.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/CombineCocoa.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/CombineCocoa.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/CombineCocoa.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..a72dc2b --- /dev/null +++ b/CombineCocoa.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded + + + \ No newline at end of file diff --git a/CombineCocoa.xcodeproj/xcshareddata/xcschemes/CombineCocoa-Package.xcscheme b/CombineCocoa.xcodeproj/xcshareddata/xcschemes/CombineCocoa-Package.xcscheme new file mode 100644 index 0000000..5b8c1fa --- /dev/null +++ b/CombineCocoa.xcodeproj/xcshareddata/xcschemes/CombineCocoa-Package.xcscheme @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Package.swift b/Package.swift index 60d232b..564f05a 100644 --- a/Package.swift +++ b/Package.swift @@ -1,23 +1,15 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.1 import PackageDescription let package = Package( - name: "CombineCocoa", - products: [ - .library( - name: "CombineCocoa", - type: .static, - targets: ["CombineCocoa"] - ) - ], - dependencies: [], - targets: [ - .target( - name: "CombineCocoa", - dependencies: [ - .target(name: "CombineCocoaRuntime") - ] - ), - .target(name: "CombineCocoaRuntime"), - ] + name: "CombineCocoa", + platforms: [.iOS(.v10)], + products: [ + .library(name: "CombineCocoa", targets: ["CombineCocoa"]), + ], + dependencies: [], + targets: [ + .target(name: "CombineCocoa", dependencies: ["Runtime"]), + .target(name: "Runtime", dependencies: []) + ] ) diff --git a/Sources/CombineCocoa/CombineCocoa.h b/Sources/CombineCocoa/CombineCocoa.h new file mode 100644 index 0000000..dd8db20 --- /dev/null +++ b/Sources/CombineCocoa/CombineCocoa.h @@ -0,0 +1,13 @@ +// +// CombineCocoa.h +// CombineCocoa +// +// Created by Joan Disho on 25/09/2019. +// Copyright © 2020 Combine Community. All rights reserved. +// + +#import +#import + +FOUNDATION_EXPORT double CombineCocoaVersionNumber; +FOUNDATION_EXPORT const unsigned char CombineCocoaVersionString[]; diff --git a/Sources/CombineCocoa/DelegateProxy/DelegateProxy.swift b/Sources/CombineCocoa/DelegateProxy/DelegateProxy.swift index 7a73454..d3aae10 100644 --- a/Sources/CombineCocoa/DelegateProxy/DelegateProxy.swift +++ b/Sources/CombineCocoa/DelegateProxy/DelegateProxy.swift @@ -10,8 +10,8 @@ import Foundation import Combine -#if canImport(CombineCocoaRuntime) -import CombineCocoaRuntime +#if canImport(Runtime) +import Runtime #endif @available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) diff --git a/Sources/CombineCocoa/Interception/NSObject+Association.swift b/Sources/CombineCocoa/Interception/NSObject+Association.swift index a22b384..7b78d15 100644 --- a/Sources/CombineCocoa/Interception/NSObject+Association.swift +++ b/Sources/CombineCocoa/Interception/NSObject+Association.swift @@ -8,8 +8,8 @@ import Foundation -#if canImport(CombineCocoaRuntime) - import CombineCocoaRuntime +#if canImport(Runtime) + import Runtime #endif internal struct AssociationKey { diff --git a/Sources/CombineCocoa/Interception/NSObject+Interseption.swift b/Sources/CombineCocoa/Interception/NSObject+Interseption.swift index fbe353f..9648c78 100644 --- a/Sources/CombineCocoa/Interception/NSObject+Interseption.swift +++ b/Sources/CombineCocoa/Interception/NSObject+Interseption.swift @@ -10,8 +10,8 @@ import Combine import Foundation -#if canImport(CombineCocoaRuntime) - import CombineCocoaRuntime +#if canImport(Runtime) + import Runtime #endif /// Whether the runtime subclass has already been prepared for method diff --git a/Sources/CombineCocoa/Interception/ObjC+RuntimeSubclassing.swift b/Sources/CombineCocoa/Interception/ObjC+RuntimeSubclassing.swift index 421a8ba..6b5be92 100644 --- a/Sources/CombineCocoa/Interception/ObjC+RuntimeSubclassing.swift +++ b/Sources/CombineCocoa/Interception/ObjC+RuntimeSubclassing.swift @@ -10,8 +10,8 @@ import Combine import Foundation -#if canImport(CombineCocoaRuntime) - import CombineCocoaRuntime +#if canImport(Runtime) + import Runtime #endif /// Whether the runtime subclass has already been swizzled. diff --git a/Sources/CombineCocoaRuntime/ObjcDelegateProxy.m b/Sources/CombineCocoaRuntime/ObjcDelegateProxy.m deleted file mode 100644 index 44963c8..0000000 --- a/Sources/CombineCocoaRuntime/ObjcDelegateProxy.m +++ /dev/null @@ -1,219 +0,0 @@ -// -// ObjcDelegateProxy.m -// CombineCocoa -// -// Created by Joan Disho & Shai Mishali on 25/09/2019. -// Copyright © 2020 Combine Community. All rights reserved. -// - -#import -#import "include/ObjcDelegateProxy.h" -#import - -#define OBJECT_VALUE(object) [NSValue valueWithNonretainedObject:(object)] - -static NSMutableDictionary *> *allSelectors; - -@implementation ObjcDelegateProxy - -- (NSSet *)selectors { - return allSelectors[OBJECT_VALUE(self.class)]; -} - -+ (void)initialize -{ - @synchronized (ObjcDelegateProxy.class) { - if (!allSelectors) { - allSelectors = [NSMutableDictionary new]; - } - allSelectors[OBJECT_VALUE(self)] = [self selectorsOfClass:self - withEncodedReturnType:[NSString stringWithFormat:@"%s", @encode(void)]]; - } -} - -- (BOOL)respondsToSelector:(SEL _Nonnull)aSelector { - return [super respondsToSelector:aSelector] || [self canRespondToSelector:aSelector]; -} - -- (BOOL)canRespondToSelector:(SEL _Nonnull)selector { - for (id current in allSelectors[OBJECT_VALUE(self.class)]) { - if (selector == (SEL) [current pointerValue]) { - return true; - } - } - - return false; -} - -- (void)interceptedSelector:(SEL _Nonnull)selector arguments:(NSArray * _Nonnull)arguments {} - -- (void)forwardInvocation:(NSInvocation *)anInvocation -{ - NSArray * _Nonnull arguments = unpackInvocation(anInvocation); - [self interceptedSelector:anInvocation.selector arguments:arguments]; -} - -NSArray * _Nonnull unpackInvocation(NSInvocation * _Nonnull invocation) { - NSUInteger numberOfArguments = invocation.methodSignature.numberOfArguments; - NSMutableArray *arguments = [NSMutableArray arrayWithCapacity:numberOfArguments - 2]; - - // Ignore `self` and `_cmd` at index 0 and 1. - for (NSUInteger index = 2; index < numberOfArguments; ++index) { - const char *argumentType = [invocation.methodSignature getArgumentTypeAtIndex:index]; - - // Skip const type qualifier. - if (argumentType[0] == 'r') { - argumentType++; - } - -#define isArgumentType(type) \ -strcmp(argumentType, @encode(type)) == 0 - -#define extractTypeAndSetValue(type, value) \ -type argument = 0; \ -[invocation getArgument:&argument atIndex:index]; \ -value = @(argument); \ - - id _Nonnull value; - - if (isArgumentType(id) || isArgumentType(Class) || isArgumentType(void (^)(void))) { - __unsafe_unretained id argument = nil; - [invocation getArgument:&argument atIndex:index]; - value = argument; - } - else if (isArgumentType(char)) { - extractTypeAndSetValue(char, value); - } - else if (isArgumentType(short)) { - extractTypeAndSetValue(short, value); - } - else if (isArgumentType(int)) { - extractTypeAndSetValue(int, value); - } - else if (isArgumentType(long)) { - extractTypeAndSetValue(long, value); - } - else if (isArgumentType(long long)) { - extractTypeAndSetValue(long long, value); - } - else if (isArgumentType(unsigned char)) { - extractTypeAndSetValue(unsigned char, value); - } - else if (isArgumentType(unsigned short)) { - extractTypeAndSetValue(unsigned short, value); - } - else if (isArgumentType(unsigned int)) { - extractTypeAndSetValue(unsigned int, value); - } - else if (isArgumentType(unsigned long)) { - extractTypeAndSetValue(unsigned long, value); - } - else if (isArgumentType(unsigned long long)) { - extractTypeAndSetValue(unsigned long long, value); - } - else if (isArgumentType(float)) { - extractTypeAndSetValue(float, value); - } - else if (isArgumentType(double)) { - extractTypeAndSetValue(double, value); - } - else if (isArgumentType(BOOL)) { - extractTypeAndSetValue(BOOL, value); - } - else if (isArgumentType(const char *)) { - extractTypeAndSetValue(const char *, value); - } - else { - NSUInteger size = 0; - NSGetSizeAndAlignment(argumentType, &size, NULL); - NSCParameterAssert(size > 0); - uint8_t data[size]; - [invocation getArgument:&data atIndex:index]; - - value = [NSValue valueWithBytes:&data objCType:argumentType]; - } - - [arguments addObject:value]; - } - - return arguments; -} - -+ (NSSet *) selectorsOfClass: (Class _Nonnull __unsafe_unretained) class - withEncodedReturnType: (NSString *) encodedReturnType { - unsigned int protocolsCount = 0; - Protocol * __unsafe_unretained _Nonnull * _Nullable protocolPointer = class_copyProtocolList(class, &protocolsCount); - - NSMutableSet *allSelectors = [[self selectorsOfProtocolPointer:protocolPointer - count:protocolsCount - andEncodedReturnType:encodedReturnType] mutableCopy]; - - Class _Nonnull __unsafe_unretained superclass = class_getSuperclass(class); - - if(superclass != nil) { - NSSet *superclassSelectors = [self selectorsOfClass:superclass - withEncodedReturnType:encodedReturnType]; - [allSelectors unionSet:superclassSelectors]; - } - - free(protocolPointer); - - return allSelectors; -} - -+ (NSSet *) selectorsOfProtocol: (Protocol * __unsafe_unretained) protocol - andEncodedReturnType: (NSString *) encodedReturnType { - unsigned int protocolMethodCount = 0; - struct objc_method_description * _Nullable methodDescriptions = protocol_copyMethodDescriptionList(protocol, false, true, &protocolMethodCount); - - // Protocol pointers - unsigned int protocolsCount = 0; - Protocol * __unsafe_unretained _Nonnull * _Nullable protocols = protocol_copyProtocolList(protocol, &protocolsCount); - - NSMutableSet *allSelectors = [NSMutableSet new]; - - // Protocol methods - for (NSInteger idx = 0; idx < protocolMethodCount; idx++) { - struct objc_method_description description = methodDescriptions[idx]; - - if ([self encodedMethodReturnTypeForMethod:description] == encodedReturnType) { - [allSelectors addObject: [NSValue valueWithPointer:description.name]]; - } - } - - if (protocols != nil) { - [allSelectors unionSet: [self selectorsOfProtocolPointer:protocols - count:protocolsCount - andEncodedReturnType:encodedReturnType]]; - } - - free(methodDescriptions); - free(protocols); - - return allSelectors; -} - -+ (NSSet *) selectorsOfProtocolPointer: (Protocol * __unsafe_unretained * _Nullable) pointer - count: (NSInteger) count - andEncodedReturnType: (NSString *) encodedReturnType { - NSMutableSet *allSelectors = [NSMutableSet new]; - - for (NSInteger i = 0; i < count; i++) { - Protocol * __unsafe_unretained _Nullable protocol = pointer[i]; - - if (protocol == nil) { continue; } - [allSelectors unionSet:[self selectorsOfProtocol:protocol - andEncodedReturnType:encodedReturnType]]; - } - - return allSelectors; -} - -+ (NSString *)encodedMethodReturnTypeForMethod: (struct objc_method_description) method { - return [[NSString alloc] initWithBytes:method.types - length:1 - encoding:NSASCIIStringEncoding]; -} - - -@end diff --git a/Sources/Runtime/ObjcDelegateProxy.m b/Sources/Runtime/ObjcDelegateProxy.m new file mode 100644 index 0000000..9ae5624 --- /dev/null +++ b/Sources/Runtime/ObjcDelegateProxy.m @@ -0,0 +1,220 @@ +// +// ObjcDelegateProxy.m +// CombineCocoa +// +// Created by Joan Disho & Shai Mishali on 25/09/2019. +// Copyright © 2020 Combine Community. All rights reserved. +// + +#import +#import "include/ObjcDelegateProxy.h" +#import + +#define OBJECT_VALUE(object) [NSValue valueWithNonretainedObject:(object)] + +static NSMutableDictionary *> *allSelectors; + +@implementation ObjcDelegateProxy + +- (NSSet *)selectors { + return allSelectors[OBJECT_VALUE(self.class)]; +} + ++ (void)initialize +{ + @synchronized (ObjcDelegateProxy.class) { + if (!allSelectors) { + allSelectors = [NSMutableDictionary new]; + } + allSelectors[OBJECT_VALUE(self)] = [self selectorsOfClass:self + withEncodedReturnType:[NSString stringWithFormat:@"%s", @encode(void)]]; + } +} + +- (BOOL)respondsToSelector:(SEL _Nonnull)aSelector { + return [super respondsToSelector:aSelector] || [self canRespondToSelector:aSelector]; +} + +- (BOOL)canRespondToSelector:(SEL _Nonnull)selector { + for (id current in allSelectors[OBJECT_VALUE(self.class)]) { + if (selector == (SEL) [current pointerValue]) { + return true; + } + } + + return false; +} + +- (void)interceptedSelector:(SEL _Nonnull)selector arguments:(NSArray * _Nonnull)arguments {} + +- (void)forwardInvocation:(NSInvocation *)anInvocation +{ + NSArray * _Nonnull arguments = unpackInvocation(anInvocation); + [self interceptedSelector:anInvocation.selector arguments:arguments]; +} + +NSArray * _Nonnull unpackInvocation(NSInvocation * _Nonnull invocation) { + NSUInteger numberOfArguments = invocation.methodSignature.numberOfArguments; + NSMutableArray *arguments = [NSMutableArray arrayWithCapacity:numberOfArguments - 2]; + + // Ignore `self` and `_cmd` at index 0 and 1. + for (NSUInteger index = 2; index < numberOfArguments; ++index) { + const char *argumentType = [invocation.methodSignature getArgumentTypeAtIndex:index]; + + // Skip const type qualifier. + if (argumentType[0] == 'r') { + argumentType++; + } + + #define isArgumentType(type) \ + strcmp(argumentType, @encode(type)) == 0 + + #define extractTypeAndSetValue(type, value) \ + type argument = 0; \ + [invocation getArgument:&argument atIndex:index]; \ + value = @(argument); \ + + id _Nonnull value; + + if (isArgumentType(id) || isArgumentType(Class) || isArgumentType(void (^)(void))) { + __unsafe_unretained id argument = nil; + [invocation getArgument:&argument atIndex:index]; + value = argument; + } + else if (isArgumentType(char)) { + extractTypeAndSetValue(char, value); + } + else if (isArgumentType(short)) { + extractTypeAndSetValue(short, value); + } + else if (isArgumentType(int)) { + extractTypeAndSetValue(int, value); + } + else if (isArgumentType(long)) { + extractTypeAndSetValue(long, value); + } + else if (isArgumentType(long long)) { + extractTypeAndSetValue(long long, value); + } + else if (isArgumentType(unsigned char)) { + extractTypeAndSetValue(unsigned char, value); + } + else if (isArgumentType(unsigned short)) { + extractTypeAndSetValue(unsigned short, value); + } + else if (isArgumentType(unsigned int)) { + extractTypeAndSetValue(unsigned int, value); + } + else if (isArgumentType(unsigned long)) { + extractTypeAndSetValue(unsigned long, value); + } + else if (isArgumentType(unsigned long long)) { + extractTypeAndSetValue(unsigned long long, value); + } + else if (isArgumentType(float)) { + extractTypeAndSetValue(float, value); + } + else if (isArgumentType(double)) { + extractTypeAndSetValue(double, value); + } + else if (isArgumentType(BOOL)) { + extractTypeAndSetValue(BOOL, value); + } + else if (isArgumentType(const char *)) { + extractTypeAndSetValue(const char *, value); + } + else { + NSUInteger size = 0; + NSGetSizeAndAlignment(argumentType, &size, NULL); + NSCParameterAssert(size > 0); + uint8_t data[size]; + [invocation getArgument:&data atIndex:index]; + + value = [NSValue valueWithBytes:&data objCType:argumentType]; + } + + [arguments addObject:value]; + } + + return arguments; +} + ++ (NSSet *) selectorsOfClass: (Class _Nonnull __unsafe_unretained) class + withEncodedReturnType: (NSString *) encodedReturnType { + unsigned int protocolsCount = 0; + Protocol * __unsafe_unretained _Nonnull * _Nullable protocolPointer = class_copyProtocolList(class, &protocolsCount); + + NSMutableSet *allSelectors = [[self selectorsOfProtocolPointer:protocolPointer + count:protocolsCount + andEncodedReturnType:encodedReturnType] mutableCopy]; + + Class _Nonnull __unsafe_unretained superclass = class_getSuperclass(class); + + if(superclass != nil) { + NSSet *superclassSelectors = [self selectorsOfClass:superclass + withEncodedReturnType:encodedReturnType]; + [allSelectors unionSet:superclassSelectors]; + } + + free(protocolPointer); + + return allSelectors; +} + ++ (NSSet *) selectorsOfProtocol: (Protocol * __unsafe_unretained) protocol + andEncodedReturnType: (NSString *) encodedReturnType { + unsigned int protocolMethodCount = 0; + struct objc_method_description * _Nullable methodDescriptions = protocol_copyMethodDescriptionList(protocol, false, true, &protocolMethodCount); + + // Protocol pointers + unsigned int protocolsCount = 0; + Protocol * __unsafe_unretained _Nonnull * _Nullable protocols = protocol_copyProtocolList(protocol, &protocolsCount); + + NSMutableSet *allSelectors = [NSMutableSet new]; + + // Protocol methods + for (NSInteger idx = 0; idx < protocolMethodCount; idx++) { + struct objc_method_description description = methodDescriptions[idx]; + + if ([self encodedMethodReturnTypeForMethod:description] == encodedReturnType) { + [allSelectors addObject: [NSValue valueWithPointer:description.name]]; + } + } + + if (protocols != nil) { + [allSelectors unionSet: [self selectorsOfProtocolPointer:protocols + count:protocolsCount + andEncodedReturnType:encodedReturnType]]; + } + + free(methodDescriptions); + free(protocols); + + return allSelectors; +} + ++ (NSSet *) selectorsOfProtocolPointer: (Protocol * __unsafe_unretained * _Nullable) pointer + count: (NSInteger) count + andEncodedReturnType: (NSString *) encodedReturnType { + NSMutableSet *allSelectors = [NSMutableSet new]; + + for (NSInteger i = 0; i < count; i++) { + Protocol * __unsafe_unretained _Nullable protocol = pointer[i]; + + if (protocol == nil) { continue; } + [allSelectors unionSet:[self selectorsOfProtocol:protocol + andEncodedReturnType:encodedReturnType]]; + } + + return allSelectors; +} + ++ (NSString *)encodedMethodReturnTypeForMethod: (struct objc_method_description) method { + return [[NSString alloc] initWithBytes:method.types + length:1 + encoding:NSASCIIStringEncoding]; +} + + +@end + diff --git a/Sources/CombineCocoaRuntime/ObjcRuntimeAliases.m b/Sources/Runtime/ObjcRuntimeAliases.m similarity index 100% rename from Sources/CombineCocoaRuntime/ObjcRuntimeAliases.m rename to Sources/Runtime/ObjcRuntimeAliases.m diff --git a/Sources/CombineCocoaRuntime/include/ObjcDelegateProxy.h b/Sources/Runtime/include/ObjcDelegateProxy.h similarity index 100% rename from Sources/CombineCocoaRuntime/include/ObjcDelegateProxy.h rename to Sources/Runtime/include/ObjcDelegateProxy.h diff --git a/Sources/CombineCocoaRuntime/include/ObjcRuntimeAliases.h b/Sources/Runtime/include/ObjcRuntimeAliases.h similarity index 100% rename from Sources/CombineCocoaRuntime/include/ObjcRuntimeAliases.h rename to Sources/Runtime/include/ObjcRuntimeAliases.h diff --git a/Sources/CombineCocoaRuntime/include/module.modulemap b/Sources/Runtime/include/module.modulemap similarity index 66% rename from Sources/CombineCocoaRuntime/include/module.modulemap rename to Sources/Runtime/include/module.modulemap index 4986328..e628955 100644 --- a/Sources/CombineCocoaRuntime/include/module.modulemap +++ b/Sources/Runtime/include/module.modulemap @@ -1,4 +1,4 @@ -module CombineCocoaRuntime { +module Runtime { umbrella header "ObjcDelegateProxy.h" export * } From bba63a616bd7595bcea06f297abeb998ef539857 Mon Sep 17 00:00:00 2001 From: Benjamin Deckys Date: Fri, 28 Jul 2023 00:49:41 +0900 Subject: [PATCH 4/4] Use quote marks for header --- Sources/Runtime/include/ObjcDelegateProxy.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Runtime/include/ObjcDelegateProxy.h b/Sources/Runtime/include/ObjcDelegateProxy.h index 62d5668..14a75c3 100644 --- a/Sources/Runtime/include/ObjcDelegateProxy.h +++ b/Sources/Runtime/include/ObjcDelegateProxy.h @@ -7,7 +7,7 @@ // #import -#import +#import "ObjcRuntimeAliases.h" @interface ObjcDelegateProxy: NSObject