Selaa lähdekoodia

完善,添加暴露接口,FileManager继承NSObject

zzb 4 vuotta sitten
vanhempi
commit
6801faa722
38 muutettua tiedostoa jossa 2877 lisäystä ja 1216 poistoa
  1. 7 3
      Example/Podfile.lock
  2. 83 0
      Example/Pods/Aspects/Aspects.h
  3. 890 0
      Example/Pods/Aspects/Aspects.m
  4. 21 0
      Example/Pods/Aspects/LICENSE
  5. 230 0
      Example/Pods/Aspects/README.md
  6. 8 3
      Example/Pods/Local Podspecs/ZZFoundation.podspec.json
  7. 7 3
      Example/Pods/Manifest.lock
  8. 1275 1062
      Example/Pods/Pods.xcodeproj/project.pbxproj
  9. 26 0
      Example/Pods/Target Support Files/Aspects/Aspects-Info.plist
  10. 5 0
      Example/Pods/Target Support Files/Aspects/Aspects-dummy.m
  11. 12 0
      Example/Pods/Target Support Files/Aspects/Aspects-prefix.pch
  12. 17 0
      Example/Pods/Target Support Files/Aspects/Aspects-umbrella.h
  13. 11 0
      Example/Pods/Target Support Files/Aspects/Aspects.debug.xcconfig
  14. 6 0
      Example/Pods/Target Support Files/Aspects/Aspects.modulemap
  15. 11 0
      Example/Pods/Target Support Files/Aspects/Aspects.release.xcconfig
  16. 2 0
      Example/Pods/Target Support Files/Kiwi/Kiwi.debug.xcconfig
  17. 2 0
      Example/Pods/Target Support Files/Kiwi/Kiwi.release.xcconfig
  18. 24 0
      Example/Pods/Target Support Files/Pods-ZZFoundation_Example/Pods-ZZFoundation_Example-acknowledgements.markdown
  19. 30 0
      Example/Pods/Target Support Files/Pods-ZZFoundation_Example/Pods-ZZFoundation_Example-acknowledgements.plist
  20. 38 58
      Example/Pods/Target Support Files/Pods-ZZFoundation_Example/Pods-ZZFoundation_Example-frameworks.sh
  21. 5 3
      Example/Pods/Target Support Files/Pods-ZZFoundation_Example/Pods-ZZFoundation_Example.debug.xcconfig
  22. 5 3
      Example/Pods/Target Support Files/Pods-ZZFoundation_Example/Pods-ZZFoundation_Example.release.xcconfig
  23. 24 0
      Example/Pods/Target Support Files/Pods-ZZFoundation_Tests/Pods-ZZFoundation_Tests-acknowledgements.markdown
  24. 30 0
      Example/Pods/Target Support Files/Pods-ZZFoundation_Tests/Pods-ZZFoundation_Tests-acknowledgements.plist
  25. 38 58
      Example/Pods/Target Support Files/Pods-ZZFoundation_Tests/Pods-ZZFoundation_Tests-frameworks.sh
  26. 5 3
      Example/Pods/Target Support Files/Pods-ZZFoundation_Tests/Pods-ZZFoundation_Tests.debug.xcconfig
  27. 5 3
      Example/Pods/Target Support Files/Pods-ZZFoundation_Tests/Pods-ZZFoundation_Tests.release.xcconfig
  28. 1 1
      Example/Pods/Target Support Files/ZZFoundation/ZZFoundation-Info.plist
  29. 5 3
      Example/Pods/Target Support Files/ZZFoundation/ZZFoundation-umbrella.h
  30. 3 0
      Example/Pods/Target Support Files/ZZFoundation/ZZFoundation.debug.xcconfig
  31. 3 0
      Example/Pods/Target Support Files/ZZFoundation/ZZFoundation.release.xcconfig
  32. 4 0
      Example/ZZFoundation.xcodeproj/project.pbxproj
  33. 2 2
      ZZFoundation.podspec
  34. 4 4
      ZZFoundation/Classes/FileManager/NSFileManager+ZZEx.h
  35. 5 5
      ZZFoundation/Classes/FileManager/NSFileManager+ZZEx.m
  36. 15 0
      ZZFoundation/Classes/BaseTool/ZZFoundation_BaseTool.h
  37. 14 0
      ZZFoundation/Classes/Collection/ZZFoundation_Set.h
  38. 4 2
      ZZFoundation/Classes/ZZFoundation.h

+ 7 - 3
Example/Podfile.lock

@@ -1,6 +1,8 @@
 PODS:
+  - Aspects (1.4.1)
   - Kiwi (3.0.0)
-  - ZZFoundation (0.1.2)
+  - ZZFoundation (0.1.4):
+    - Aspects (~> 1.4.1)
 
 DEPENDENCIES:
   - Kiwi
@@ -8,6 +10,7 @@ DEPENDENCIES:
 
 SPEC REPOS:
   trunk:
+    - Aspects
     - Kiwi
 
 EXTERNAL SOURCES:
@@ -15,9 +18,10 @@ EXTERNAL SOURCES:
     :path: "../"
 
 SPEC CHECKSUMS:
+  Aspects: 7595ba96a6727a58ebcbfc954497fc5d2fdde546
   Kiwi: fbeafef0f00e4d8f7dcb3420a4930afe70af77f7
-  ZZFoundation: 6a95397beaab8bf75160a004c21e8d2c7f769473
+  ZZFoundation: 91e9ee45372135b8fc4d10a7dd76cc6c164d4d51
 
 PODFILE CHECKSUM: 0add32887ca0be5d564b931217e4042cda8f56b5
 
-COCOAPODS: 1.9.3
+COCOAPODS: 1.10.1

+ 83 - 0
Example/Pods/Aspects/Aspects.h

@@ -0,0 +1,83 @@
+//
+//  Aspects.h
+//  Aspects - A delightful, simple library for aspect oriented programming.
+//
+//  Copyright (c) 2014 Peter Steinberger. Licensed under the MIT license.
+//
+
+#import <Foundation/Foundation.h>
+
+typedef NS_OPTIONS(NSUInteger, AspectOptions) {
+    AspectPositionAfter   = 0,            /// Called after the original implementation (default)
+    AspectPositionInstead = 1,            /// Will replace the original implementation.
+    AspectPositionBefore  = 2,            /// Called before the original implementation.
+    
+    AspectOptionAutomaticRemoval = 1 << 3 /// Will remove the hook after the first execution.
+};
+
+/// Opaque Aspect Token that allows to deregister the hook.
+@protocol AspectToken <NSObject>
+
+/// Deregisters an aspect.
+/// @return YES if deregistration is successful, otherwise NO.
+- (BOOL)remove;
+
+@end
+
+/// The AspectInfo protocol is the first parameter of our block syntax.
+@protocol AspectInfo <NSObject>
+
+/// The instance that is currently hooked.
+- (id)instance;
+
+/// The original invocation of the hooked method.
+- (NSInvocation *)originalInvocation;
+
+/// All method arguments, boxed. This is lazily evaluated.
+- (NSArray *)arguments;
+
+@end
+
+/**
+ Aspects uses Objective-C message forwarding to hook into messages. This will create some overhead. Don't add aspects to methods that are called a lot. Aspects is meant for view/controller code that is not called a 1000 times per second.
+
+ Adding aspects returns an opaque token which can be used to deregister again. All calls are thread safe.
+ */
+@interface NSObject (Aspects)
+
+/// Adds a block of code before/instead/after the current `selector` for a specific class.
+///
+/// @param block Aspects replicates the type signature of the method being hooked.
+/// The first parameter will be `id<AspectInfo>`, followed by all parameters of the method.
+/// These parameters are optional and will be filled to match the block signature.
+/// You can even use an empty block, or one that simple gets `id<AspectInfo>`.
+///
+/// @note Hooking static methods is not supported.
+/// @return A token which allows to later deregister the aspect.
++ (id<AspectToken>)aspect_hookSelector:(SEL)selector
+                      withOptions:(AspectOptions)options
+                       usingBlock:(id)block
+                            error:(NSError **)error;
+
+/// Adds a block of code before/instead/after the current `selector` for a specific instance.
+- (id<AspectToken>)aspect_hookSelector:(SEL)selector
+                      withOptions:(AspectOptions)options
+                       usingBlock:(id)block
+                            error:(NSError **)error;
+
+@end
+
+
+typedef NS_ENUM(NSUInteger, AspectErrorCode) {
+    AspectErrorSelectorBlacklisted,                   /// Selectors like release, retain, autorelease are blacklisted.
+    AspectErrorDoesNotRespondToSelector,              /// Selector could not be found.
+    AspectErrorSelectorDeallocPosition,               /// When hooking dealloc, only AspectPositionBefore is allowed.
+    AspectErrorSelectorAlreadyHookedInClassHierarchy, /// Statically hooking the same method in subclasses is not allowed.
+    AspectErrorFailedToAllocateClassPair,             /// The runtime failed creating a class pair.
+    AspectErrorMissingBlockSignature,                 /// The block misses compile time signature info and can't be called.
+    AspectErrorIncompatibleBlockSignature,            /// The block signature does not match the method or is too large.
+
+    AspectErrorRemoveObjectAlreadyDeallocated = 100   /// (for removing) The object hooked is already deallocated.
+};
+
+extern NSString *const AspectErrorDomain;

+ 890 - 0
Example/Pods/Aspects/Aspects.m

@@ -0,0 +1,890 @@
+//
+//  Aspects.m
+//  Aspects - A delightful, simple library for aspect oriented programming.
+//
+//  Copyright (c) 2014 Peter Steinberger. Licensed under the MIT license.
+//
+
+#import "Aspects.h"
+#import <libkern/OSAtomic.h>
+#import <objc/runtime.h>
+#import <objc/message.h>
+
+#define AspectLog(...)
+//#define AspectLog(...) do { NSLog(__VA_ARGS__); }while(0)
+#define AspectLogError(...) do { NSLog(__VA_ARGS__); }while(0)
+
+// Block internals.
+typedef NS_OPTIONS(int, AspectBlockFlags) {
+	AspectBlockFlagsHasCopyDisposeHelpers = (1 << 25),
+	AspectBlockFlagsHasSignature          = (1 << 30)
+};
+typedef struct _AspectBlock {
+	__unused Class isa;
+	AspectBlockFlags flags;
+	__unused int reserved;
+	void (__unused *invoke)(struct _AspectBlock *block, ...);
+	struct {
+		unsigned long int reserved;
+		unsigned long int size;
+		// requires AspectBlockFlagsHasCopyDisposeHelpers
+		void (*copy)(void *dst, const void *src);
+		void (*dispose)(const void *);
+		// requires AspectBlockFlagsHasSignature
+		const char *signature;
+		const char *layout;
+	} *descriptor;
+	// imported variables
+} *AspectBlockRef;
+
+@interface AspectInfo : NSObject <AspectInfo>
+- (id)initWithInstance:(__unsafe_unretained id)instance invocation:(NSInvocation *)invocation;
+@property (nonatomic, unsafe_unretained, readonly) id instance;
+@property (nonatomic, strong, readonly) NSArray *arguments;
+@property (nonatomic, strong, readonly) NSInvocation *originalInvocation;
+@end
+
+// Tracks a single aspect.
+@interface AspectIdentifier : NSObject
++ (instancetype)identifierWithSelector:(SEL)selector object:(id)object options:(AspectOptions)options block:(id)block error:(NSError **)error;
+- (BOOL)invokeWithInfo:(id<AspectInfo>)info;
+@property (nonatomic, assign) SEL selector;
+@property (nonatomic, strong) id block;
+@property (nonatomic, strong) NSMethodSignature *blockSignature;
+@property (nonatomic, weak) id object;
+@property (nonatomic, assign) AspectOptions options;
+@end
+
+// Tracks all aspects for an object/class.
+@interface AspectsContainer : NSObject
+- (void)addAspect:(AspectIdentifier *)aspect withOptions:(AspectOptions)injectPosition;
+- (BOOL)removeAspect:(id)aspect;
+- (BOOL)hasAspects;
+@property (atomic, copy) NSArray *beforeAspects;
+@property (atomic, copy) NSArray *insteadAspects;
+@property (atomic, copy) NSArray *afterAspects;
+@end
+
+@interface AspectTracker : NSObject
+- (id)initWithTrackedClass:(Class)trackedClass parent:(AspectTracker *)parent;
+@property (nonatomic, strong) Class trackedClass;
+@property (nonatomic, strong) NSMutableSet *selectorNames;
+@property (nonatomic, weak) AspectTracker *parentEntry;
+@end
+
+@interface NSInvocation (Aspects)
+- (NSArray *)aspects_arguments;
+@end
+
+#define AspectPositionFilter 0x07
+
+#define AspectError(errorCode, errorDescription) do { \
+AspectLogError(@"Aspects: %@", errorDescription); \
+if (error) { *error = [NSError errorWithDomain:AspectErrorDomain code:errorCode userInfo:@{NSLocalizedDescriptionKey: errorDescription}]; }}while(0)
+
+NSString *const AspectErrorDomain = @"AspectErrorDomain";
+static NSString *const AspectsSubclassSuffix = @"_Aspects_";
+static NSString *const AspectsMessagePrefix = @"aspects_";
+
+@implementation NSObject (Aspects)
+
+///////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Public Aspects API
+
++ (id<AspectToken>)aspect_hookSelector:(SEL)selector
+                      withOptions:(AspectOptions)options
+                       usingBlock:(id)block
+                            error:(NSError **)error {
+    return aspect_add((id)self, selector, options, block, error);
+}
+
+/// @return A token which allows to later deregister the aspect.
+- (id<AspectToken>)aspect_hookSelector:(SEL)selector
+                      withOptions:(AspectOptions)options
+                       usingBlock:(id)block
+                            error:(NSError **)error {
+    return aspect_add(self, selector, options, block, error);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Private Helper
+
+static id aspect_add(id self, SEL selector, AspectOptions options, id block, NSError **error) {
+    NSCParameterAssert(self);
+    NSCParameterAssert(selector);
+    NSCParameterAssert(block);
+
+    __block AspectIdentifier *identifier = nil;
+    aspect_performLocked(^{
+        if (aspect_isSelectorAllowedAndTrack(self, selector, options, error)) {
+            AspectsContainer *aspectContainer = aspect_getContainerForObject(self, selector);
+            identifier = [AspectIdentifier identifierWithSelector:selector object:self options:options block:block error:error];
+            if (identifier) {
+                [aspectContainer addAspect:identifier withOptions:options];
+
+                // Modify the class to allow message interception.
+                aspect_prepareClassAndHookSelector(self, selector, error);
+            }
+        }
+    });
+    return identifier;
+}
+
+static BOOL aspect_remove(AspectIdentifier *aspect, NSError **error) {
+    NSCAssert([aspect isKindOfClass:AspectIdentifier.class], @"Must have correct type.");
+
+    __block BOOL success = NO;
+    aspect_performLocked(^{
+        id self = aspect.object; // strongify
+        if (self) {
+            AspectsContainer *aspectContainer = aspect_getContainerForObject(self, aspect.selector);
+            success = [aspectContainer removeAspect:aspect];
+
+            aspect_cleanupHookedClassAndSelector(self, aspect.selector);
+            // destroy token
+            aspect.object = nil;
+            aspect.block = nil;
+            aspect.selector = NULL;
+        }else {
+            NSString *errrorDesc = [NSString stringWithFormat:@"Unable to deregister hook. Object already deallocated: %@", aspect];
+            AspectError(AspectErrorRemoveObjectAlreadyDeallocated, errrorDesc);
+        }
+    });
+    return success;
+}
+
+static void aspect_performLocked(dispatch_block_t block) {
+    static OSSpinLock aspect_lock = OS_SPINLOCK_INIT;
+    OSSpinLockLock(&aspect_lock);
+    block();
+    OSSpinLockUnlock(&aspect_lock);
+}
+
+static SEL aspect_aliasForSelector(SEL selector) {
+    NSCParameterAssert(selector);
+	return NSSelectorFromString([AspectsMessagePrefix stringByAppendingFormat:@"_%@", NSStringFromSelector(selector)]);
+}
+
+static NSMethodSignature *aspect_blockMethodSignature(id block, NSError **error) {
+    AspectBlockRef layout = (__bridge void *)block;
+	if (!(layout->flags & AspectBlockFlagsHasSignature)) {
+        NSString *description = [NSString stringWithFormat:@"The block %@ doesn't contain a type signature.", block];
+        AspectError(AspectErrorMissingBlockSignature, description);
+        return nil;
+    }
+	void *desc = layout->descriptor;
+	desc += 2 * sizeof(unsigned long int);
+	if (layout->flags & AspectBlockFlagsHasCopyDisposeHelpers) {
+		desc += 2 * sizeof(void *);
+    }
+	if (!desc) {
+        NSString *description = [NSString stringWithFormat:@"The block %@ doesn't has a type signature.", block];
+        AspectError(AspectErrorMissingBlockSignature, description);
+        return nil;
+    }
+	const char *signature = (*(const char **)desc);
+	return [NSMethodSignature signatureWithObjCTypes:signature];
+}
+
+static BOOL aspect_isCompatibleBlockSignature(NSMethodSignature *blockSignature, id object, SEL selector, NSError **error) {
+    NSCParameterAssert(blockSignature);
+    NSCParameterAssert(object);
+    NSCParameterAssert(selector);
+
+    BOOL signaturesMatch = YES;
+    NSMethodSignature *methodSignature = [[object class] instanceMethodSignatureForSelector:selector];
+    if (blockSignature.numberOfArguments > methodSignature.numberOfArguments) {
+        signaturesMatch = NO;
+    }else {
+        if (blockSignature.numberOfArguments > 1) {
+            const char *blockType = [blockSignature getArgumentTypeAtIndex:1];
+            if (blockType[0] != '@') {
+                signaturesMatch = NO;
+            }
+        }
+        // Argument 0 is self/block, argument 1 is SEL or id<AspectInfo>. We start comparing at argument 2.
+        // The block can have less arguments than the method, that's ok.
+        if (signaturesMatch) {
+            for (NSUInteger idx = 2; idx < blockSignature.numberOfArguments; idx++) {
+                const char *methodType = [methodSignature getArgumentTypeAtIndex:idx];
+                const char *blockType = [blockSignature getArgumentTypeAtIndex:idx];
+                // Only compare parameter, not the optional type data.
+                if (!methodType || !blockType || methodType[0] != blockType[0]) {
+                    signaturesMatch = NO; break;
+                }
+            }
+        }
+    }
+
+    if (!signaturesMatch) {
+        NSString *description = [NSString stringWithFormat:@"Blog signature %@ doesn't match %@.", blockSignature, methodSignature];
+        AspectError(AspectErrorIncompatibleBlockSignature, description);
+        return NO;
+    }
+    return YES;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Class + Selector Preparation
+
+static BOOL aspect_isMsgForwardIMP(IMP impl) {
+    return impl == _objc_msgForward
+#if !defined(__arm64__)
+    || impl == (IMP)_objc_msgForward_stret
+#endif
+    ;
+}
+
+static IMP aspect_getMsgForwardIMP(NSObject *self, SEL selector) {
+    IMP msgForwardIMP = _objc_msgForward;
+#if !defined(__arm64__)
+    // As an ugly internal runtime implementation detail in the 32bit runtime, we need to determine of the method we hook returns a struct or anything larger than id.
+    // https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/LowLevelABI/000-Introduction/introduction.html
+    // https://github.com/ReactiveCocoa/ReactiveCocoa/issues/783
+    // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042e/IHI0042E_aapcs.pdf (Section 5.4)
+    Method method = class_getInstanceMethod(self.class, selector);
+    const char *encoding = method_getTypeEncoding(method);
+    BOOL methodReturnsStructValue = encoding[0] == _C_STRUCT_B;
+    if (methodReturnsStructValue) {
+        @try {
+            NSUInteger valueSize = 0;
+            NSGetSizeAndAlignment(encoding, &valueSize, NULL);
+
+            if (valueSize == 1 || valueSize == 2 || valueSize == 4 || valueSize == 8) {
+                methodReturnsStructValue = NO;
+            }
+        } @catch (NSException *e) {}
+    }
+    if (methodReturnsStructValue) {
+        msgForwardIMP = (IMP)_objc_msgForward_stret;
+    }
+#endif
+    return msgForwardIMP;
+}
+
+static void aspect_prepareClassAndHookSelector(NSObject *self, SEL selector, NSError **error) {
+    NSCParameterAssert(selector);
+    Class klass = aspect_hookClass(self, error);
+    Method targetMethod = class_getInstanceMethod(klass, selector);
+    IMP targetMethodIMP = method_getImplementation(targetMethod);
+    if (!aspect_isMsgForwardIMP(targetMethodIMP)) {
+        // Make a method alias for the existing method implementation, it not already copied.
+        const char *typeEncoding = method_getTypeEncoding(targetMethod);
+        SEL aliasSelector = aspect_aliasForSelector(selector);
+        if (![klass instancesRespondToSelector:aliasSelector]) {
+            __unused BOOL addedAlias = class_addMethod(klass, aliasSelector, method_getImplementation(targetMethod), typeEncoding);
+            NSCAssert(addedAlias, @"Original implementation for %@ is already copied to %@ on %@", NSStringFromSelector(selector), NSStringFromSelector(aliasSelector), klass);
+        }
+
+        // We use forwardInvocation to hook in.
+        class_replaceMethod(klass, selector, aspect_getMsgForwardIMP(self, selector), typeEncoding);
+        AspectLog(@"Aspects: Installed hook for -[%@ %@].", klass, NSStringFromSelector(selector));
+    }
+}
+
+// Will undo the runtime changes made.
+static void aspect_cleanupHookedClassAndSelector(NSObject *self, SEL selector) {
+    NSCParameterAssert(self);
+    NSCParameterAssert(selector);
+
+	Class klass = object_getClass(self);
+    BOOL isMetaClass = class_isMetaClass(klass);
+    if (isMetaClass) {
+        klass = (Class)self;
+    }
+
+    // Check if the method is marked as forwarded and undo that.
+    Method targetMethod = class_getInstanceMethod(klass, selector);
+    IMP targetMethodIMP = method_getImplementation(targetMethod);
+    if (aspect_isMsgForwardIMP(targetMethodIMP)) {
+        // Restore the original method implementation.
+        const char *typeEncoding = method_getTypeEncoding(targetMethod);
+        SEL aliasSelector = aspect_aliasForSelector(selector);
+        Method originalMethod = class_getInstanceMethod(klass, aliasSelector);
+        IMP originalIMP = method_getImplementation(originalMethod);
+        NSCAssert(originalMethod, @"Original implementation for %@ not found %@ on %@", NSStringFromSelector(selector), NSStringFromSelector(aliasSelector), klass);
+
+        class_replaceMethod(klass, selector, originalIMP, typeEncoding);
+        AspectLog(@"Aspects: Removed hook for -[%@ %@].", klass, NSStringFromSelector(selector));
+    }
+
+    // Deregister global tracked selector
+    aspect_deregisterTrackedSelector(self, selector);
+
+    // Get the aspect container and check if there are any hooks remaining. Clean up if there are not.
+    AspectsContainer *container = aspect_getContainerForObject(self, selector);
+    if (!container.hasAspects) {
+        // Destroy the container
+        aspect_destroyContainerForObject(self, selector);
+
+        // Figure out how the class was modified to undo the changes.
+        NSString *className = NSStringFromClass(klass);
+        if ([className hasSuffix:AspectsSubclassSuffix]) {
+            Class originalClass = NSClassFromString([className stringByReplacingOccurrencesOfString:AspectsSubclassSuffix withString:@""]);
+            NSCAssert(originalClass != nil, @"Original class must exist");
+            object_setClass(self, originalClass);
+            AspectLog(@"Aspects: %@ has been restored.", NSStringFromClass(originalClass));
+
+            // We can only dispose the class pair if we can ensure that no instances exist using our subclass.
+            // Since we don't globally track this, we can't ensure this - but there's also not much overhead in keeping it around.
+            //objc_disposeClassPair(object.class);
+        }else {
+            // Class is most likely swizzled in place. Undo that.
+            if (isMetaClass) {
+                aspect_undoSwizzleClassInPlace((Class)self);
+            }
+        }
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Hook Class
+
+static Class aspect_hookClass(NSObject *self, NSError **error) {
+    NSCParameterAssert(self);
+	Class statedClass = self.class;
+	Class baseClass = object_getClass(self);
+	NSString *className = NSStringFromClass(baseClass);
+
+    // Already subclassed
+	if ([className hasSuffix:AspectsSubclassSuffix]) {
+		return baseClass;
+
+        // We swizzle a class object, not a single object.
+	}else if (class_isMetaClass(baseClass)) {
+        return aspect_swizzleClassInPlace((Class)self);
+        // Probably a KVO'ed class. Swizzle in place. Also swizzle meta classes in place.
+    }else if (statedClass != baseClass) {
+        return aspect_swizzleClassInPlace(baseClass);
+    }
+
+    // Default case. Create dynamic subclass.
+	const char *subclassName = [className stringByAppendingString:AspectsSubclassSuffix].UTF8String;
+	Class subclass = objc_getClass(subclassName);
+
+	if (subclass == nil) {
+		subclass = objc_allocateClassPair(baseClass, subclassName, 0);
+		if (subclass == nil) {
+            NSString *errrorDesc = [NSString stringWithFormat:@"objc_allocateClassPair failed to allocate class %s.", subclassName];
+            AspectError(AspectErrorFailedToAllocateClassPair, errrorDesc);
+            return nil;
+        }
+
+		aspect_swizzleForwardInvocation(subclass);
+		aspect_hookedGetClass(subclass, statedClass);
+		aspect_hookedGetClass(object_getClass(subclass), statedClass);
+		objc_registerClassPair(subclass);
+	}
+
+	object_setClass(self, subclass);
+	return subclass;
+}
+
+static NSString *const AspectsForwardInvocationSelectorName = @"__aspects_forwardInvocation:";
+static void aspect_swizzleForwardInvocation(Class klass) {
+    NSCParameterAssert(klass);
+    // If there is no method, replace will act like class_addMethod.
+    IMP originalImplementation = class_replaceMethod(klass, @selector(forwardInvocation:), (IMP)__ASPECTS_ARE_BEING_CALLED__, "v@:@");
+    if (originalImplementation) {
+        class_addMethod(klass, NSSelectorFromString(AspectsForwardInvocationSelectorName), originalImplementation, "v@:@");
+    }
+    AspectLog(@"Aspects: %@ is now aspect aware.", NSStringFromClass(klass));
+}
+
+static void aspect_undoSwizzleForwardInvocation(Class klass) {
+    NSCParameterAssert(klass);
+    Method originalMethod = class_getInstanceMethod(klass, NSSelectorFromString(AspectsForwardInvocationSelectorName));
+    Method objectMethod = class_getInstanceMethod(NSObject.class, @selector(forwardInvocation:));
+    // There is no class_removeMethod, so the best we can do is to retore the original implementation, or use a dummy.
+    IMP originalImplementation = method_getImplementation(originalMethod ?: objectMethod);
+    class_replaceMethod(klass, @selector(forwardInvocation:), originalImplementation, "v@:@");
+
+    AspectLog(@"Aspects: %@ has been restored.", NSStringFromClass(klass));
+}
+
+static void aspect_hookedGetClass(Class class, Class statedClass) {
+    NSCParameterAssert(class);
+    NSCParameterAssert(statedClass);
+	Method method = class_getInstanceMethod(class, @selector(class));
+	IMP newIMP = imp_implementationWithBlock(^(id self) {
+		return statedClass;
+	});
+	class_replaceMethod(class, @selector(class), newIMP, method_getTypeEncoding(method));
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Swizzle Class In Place
+
+static void _aspect_modifySwizzledClasses(void (^block)(NSMutableSet *swizzledClasses)) {
+    static NSMutableSet *swizzledClasses;
+    static dispatch_once_t pred;
+    dispatch_once(&pred, ^{
+        swizzledClasses = [NSMutableSet new];
+    });
+    @synchronized(swizzledClasses) {
+        block(swizzledClasses);
+    }
+}
+
+static Class aspect_swizzleClassInPlace(Class klass) {
+    NSCParameterAssert(klass);
+    NSString *className = NSStringFromClass(klass);
+
+    _aspect_modifySwizzledClasses(^(NSMutableSet *swizzledClasses) {
+        if (![swizzledClasses containsObject:className]) {
+            aspect_swizzleForwardInvocation(klass);
+            [swizzledClasses addObject:className];
+        }
+    });
+    return klass;
+}
+
+static void aspect_undoSwizzleClassInPlace(Class klass) {
+    NSCParameterAssert(klass);
+    NSString *className = NSStringFromClass(klass);
+
+    _aspect_modifySwizzledClasses(^(NSMutableSet *swizzledClasses) {
+        if ([swizzledClasses containsObject:className]) {
+            aspect_undoSwizzleForwardInvocation(klass);
+            [swizzledClasses removeObject:className];
+        }
+    });
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Aspect Invoke Point
+
+// This is a macro so we get a cleaner stack trace.
+#define aspect_invoke(aspects, info) \
+for (AspectIdentifier *aspect in aspects) {\
+    [aspect invokeWithInfo:info];\
+    if (aspect.options & AspectOptionAutomaticRemoval) { \
+        aspectsToRemove = [aspectsToRemove?:@[] arrayByAddingObject:aspect]; \
+    } \
+}
+
+// This is the swizzled forwardInvocation: method.
+static void __ASPECTS_ARE_BEING_CALLED__(__unsafe_unretained NSObject *self, SEL selector, NSInvocation *invocation) {
+    NSCParameterAssert(self);
+    NSCParameterAssert(invocation);
+    SEL originalSelector = invocation.selector;
+	SEL aliasSelector = aspect_aliasForSelector(invocation.selector);
+    invocation.selector = aliasSelector;
+    AspectsContainer *objectContainer = objc_getAssociatedObject(self, aliasSelector);
+    AspectsContainer *classContainer = aspect_getContainerForClass(object_getClass(self), aliasSelector);
+    AspectInfo *info = [[AspectInfo alloc] initWithInstance:self invocation:invocation];
+    NSArray *aspectsToRemove = nil;
+
+    // Before hooks.
+    aspect_invoke(classContainer.beforeAspects, info);
+    aspect_invoke(objectContainer.beforeAspects, info);
+
+    // Instead hooks.
+    BOOL respondsToAlias = YES;
+    if (objectContainer.insteadAspects.count || classContainer.insteadAspects.count) {
+        aspect_invoke(classContainer.insteadAspects, info);
+        aspect_invoke(objectContainer.insteadAspects, info);
+    }else {
+        Class klass = object_getClass(invocation.target);
+        do {
+            if ((respondsToAlias = [klass instancesRespondToSelector:aliasSelector])) {
+                [invocation invoke];
+                break;
+            }
+        }while (!respondsToAlias && (klass = class_getSuperclass(klass)));
+    }
+
+    // After hooks.
+    aspect_invoke(classContainer.afterAspects, info);
+    aspect_invoke(objectContainer.afterAspects, info);
+
+    // If no hooks are installed, call original implementation (usually to throw an exception)
+    if (!respondsToAlias) {
+        invocation.selector = originalSelector;
+        SEL originalForwardInvocationSEL = NSSelectorFromString(AspectsForwardInvocationSelectorName);
+        if ([self respondsToSelector:originalForwardInvocationSEL]) {
+            ((void( *)(id, SEL, NSInvocation *))objc_msgSend)(self, originalForwardInvocationSEL, invocation);
+        }else {
+            [self doesNotRecognizeSelector:invocation.selector];
+        }
+    }
+
+    // Remove any hooks that are queued for deregistration.
+    [aspectsToRemove makeObjectsPerformSelector:@selector(remove)];
+}
+#undef aspect_invoke
+
+///////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Aspect Container Management
+
+// Loads or creates the aspect container.
+static AspectsContainer *aspect_getContainerForObject(NSObject *self, SEL selector) {
+    NSCParameterAssert(self);
+    SEL aliasSelector = aspect_aliasForSelector(selector);
+    AspectsContainer *aspectContainer = objc_getAssociatedObject(self, aliasSelector);
+    if (!aspectContainer) {
+        aspectContainer = [AspectsContainer new];
+        objc_setAssociatedObject(self, aliasSelector, aspectContainer, OBJC_ASSOCIATION_RETAIN);
+    }
+    return aspectContainer;
+}
+
+static AspectsContainer *aspect_getContainerForClass(Class klass, SEL selector) {
+    NSCParameterAssert(klass);
+    AspectsContainer *classContainer = nil;
+    do {
+        classContainer = objc_getAssociatedObject(klass, selector);
+        if (classContainer.hasAspects) break;
+    }while ((klass = class_getSuperclass(klass)));
+
+    return classContainer;
+}
+
+static void aspect_destroyContainerForObject(id<NSObject> self, SEL selector) {
+    NSCParameterAssert(self);
+    SEL aliasSelector = aspect_aliasForSelector(selector);
+    objc_setAssociatedObject(self, aliasSelector, nil, OBJC_ASSOCIATION_RETAIN);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Selector Blacklist Checking
+
+static NSMutableDictionary *aspect_getSwizzledClassesDict() {
+    static NSMutableDictionary *swizzledClassesDict;
+    static dispatch_once_t pred;
+    dispatch_once(&pred, ^{
+        swizzledClassesDict = [NSMutableDictionary new];
+    });
+    return swizzledClassesDict;
+}
+
+static BOOL aspect_isSelectorAllowedAndTrack(NSObject *self, SEL selector, AspectOptions options, NSError **error) {
+    static NSSet *disallowedSelectorList;
+    static dispatch_once_t pred;
+    dispatch_once(&pred, ^{
+        disallowedSelectorList = [NSSet setWithObjects:@"retain", @"release", @"autorelease", @"forwardInvocation:", nil];
+    });
+
+    // Check against the blacklist.
+    NSString *selectorName = NSStringFromSelector(selector);
+    if ([disallowedSelectorList containsObject:selectorName]) {
+        NSString *errorDescription = [NSString stringWithFormat:@"Selector %@ is blacklisted.", selectorName];
+        AspectError(AspectErrorSelectorBlacklisted, errorDescription);
+        return NO;
+    }
+
+    // Additional checks.
+    AspectOptions position = options&AspectPositionFilter;
+    if ([selectorName isEqualToString:@"dealloc"] && position != AspectPositionBefore) {
+        NSString *errorDesc = @"AspectPositionBefore is the only valid position when hooking dealloc.";
+        AspectError(AspectErrorSelectorDeallocPosition, errorDesc);
+        return NO;
+    }
+
+    if (![self respondsToSelector:selector] && ![self.class instancesRespondToSelector:selector]) {
+        NSString *errorDesc = [NSString stringWithFormat:@"Unable to find selector -[%@ %@].", NSStringFromClass(self.class), selectorName];
+        AspectError(AspectErrorDoesNotRespondToSelector, errorDesc);
+        return NO;
+    }
+
+    // Search for the current class and the class hierarchy IF we are modifying a class object
+    if (class_isMetaClass(object_getClass(self))) {
+        Class klass = [self class];
+        NSMutableDictionary *swizzledClassesDict = aspect_getSwizzledClassesDict();
+        Class currentClass = [self class];
+        do {
+            AspectTracker *tracker = swizzledClassesDict[currentClass];
+            if ([tracker.selectorNames containsObject:selectorName]) {
+
+                // Find the topmost class for the log.
+                if (tracker.parentEntry) {
+                    AspectTracker *topmostEntry = tracker.parentEntry;
+                    while (topmostEntry.parentEntry) {
+                        topmostEntry = topmostEntry.parentEntry;
+                    }
+                    NSString *errorDescription = [NSString stringWithFormat:@"Error: %@ already hooked in %@. A method can only be hooked once per class hierarchy.", selectorName, NSStringFromClass(topmostEntry.trackedClass)];
+                    AspectError(AspectErrorSelectorAlreadyHookedInClassHierarchy, errorDescription);
+                    return NO;
+                }else if (klass == currentClass) {
+                    // Already modified and topmost!
+                    return YES;
+                }
+            }
+        }while ((currentClass = class_getSuperclass(currentClass)));
+
+        // Add the selector as being modified.
+        currentClass = klass;
+        AspectTracker *parentTracker = nil;
+        do {
+            AspectTracker *tracker = swizzledClassesDict[currentClass];
+            if (!tracker) {
+                tracker = [[AspectTracker alloc] initWithTrackedClass:currentClass parent:parentTracker];
+                swizzledClassesDict[(id<NSCopying>)currentClass] = tracker;
+            }
+            [tracker.selectorNames addObject:selectorName];
+            // All superclasses get marked as having a subclass that is modified.
+            parentTracker = tracker;
+        }while ((currentClass = class_getSuperclass(currentClass)));
+    }
+
+    return YES;
+}
+
+static void aspect_deregisterTrackedSelector(id self, SEL selector) {
+    if (!class_isMetaClass(object_getClass(self))) return;
+
+    NSMutableDictionary *swizzledClassesDict = aspect_getSwizzledClassesDict();
+    NSString *selectorName = NSStringFromSelector(selector);
+    Class currentClass = [self class];
+    do {
+        AspectTracker *tracker = swizzledClassesDict[currentClass];
+        if (tracker) {
+            [tracker.selectorNames removeObject:selectorName];
+            if (tracker.selectorNames.count == 0) {
+                [swizzledClassesDict removeObjectForKey:tracker];
+            }
+        }
+    }while ((currentClass = class_getSuperclass(currentClass)));
+}
+
+@end
+
+@implementation AspectTracker
+
+- (id)initWithTrackedClass:(Class)trackedClass parent:(AspectTracker *)parent {
+    if (self = [super init]) {
+        _trackedClass = trackedClass;
+        _parentEntry = parent;
+        _selectorNames = [NSMutableSet new];
+    }
+    return self;
+}
+- (NSString *)description {
+    return [NSString stringWithFormat:@"<%@: %@, trackedClass: %@, selectorNames:%@, parent:%p>", self.class, self, NSStringFromClass(self.trackedClass), self.selectorNames, self.parentEntry];
+}
+
+@end
+
+///////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark - NSInvocation (Aspects)
+
+@implementation NSInvocation (Aspects)
+
+// Thanks to the ReactiveCocoa team for providing a generic solution for this.
+- (id)aspect_argumentAtIndex:(NSUInteger)index {
+	const char *argType = [self.methodSignature getArgumentTypeAtIndex:index];
+	// Skip const type qualifier.
+	if (argType[0] == _C_CONST) argType++;
+
+#define WRAP_AND_RETURN(type) do { type val = 0; [self getArgument:&val atIndex:(NSInteger)index]; return @(val); } while (0)
+	if (strcmp(argType, @encode(id)) == 0 || strcmp(argType, @encode(Class)) == 0) {
+		__autoreleasing id returnObj;
+		[self getArgument:&returnObj atIndex:(NSInteger)index];
+		return returnObj;
+	} else if (strcmp(argType, @encode(SEL)) == 0) {
+        SEL selector = 0;
+        [self getArgument:&selector atIndex:(NSInteger)index];
+        return NSStringFromSelector(selector);
+    } else if (strcmp(argType, @encode(Class)) == 0) {
+        __autoreleasing Class theClass = Nil;
+        [self getArgument:&theClass atIndex:(NSInteger)index];
+        return theClass;
+        // Using this list will box the number with the appropriate constructor, instead of the generic NSValue.
+	} else if (strcmp(argType, @encode(char)) == 0) {
+		WRAP_AND_RETURN(char);
+	} else if (strcmp(argType, @encode(int)) == 0) {
+		WRAP_AND_RETURN(int);
+	} else if (strcmp(argType, @encode(short)) == 0) {
+		WRAP_AND_RETURN(short);
+	} else if (strcmp(argType, @encode(long)) == 0) {
+		WRAP_AND_RETURN(long);
+	} else if (strcmp(argType, @encode(long long)) == 0) {
+		WRAP_AND_RETURN(long long);
+	} else if (strcmp(argType, @encode(unsigned char)) == 0) {
+		WRAP_AND_RETURN(unsigned char);
+	} else if (strcmp(argType, @encode(unsigned int)) == 0) {
+		WRAP_AND_RETURN(unsigned int);
+	} else if (strcmp(argType, @encode(unsigned short)) == 0) {
+		WRAP_AND_RETURN(unsigned short);
+	} else if (strcmp(argType, @encode(unsigned long)) == 0) {
+		WRAP_AND_RETURN(unsigned long);
+	} else if (strcmp(argType, @encode(unsigned long long)) == 0) {
+		WRAP_AND_RETURN(unsigned long long);
+	} else if (strcmp(argType, @encode(float)) == 0) {
+		WRAP_AND_RETURN(float);
+	} else if (strcmp(argType, @encode(double)) == 0) {
+		WRAP_AND_RETURN(double);
+	} else if (strcmp(argType, @encode(BOOL)) == 0) {
+		WRAP_AND_RETURN(BOOL);
+	} else if (strcmp(argType, @encode(bool)) == 0) {
+		WRAP_AND_RETURN(BOOL);
+	} else if (strcmp(argType, @encode(char *)) == 0) {
+		WRAP_AND_RETURN(const char *);
+	} else if (strcmp(argType, @encode(void (^)(void))) == 0) {
+		__unsafe_unretained id block = nil;
+		[self getArgument:&block atIndex:(NSInteger)index];
+		return [block copy];
+	} else {
+		NSUInteger valueSize = 0;
+		NSGetSizeAndAlignment(argType, &valueSize, NULL);
+
+		unsigned char valueBytes[valueSize];
+		[self getArgument:valueBytes atIndex:(NSInteger)index];
+
+		return [NSValue valueWithBytes:valueBytes objCType:argType];
+	}
+	return nil;
+#undef WRAP_AND_RETURN
+}
+
+- (NSArray *)aspects_arguments {
+	NSMutableArray *argumentsArray = [NSMutableArray array];
+	for (NSUInteger idx = 2; idx < self.methodSignature.numberOfArguments; idx++) {
+		[argumentsArray addObject:[self aspect_argumentAtIndex:idx] ?: NSNull.null];
+	}
+	return [argumentsArray copy];
+}
+
+@end
+
+///////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark - AspectIdentifier
+
+@implementation AspectIdentifier
+
++ (instancetype)identifierWithSelector:(SEL)selector object:(id)object options:(AspectOptions)options block:(id)block error:(NSError **)error {
+    NSCParameterAssert(block);
+    NSCParameterAssert(selector);
+    NSMethodSignature *blockSignature = aspect_blockMethodSignature(block, error); // TODO: check signature compatibility, etc.
+    if (!aspect_isCompatibleBlockSignature(blockSignature, object, selector, error)) {
+        return nil;
+    }
+
+    AspectIdentifier *identifier = nil;
+    if (blockSignature) {
+        identifier = [AspectIdentifier new];
+        identifier.selector = selector;
+        identifier.block = block;
+        identifier.blockSignature = blockSignature;
+        identifier.options = options;
+        identifier.object = object; // weak
+    }
+    return identifier;
+}
+
+- (BOOL)invokeWithInfo:(id<AspectInfo>)info {
+    NSInvocation *blockInvocation = [NSInvocation invocationWithMethodSignature:self.blockSignature];
+    NSInvocation *originalInvocation = info.originalInvocation;
+    NSUInteger numberOfArguments = self.blockSignature.numberOfArguments;
+
+    // Be extra paranoid. We already check that on hook registration.
+    if (numberOfArguments > originalInvocation.methodSignature.numberOfArguments) {
+        AspectLogError(@"Block has too many arguments. Not calling %@", info);
+        return NO;
+    }
+
+    // The `self` of the block will be the AspectInfo. Optional.
+    if (numberOfArguments > 1) {
+        [blockInvocation setArgument:&info atIndex:1];
+    }
+    
+	void *argBuf = NULL;
+    for (NSUInteger idx = 2; idx < numberOfArguments; idx++) {
+        const char *type = [originalInvocation.methodSignature getArgumentTypeAtIndex:idx];
+		NSUInteger argSize;
+		NSGetSizeAndAlignment(type, &argSize, NULL);
+        
+		if (!(argBuf = reallocf(argBuf, argSize))) {
+            AspectLogError(@"Failed to allocate memory for block invocation.");
+			return NO;
+		}
+        
+		[originalInvocation getArgument:argBuf atIndex:idx];
+		[blockInvocation setArgument:argBuf atIndex:idx];
+    }
+    
+    [blockInvocation invokeWithTarget:self.block];
+    
+    if (argBuf != NULL) {
+        free(argBuf);
+    }
+    return YES;
+}
+
+- (NSString *)description {
+    return [NSString stringWithFormat:@"<%@: %p, SEL:%@ object:%@ options:%tu block:%@ (#%tu args)>", self.class, self, NSStringFromSelector(self.selector), self.object, self.options, self.block, self.blockSignature.numberOfArguments];
+}
+
+- (BOOL)remove {
+    return aspect_remove(self, NULL);
+}
+
+@end
+
+///////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark - AspectsContainer
+
+@implementation AspectsContainer
+
+- (BOOL)hasAspects {
+    return self.beforeAspects.count > 0 || self.insteadAspects.count > 0 || self.afterAspects.count > 0;
+}
+
+- (void)addAspect:(AspectIdentifier *)aspect withOptions:(AspectOptions)options {
+    NSParameterAssert(aspect);
+    NSUInteger position = options&AspectPositionFilter;
+    switch (position) {
+        case AspectPositionBefore:  self.beforeAspects  = [(self.beforeAspects ?:@[]) arrayByAddingObject:aspect]; break;
+        case AspectPositionInstead: self.insteadAspects = [(self.insteadAspects?:@[]) arrayByAddingObject:aspect]; break;
+        case AspectPositionAfter:   self.afterAspects   = [(self.afterAspects  ?:@[]) arrayByAddingObject:aspect]; break;
+    }
+}
+
+- (BOOL)removeAspect:(id)aspect {
+    for (NSString *aspectArrayName in @[NSStringFromSelector(@selector(beforeAspects)),
+                                        NSStringFromSelector(@selector(insteadAspects)),
+                                        NSStringFromSelector(@selector(afterAspects))]) {
+        NSArray *array = [self valueForKey:aspectArrayName];
+        NSUInteger index = [array indexOfObjectIdenticalTo:aspect];
+        if (array && index != NSNotFound) {
+            NSMutableArray *newArray = [NSMutableArray arrayWithArray:array];
+            [newArray removeObjectAtIndex:index];
+            [self setValue:newArray forKey:aspectArrayName];
+            return YES;
+        }
+    }
+    return NO;
+}
+
+- (NSString *)description {
+    return [NSString stringWithFormat:@"<%@: %p, before:%@, instead:%@, after:%@>", self.class, self, self.beforeAspects, self.insteadAspects, self.afterAspects];
+}
+
+@end
+
+///////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark - AspectInfo
+
+@implementation AspectInfo
+
+@synthesize arguments = _arguments;
+
+- (id)initWithInstance:(__unsafe_unretained id)instance invocation:(NSInvocation *)invocation {
+    NSCParameterAssert(instance);
+    NSCParameterAssert(invocation);
+    if (self = [super init]) {
+        _instance = instance;
+        _originalInvocation = invocation;
+    }
+    return self;
+}
+
+- (NSArray *)arguments {
+    // Lazily evaluate arguments, boxing is expensive.
+    if (!_arguments) {
+        _arguments = self.originalInvocation.aspects_arguments;
+    }
+    return _arguments;
+}
+
+@end

+ 21 - 0
Example/Pods/Aspects/LICENSE

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Peter Steinberger, steipete@gmail.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 230 - 0
Example/Pods/Aspects/README.md

@@ -0,0 +1,230 @@
+Aspects v1.4.1 [![Build Status](https://travis-ci.org/steipete/Aspects.svg?branch=master)](https://travis-ci.org/steipete/Aspects)
+==============
+
+Delightful, simple library for aspect oriented programming by [@steipete](http://twitter.com/steipete).
+
+**Think of Aspects as method swizzling on steroids. It allows you to add code to existing methods per class or per instance**, whilst thinking of the insertion point e.g. before/instead/after. Aspects automatically deals with calling super and is easier to use than regular method swizzling.
+
+This is stable and used in hundreds of apps since it's part of [PSPDFKit, an iOS PDF framework that ships with apps like Dropbox or Evernote](http://pspdfkit.com), and now I finally made it open source.
+
+Aspects extends `NSObject` with the following methods:
+
+``` objc
+/// Adds a block of code before/instead/after the current `selector` for a specific class.
+///
+/// @param block Aspects replicates the type signature of the method being hooked.
+/// The first parameter will be `id<AspectInfo>`, followed by all parameters of the method.
+/// These parameters are optional and will be filled to match the block signature.
+/// You can even use an empty block, or one that simple gets `id<AspectInfo>`.
+///
+/// @note Hooking static methods is not supported.
+/// @return A token which allows to later deregister the aspect.
++ (id<AspectToken>)aspect_hookSelector:(SEL)selector
+                      withOptions:(AspectOptions)options
+                       usingBlock:(id)block
+                            error:(NSError **)error;
+
+/// Adds a block of code before/instead/after the current `selector` for a specific instance.
+- (id<AspectToken>)aspect_hookSelector:(SEL)selector
+                      withOptions:(AspectOptions)options
+                       usingBlock:(id)block
+                            error:(NSError **)error;
+
+/// Deregister an aspect.
+/// @return YES if deregistration is successful, otherwise NO.
+id<AspectToken> aspect = ...;
+[aspect remove];
+```
+
+Adding aspects returns an opaque token of type `AspectToken` which can be used to deregister again. All calls are thread-safe.
+
+Aspects uses Objective-C message forwarding to hook into messages. This will create some overhead. Don't add aspects to methods that are called a lot. Aspects is meant for view/controller code that is not called 1000 times per second.
+
+Aspects calls and matches block arguments. Blocks without arguments are supported as well. The first block argument will be of type `id<AspectInfo>`.
+
+When to use Aspects
+-------------------
+Aspect-oritented programming (AOP) is used to encapsulate "cross-cutting" concerns. These are the kind of requirements that *cut-accross* many modules in your system, and so cannot be encapsulated using normal Object Oriented programming. Some examples of these kinds of requirements: 
+
+* *Whenever* a user invokes a method on the service client, security should be checked. 
+* *Whenever* a useer interacts with the store, a genius suggestion should be presented, based on their interaction. 
+* *All* calls should be logged. 
+
+If we implemented the above requirements using regular OO there'd be some drawbacks: 
+
+
+Good OO says a class should have a single responsibility, however adding on extra *cross-cutting* requirements means a class that is taking on other responsibilites. For example you might have a **StoreClient** that supposed to be all about making purchases from an online store. Add in some cross-cutting requirements and it might also have to take on the roles of logging, security and recommendations. This is not great: 
+
+* Our StoreClient is now harder to understand and maintain.
+* These cross-cutting requirements are duplicated and spreading throughout our app. 
+
+AOP lets us modularize these cross-cutting requirements, and then cleanly identify all of the places they should be applied. As shown in the examples above cross-cutting requirements can be eithe technical or business focused in nature.  
+
+## Here are some concrete examples: 
+
+
+Aspects can be used to **dynamically add logging** for debug builds only:
+
+``` objc
+[UIViewController aspect_hookSelector:@selector(viewWillAppear:) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo, BOOL animated) {
+    NSLog(@"View Controller %@ will appear animated: %tu", aspectInfo.instance, animated);
+} error:NULL];
+```
+
+-------------------
+It can be used to greatly simplify your analytics setup:
+https://github.com/orta/ARAnalytics
+
+-------------------
+You can check if methods are really being called in your test cases:
+``` objc
+- (void)testExample {
+    TestClass *testClass = [TestClass new];
+    TestClass *testClass2 = [TestClass new];
+
+    __block BOOL testCallCalled = NO;
+    [testClass aspect_hookSelector:@selector(testCall) withOptions:AspectPositionAfter usingBlock:^{
+        testCallCalled = YES;
+    } error:NULL];
+
+    [testClass2 testCallAndExecuteBlock:^{
+        [testClass testCall];
+    } error:NULL];
+    XCTAssertTrue(testCallCalled, @"Calling testCallAndExecuteBlock must call testCall");
+}
+```
+-------------------
+It can be really useful for debugging. Here I was curious when exactly the tap gesture changed state:
+
+``` objc
+[_singleTapGesture aspect_hookSelector:@selector(setState:) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo) {
+    NSLog(@"%@: %@", aspectInfo.instance, aspectInfo.arguments);
+} error:NULL];
+```
+
+-------------------
+Another convenient use case is adding handlers for classes that you don't own. I've written it for use in [PSPDFKit](http://pspdfkit.com), where we require notifications when a view controller is being dismissed modally. This includes UIKit view controllers like `MFMailComposeViewController` or `UIImagePickerController`. We could have created subclasses for each of these controllers, but this would be quite a lot of unnecessary code. Aspects gives you a simpler solution for this problem:
+
+``` objc
+@implementation UIViewController (DismissActionHook)
+
+// Will add a dismiss action once the controller gets dismissed.
+- (void)pspdf_addWillDismissAction:(void (^)(void))action {
+    PSPDFAssert(action != NULL);
+
+    [self aspect_hookSelector:@selector(viewWillDisappear:) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo) {
+        if ([aspectInfo.instance isBeingDismissed]) {
+            action();
+        }
+    } error:NULL];
+}
+
+@end
+```
+
+Debugging
+---------
+Aspects identifies itself nicely in the stack trace, so it's easy to see if a method has been hooked:
+
+<img src="https://raw.githubusercontent.com/steipete/Aspects/master/stacktrace@2x.png?token=58493__eyJzY29wZSI6IlJhd0Jsb2I6c3RlaXBldGUvQXNwZWN0cy9tYXN0ZXIvc3RhY2t0cmFjZUAyeC5wbmciLCJleHBpcmVzIjoxMzk5NzQ3OTI3fQ%3D%3D--97cf7e7bac491149eb8db3d1b9a562ab88154a3c" width="75%">
+
+Using Aspects with non-void return types
+----------------------------------------
+
+You can use the invocation object to customize the return value:
+
+``` objc
+    [PSPDFDrawView aspect_hookSelector:@selector(shouldProcessTouches:withEvent:) withOptions:AspectPositionInstead usingBlock:^(id<AspectInfo> info, NSSet *touches, UIEvent *event) {
+        // Call original implementation.
+        BOOL processTouches;
+        NSInvocation *invocation = info.originalInvocation;
+        [invocation invoke];
+        [invocation getReturnValue:&processTouches];
+
+        if (processTouches) {
+            processTouches = pspdf_stylusShouldProcessTouches(touches, event);
+            [invocation setReturnValue:&processTouches];
+        }
+    } error:NULL];
+```
+
+Installation
+------------
+The simplest option is to use `pod "Aspects"`.
+
+You can also add the two files `Aspects.h/m`. There are no further requirements.
+
+Compatibility and Limitations
+-----------------------------
+Aspects uses quite some runtime trickery to achieve what it does. You can mostly mix this with regular method swizzling.
+
+An important limitation is that for class-based hooking, a method can only be hooked once within the subclass hierarchy. [See #2](https://github.com/steipete/Aspects/issues/2)
+This does not apply for objects that are hooked. Aspects creates a dynamic subclass here and has full control.
+
+KVO works if observers are created after your calls `aspect_hookSelector:` It most likely will crash the other way around.
+Still looking for workarounds here - any help apprechiated.
+
+Because of ugly implementation details on the ObjC runtime, methods that return unions that also contain structs might not work correctly unless this code runs on the arm64 runtime.
+
+Credits
+-------
+The idea to use `_objc_msgForward` and parts of the `NSInvocation` argument selection is from the excellent [ReactiveCocoa](https://github.com/ReactiveCocoa/ReactiveCocoa) from the GitHub guys. [This article](http://codeshaker.blogspot.co.at/2012/01/aop-delivered.html) explains how it works under the hood.
+
+
+Supported iOS & SDK Versions
+-----------------------------
+
+* Aspects requires ARC.
+* Aspects is tested with iOS 6+ and OS X 10.7 or higher.
+
+License
+-------
+MIT licensed, Copyright (c) 2014 Peter Steinberger, steipete@gmail.com, [@steipete](http://twitter.com/steipete)
+
+
+Release Notes
+-----------------
+
+Version 1.4.1
+
+- Rename error codes.
+
+Version 1.4.0
+
+- Add support for block signatures that match method signatures. (thanks to @nickynick)
+
+Version 1.3.1
+
+- Add support for OS X 10.7 or higher. (thanks to @ashfurrow)
+
+Version 1.3.0
+
+- Add automatic deregistration.
+- Checks if the selector exists before trying to hook.
+- Improved dealloc hooking. (no more unsafe_unretained needed)
+- Better examples.
+- Always log errors.
+
+Version 1.2.0
+
+- Adds error parameter.
+- Improvements in subclassing registration tracking.
+
+Version 1.1.0
+
+- Renamed the files from NSObject+Aspects.m/h to just Aspects.m/h.
+- Removing now works via calling `remove` on the aspect token.
+- Allow hooking dealloc.
+- Fixes infinite loop if the same method is hooked for multiple classes. Hooking will only work for one class in the hierarchy.
+- Additional checks to prevent things like hooking retain/release/autorelease or forwardInvocation:
+- The original implementation of forwardInvocation is now correctly preserved.
+- Classes are properly cleaned up and restored to the original state after the last hook is deregistered.
+- Lots and lots of new test cases!
+
+Version 1.0.1
+
+- Minor tweaks and documentation improvements.
+
+Version 1.0.0
+
+- Initial release

+ 8 - 3
Example/Pods/Local Podspecs/ZZFoundation.podspec.json

@@ -1,6 +1,6 @@
 {
   "name": "ZZFoundation",
-  "version": "0.1.2",
+  "version": "0.1.4",
   "summary": "基础版本.",
   "description": "TODO: Add long description of the pod here.",
   "homepage": "https://github.com/Ox8BADFOOD/ZZFoundation",
@@ -13,10 +13,15 @@
   },
   "source": {
     "git": "https://github.com/Ox8BADFOOD/ZZFoundation.git",
-    "tag": "0.1.2"
+    "tag": "0.1.4"
   },
   "platforms": {
     "ios": "9.0"
   },
-  "source_files": "ZZFoundation/Classes/**/*"
+  "source_files": "ZZFoundation/Classes/**/*",
+  "dependencies": {
+    "Aspects": [
+      "~> 1.4.1"
+    ]
+  }
 }

+ 7 - 3
Example/Pods/Manifest.lock

@@ -1,6 +1,8 @@
 PODS:
+  - Aspects (1.4.1)
   - Kiwi (3.0.0)
-  - ZZFoundation (0.1.2)
+  - ZZFoundation (0.1.4):
+    - Aspects (~> 1.4.1)
 
 DEPENDENCIES:
   - Kiwi
@@ -8,6 +10,7 @@ DEPENDENCIES:
 
 SPEC REPOS:
   trunk:
+    - Aspects
     - Kiwi
 
 EXTERNAL SOURCES:
@@ -15,9 +18,10 @@ EXTERNAL SOURCES:
     :path: "../"
 
 SPEC CHECKSUMS:
+  Aspects: 7595ba96a6727a58ebcbfc954497fc5d2fdde546
   Kiwi: fbeafef0f00e4d8f7dcb3420a4930afe70af77f7
-  ZZFoundation: 6a95397beaab8bf75160a004c21e8d2c7f769473
+  ZZFoundation: 91e9ee45372135b8fc4d10a7dd76cc6c164d4d51
 
 PODFILE CHECKSUM: 0add32887ca0be5d564b931217e4042cda8f56b5
 
-COCOAPODS: 1.9.3
+COCOAPODS: 1.10.1

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1275 - 1062
Example/Pods/Pods.xcodeproj/project.pbxproj


+ 26 - 0
Example/Pods/Target Support Files/Aspects/Aspects-Info.plist

@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+  <key>CFBundleDevelopmentRegion</key>
+  <string>en</string>
+  <key>CFBundleExecutable</key>
+  <string>${EXECUTABLE_NAME}</string>
+  <key>CFBundleIdentifier</key>
+  <string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
+  <key>CFBundleInfoDictionaryVersion</key>
+  <string>6.0</string>
+  <key>CFBundleName</key>
+  <string>${PRODUCT_NAME}</string>
+  <key>CFBundlePackageType</key>
+  <string>FMWK</string>
+  <key>CFBundleShortVersionString</key>
+  <string>1.4.1</string>
+  <key>CFBundleSignature</key>
+  <string>????</string>
+  <key>CFBundleVersion</key>
+  <string>${CURRENT_PROJECT_VERSION}</string>
+  <key>NSPrincipalClass</key>
+  <string></string>
+</dict>
+</plist>

+ 5 - 0
Example/Pods/Target Support Files/Aspects/Aspects-dummy.m

@@ -0,0 +1,5 @@
+#import <Foundation/Foundation.h>
+@interface PodsDummy_Aspects : NSObject
+@end
+@implementation PodsDummy_Aspects
+@end

+ 12 - 0
Example/Pods/Target Support Files/Aspects/Aspects-prefix.pch

@@ -0,0 +1,12 @@
+#ifdef __OBJC__
+#import <UIKit/UIKit.h>
+#else
+#ifndef FOUNDATION_EXPORT
+#if defined(__cplusplus)
+#define FOUNDATION_EXPORT extern "C"
+#else
+#define FOUNDATION_EXPORT extern
+#endif
+#endif
+#endif
+

+ 17 - 0
Example/Pods/Target Support Files/Aspects/Aspects-umbrella.h

@@ -0,0 +1,17 @@
+#ifdef __OBJC__
+#import <UIKit/UIKit.h>
+#else
+#ifndef FOUNDATION_EXPORT
+#if defined(__cplusplus)
+#define FOUNDATION_EXPORT extern "C"
+#else
+#define FOUNDATION_EXPORT extern
+#endif
+#endif
+#endif
+
+#import "Aspects.h"
+
+FOUNDATION_EXPORT double AspectsVersionNumber;
+FOUNDATION_EXPORT const unsigned char AspectsVersionString[];
+

+ 11 - 0
Example/Pods/Target Support Files/Aspects/Aspects.debug.xcconfig

@@ -0,0 +1,11 @@
+CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
+CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Aspects
+GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
+PODS_BUILD_DIR = ${BUILD_DIR}
+PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
+PODS_ROOT = ${SRCROOT}
+PODS_TARGET_SRCROOT = ${PODS_ROOT}/Aspects
+PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
+PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
+SKIP_INSTALL = YES
+USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES

+ 6 - 0
Example/Pods/Target Support Files/Aspects/Aspects.modulemap

@@ -0,0 +1,6 @@
+framework module Aspects {
+  umbrella header "Aspects-umbrella.h"
+
+  export *
+  module * { export * }
+}

+ 11 - 0
Example/Pods/Target Support Files/Aspects/Aspects.release.xcconfig

@@ -0,0 +1,11 @@
+CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
+CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Aspects
+GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
+PODS_BUILD_DIR = ${BUILD_DIR}
+PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
+PODS_ROOT = ${SRCROOT}
+PODS_TARGET_SRCROOT = ${PODS_ROOT}/Aspects
+PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
+PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
+SKIP_INSTALL = YES
+USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES

+ 2 - 0
Example/Pods/Target Support Files/Kiwi/Kiwi.debug.xcconfig

@@ -1,3 +1,4 @@
+CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
 CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Kiwi
 FRAMEWORK_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks"
 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
@@ -7,6 +8,7 @@ PODS_BUILD_DIR = ${BUILD_DIR}
 PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
 PODS_ROOT = ${SRCROOT}
 PODS_TARGET_SRCROOT = ${PODS_ROOT}/Kiwi
+PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
 PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
 SKIP_INSTALL = YES
 SWIFT_INCLUDE_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/usr/lib"

+ 2 - 0
Example/Pods/Target Support Files/Kiwi/Kiwi.release.xcconfig

@@ -1,3 +1,4 @@
+CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
 CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Kiwi
 FRAMEWORK_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks"
 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
@@ -7,6 +8,7 @@ PODS_BUILD_DIR = ${BUILD_DIR}
 PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
 PODS_ROOT = ${SRCROOT}
 PODS_TARGET_SRCROOT = ${PODS_ROOT}/Kiwi
+PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
 PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
 SKIP_INSTALL = YES
 SWIFT_INCLUDE_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/usr/lib"

+ 24 - 0
Example/Pods/Target Support Files/Pods-ZZFoundation_Example/Pods-ZZFoundation_Example-acknowledgements.markdown

@@ -1,6 +1,30 @@
 # Acknowledgements
 This application makes use of the following third party libraries:
 
+## Aspects
+
+The MIT License (MIT)
+
+Copyright (c) 2014 Peter Steinberger, steipete@gmail.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
 ## ZZFoundation
 
 Copyright (c) 2020 bymiracles@163.com <350991881@qq.com>

+ 30 - 0
Example/Pods/Target Support Files/Pods-ZZFoundation_Example/Pods-ZZFoundation_Example-acknowledgements.plist

@@ -12,6 +12,36 @@
 			<key>Type</key>
 			<string>PSGroupSpecifier</string>
 		</dict>
+		<dict>
+			<key>FooterText</key>
+			<string>The MIT License (MIT)
+
+Copyright (c) 2014 Peter Steinberger, steipete@gmail.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.</string>
+			<key>License</key>
+			<string>MIT</string>
+			<key>Title</key>
+			<string>Aspects</string>
+			<key>Type</key>
+			<string>PSGroupSpecifier</string>
+		</dict>
 		<dict>
 			<key>FooterText</key>
 			<string>Copyright (c) 2020 bymiracles@163.com &lt;350991881@qq.com&gt;

+ 38 - 58
Example/Pods/Target Support Files/Pods-ZZFoundation_Example/Pods-ZZFoundation_Example-frameworks.sh

@@ -19,9 +19,8 @@ mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
 
 COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}"
 SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
+BCSYMBOLMAP_DIR="BCSymbolMaps"
 
-# Used as a return value for each invocation of `strip_invalid_archs` function.
-STRIP_BINARY_RETVAL=0
 
 # This protects against multiple targets copying the same framework dependency at the same time. The solution
 # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
@@ -45,6 +44,16 @@ install_framework()
     source="$(readlink "${source}")"
   fi
 
+  if [ -d "${source}/${BCSYMBOLMAP_DIR}" ]; then
+    # Locate and install any .bcsymbolmaps if present, and remove them from the .framework before the framework is copied
+    find "${source}/${BCSYMBOLMAP_DIR}" -name "*.bcsymbolmap"|while read f; do
+      echo "Installing $f"
+      install_bcsymbolmap "$f" "$destination"
+      rm "$f"
+    done
+    rmdir "${source}/${BCSYMBOLMAP_DIR}"
+  fi
+
   # Use filter instead of exclude so missing patterns don't throw errors.
   echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
   rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
@@ -80,7 +89,6 @@ install_framework()
     done
   fi
 }
-
 # Copies and strips a vendored dSYM
 install_dsym() {
   local source="$1"
@@ -95,12 +103,11 @@ install_dsym() {
     binary_name="$(ls "$source/Contents/Resources/DWARF")"
     binary="${DERIVED_FILES_DIR}/${basename}.dSYM/Contents/Resources/DWARF/${binary_name}"
 
-    # Strip invalid architectures so "fat" simulator / device frameworks work on device
+    # Strip invalid architectures from the dSYM.
     if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then
       strip_invalid_archs "$binary" "$warn_missing_arch"
     fi
-
-    if [[ $STRIP_BINARY_RETVAL == 1 ]]; then
+    if [[ $STRIP_BINARY_RETVAL == 0 ]]; then
       # Move the stripped file into its final destination.
       echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\""
       rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
@@ -111,28 +118,8 @@ install_dsym() {
   fi
 }
 
-# Copies the bcsymbolmap files of a vendored framework
-install_bcsymbolmap() {
-    local bcsymbolmap_path="$1"
-    local destination="${BUILT_PRODUCTS_DIR}"
-    echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}""
-    rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"
-}
-
-# Signs a framework with the provided identity
-code_sign_if_enabled() {
-  if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
-    # Use the current code_sign_identity
-    echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
-    local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
-
-    if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
-      code_sign_cmd="$code_sign_cmd &"
-    fi
-    echo "$code_sign_cmd"
-    eval "$code_sign_cmd"
-  fi
-}
+# Used as a return value for each invocation of `strip_invalid_archs` function.
+STRIP_BINARY_RETVAL=0
 
 # Strip invalid architectures
 strip_invalid_archs() {
@@ -147,7 +134,7 @@ strip_invalid_archs() {
     if [[ "$warn_missing_arch" == "true" ]]; then
       echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
     fi
-    STRIP_BINARY_RETVAL=0
+    STRIP_BINARY_RETVAL=1
     return
   fi
   stripped=""
@@ -161,45 +148,38 @@ strip_invalid_archs() {
   if [[ "$stripped" ]]; then
     echo "Stripped $binary of architectures:$stripped"
   fi
-  STRIP_BINARY_RETVAL=1
+  STRIP_BINARY_RETVAL=0
 }
 
-install_artifact() {
-  artifact="$1"
-  base="$(basename "$artifact")"
-  case $base in
-  *.framework)
-    install_framework "$artifact"
-    ;;
-  *.dSYM)
-    # Suppress arch warnings since XCFrameworks will include many dSYM files
-    install_dsym "$artifact" "false"
-    ;;
-  *.bcsymbolmap)
-    install_bcsymbolmap "$artifact"
-    ;;
-  *)
-    echo "error: Unrecognized artifact "$artifact""
-    ;;
-  esac
+# Copies the bcsymbolmap files of a vendored framework
+install_bcsymbolmap() {
+    local bcsymbolmap_path="$1"
+    local destination="${BUILT_PRODUCTS_DIR}"
+    echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}""
+    rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"
 }
 
-copy_artifacts() {
-  file_list="$1"
-  while read artifact; do
-    install_artifact "$artifact"
-  done <$file_list
-}
+# Signs a framework with the provided identity
+code_sign_if_enabled() {
+  if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
+    # Use the current code_sign_identity
+    echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
+    local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
 
-ARTIFACT_LIST_FILE="${BUILT_PRODUCTS_DIR}/cocoapods-artifacts-${CONFIGURATION}.txt"
-if [ -r "${ARTIFACT_LIST_FILE}" ]; then
-  copy_artifacts "${ARTIFACT_LIST_FILE}"
-fi
+    if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
+      code_sign_cmd="$code_sign_cmd &"
+    fi
+    echo "$code_sign_cmd"
+    eval "$code_sign_cmd"
+  fi
+}
 
 if [[ "$CONFIGURATION" == "Debug" ]]; then
+  install_framework "${BUILT_PRODUCTS_DIR}/Aspects/Aspects.framework"
   install_framework "${BUILT_PRODUCTS_DIR}/ZZFoundation/ZZFoundation.framework"
 fi
 if [[ "$CONFIGURATION" == "Release" ]]; then
+  install_framework "${BUILT_PRODUCTS_DIR}/Aspects/Aspects.framework"
   install_framework "${BUILT_PRODUCTS_DIR}/ZZFoundation/ZZFoundation.framework"
 fi
 if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then

+ 5 - 3
Example/Pods/Target Support Files/Pods-ZZFoundation_Example/Pods-ZZFoundation_Example.debug.xcconfig

@@ -1,10 +1,12 @@
-FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/ZZFoundation"
+CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
+FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Aspects" "${PODS_CONFIGURATION_BUILD_DIR}/ZZFoundation"
 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/ZZFoundation/ZZFoundation.framework/Headers"
+HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Aspects/Aspects.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/ZZFoundation/ZZFoundation.framework/Headers"
 LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
-OTHER_LDFLAGS = $(inherited) -framework "ZZFoundation"
+OTHER_LDFLAGS = $(inherited) -framework "Aspects" -framework "ZZFoundation"
 PODS_BUILD_DIR = ${BUILD_DIR}
 PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
 PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
 PODS_ROOT = ${SRCROOT}/Pods
+PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
 USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES

+ 5 - 3
Example/Pods/Target Support Files/Pods-ZZFoundation_Example/Pods-ZZFoundation_Example.release.xcconfig

@@ -1,10 +1,12 @@
-FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/ZZFoundation"
+CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
+FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Aspects" "${PODS_CONFIGURATION_BUILD_DIR}/ZZFoundation"
 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/ZZFoundation/ZZFoundation.framework/Headers"
+HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Aspects/Aspects.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/ZZFoundation/ZZFoundation.framework/Headers"
 LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
-OTHER_LDFLAGS = $(inherited) -framework "ZZFoundation"
+OTHER_LDFLAGS = $(inherited) -framework "Aspects" -framework "ZZFoundation"
 PODS_BUILD_DIR = ${BUILD_DIR}
 PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
 PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
 PODS_ROOT = ${SRCROOT}/Pods
+PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
 USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES

+ 24 - 0
Example/Pods/Target Support Files/Pods-ZZFoundation_Tests/Pods-ZZFoundation_Tests-acknowledgements.markdown

@@ -1,6 +1,30 @@
 # Acknowledgements
 This application makes use of the following third party libraries:
 
+## Aspects
+
+The MIT License (MIT)
+
+Copyright (c) 2014 Peter Steinberger, steipete@gmail.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
 ## ZZFoundation
 
 Copyright (c) 2020 bymiracles@163.com <350991881@qq.com>

+ 30 - 0
Example/Pods/Target Support Files/Pods-ZZFoundation_Tests/Pods-ZZFoundation_Tests-acknowledgements.plist

@@ -12,6 +12,36 @@
 			<key>Type</key>
 			<string>PSGroupSpecifier</string>
 		</dict>
+		<dict>
+			<key>FooterText</key>
+			<string>The MIT License (MIT)
+
+Copyright (c) 2014 Peter Steinberger, steipete@gmail.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.</string>
+			<key>License</key>
+			<string>MIT</string>
+			<key>Title</key>
+			<string>Aspects</string>
+			<key>Type</key>
+			<string>PSGroupSpecifier</string>
+		</dict>
 		<dict>
 			<key>FooterText</key>
 			<string>Copyright (c) 2020 bymiracles@163.com &lt;350991881@qq.com&gt;

+ 38 - 58
Example/Pods/Target Support Files/Pods-ZZFoundation_Tests/Pods-ZZFoundation_Tests-frameworks.sh

@@ -19,9 +19,8 @@ mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
 
 COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}"
 SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
+BCSYMBOLMAP_DIR="BCSymbolMaps"
 
-# Used as a return value for each invocation of `strip_invalid_archs` function.
-STRIP_BINARY_RETVAL=0
 
 # This protects against multiple targets copying the same framework dependency at the same time. The solution
 # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
@@ -45,6 +44,16 @@ install_framework()
     source="$(readlink "${source}")"
   fi
 
+  if [ -d "${source}/${BCSYMBOLMAP_DIR}" ]; then
+    # Locate and install any .bcsymbolmaps if present, and remove them from the .framework before the framework is copied
+    find "${source}/${BCSYMBOLMAP_DIR}" -name "*.bcsymbolmap"|while read f; do
+      echo "Installing $f"
+      install_bcsymbolmap "$f" "$destination"
+      rm "$f"
+    done
+    rmdir "${source}/${BCSYMBOLMAP_DIR}"
+  fi
+
   # Use filter instead of exclude so missing patterns don't throw errors.
   echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
   rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
@@ -80,7 +89,6 @@ install_framework()
     done
   fi
 }
-
 # Copies and strips a vendored dSYM
 install_dsym() {
   local source="$1"
@@ -95,12 +103,11 @@ install_dsym() {
     binary_name="$(ls "$source/Contents/Resources/DWARF")"
     binary="${DERIVED_FILES_DIR}/${basename}.dSYM/Contents/Resources/DWARF/${binary_name}"
 
-    # Strip invalid architectures so "fat" simulator / device frameworks work on device
+    # Strip invalid architectures from the dSYM.
     if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then
       strip_invalid_archs "$binary" "$warn_missing_arch"
     fi
-
-    if [[ $STRIP_BINARY_RETVAL == 1 ]]; then
+    if [[ $STRIP_BINARY_RETVAL == 0 ]]; then
       # Move the stripped file into its final destination.
       echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\""
       rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
@@ -111,28 +118,8 @@ install_dsym() {
   fi
 }
 
-# Copies the bcsymbolmap files of a vendored framework
-install_bcsymbolmap() {
-    local bcsymbolmap_path="$1"
-    local destination="${BUILT_PRODUCTS_DIR}"
-    echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}""
-    rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"
-}
-
-# Signs a framework with the provided identity
-code_sign_if_enabled() {
-  if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
-    # Use the current code_sign_identity
-    echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
-    local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
-
-    if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
-      code_sign_cmd="$code_sign_cmd &"
-    fi
-    echo "$code_sign_cmd"
-    eval "$code_sign_cmd"
-  fi
-}
+# Used as a return value for each invocation of `strip_invalid_archs` function.
+STRIP_BINARY_RETVAL=0
 
 # Strip invalid architectures
 strip_invalid_archs() {
@@ -147,7 +134,7 @@ strip_invalid_archs() {
     if [[ "$warn_missing_arch" == "true" ]]; then
       echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
     fi
-    STRIP_BINARY_RETVAL=0
+    STRIP_BINARY_RETVAL=1
     return
   fi
   stripped=""
@@ -161,46 +148,39 @@ strip_invalid_archs() {
   if [[ "$stripped" ]]; then
     echo "Stripped $binary of architectures:$stripped"
   fi
-  STRIP_BINARY_RETVAL=1
+  STRIP_BINARY_RETVAL=0
 }
 
-install_artifact() {
-  artifact="$1"
-  base="$(basename "$artifact")"
-  case $base in
-  *.framework)
-    install_framework "$artifact"
-    ;;
-  *.dSYM)
-    # Suppress arch warnings since XCFrameworks will include many dSYM files
-    install_dsym "$artifact" "false"
-    ;;
-  *.bcsymbolmap)
-    install_bcsymbolmap "$artifact"
-    ;;
-  *)
-    echo "error: Unrecognized artifact "$artifact""
-    ;;
-  esac
+# Copies the bcsymbolmap files of a vendored framework
+install_bcsymbolmap() {
+    local bcsymbolmap_path="$1"
+    local destination="${BUILT_PRODUCTS_DIR}"
+    echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}""
+    rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"
 }
 
-copy_artifacts() {
-  file_list="$1"
-  while read artifact; do
-    install_artifact "$artifact"
-  done <$file_list
-}
+# Signs a framework with the provided identity
+code_sign_if_enabled() {
+  if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
+    # Use the current code_sign_identity
+    echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
+    local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
 
-ARTIFACT_LIST_FILE="${BUILT_PRODUCTS_DIR}/cocoapods-artifacts-${CONFIGURATION}.txt"
-if [ -r "${ARTIFACT_LIST_FILE}" ]; then
-  copy_artifacts "${ARTIFACT_LIST_FILE}"
-fi
+    if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
+      code_sign_cmd="$code_sign_cmd &"
+    fi
+    echo "$code_sign_cmd"
+    eval "$code_sign_cmd"
+  fi
+}
 
 if [[ "$CONFIGURATION" == "Debug" ]]; then
+  install_framework "${BUILT_PRODUCTS_DIR}/Aspects/Aspects.framework"
   install_framework "${BUILT_PRODUCTS_DIR}/ZZFoundation/ZZFoundation.framework"
   install_framework "${BUILT_PRODUCTS_DIR}/Kiwi/Kiwi.framework"
 fi
 if [[ "$CONFIGURATION" == "Release" ]]; then
+  install_framework "${BUILT_PRODUCTS_DIR}/Aspects/Aspects.framework"
   install_framework "${BUILT_PRODUCTS_DIR}/ZZFoundation/ZZFoundation.framework"
   install_framework "${BUILT_PRODUCTS_DIR}/Kiwi/Kiwi.framework"
 fi

+ 5 - 3
Example/Pods/Target Support Files/Pods-ZZFoundation_Tests/Pods-ZZFoundation_Tests.debug.xcconfig

@@ -1,10 +1,12 @@
-FRAMEWORK_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks" "${PODS_CONFIGURATION_BUILD_DIR}/Kiwi" "${PODS_CONFIGURATION_BUILD_DIR}/ZZFoundation"
+CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
+FRAMEWORK_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks" "${PODS_CONFIGURATION_BUILD_DIR}/Aspects" "${PODS_CONFIGURATION_BUILD_DIR}/Kiwi" "${PODS_CONFIGURATION_BUILD_DIR}/ZZFoundation"
 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Kiwi/Kiwi.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/ZZFoundation/ZZFoundation.framework/Headers"
+HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Aspects/Aspects.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Kiwi/Kiwi.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/ZZFoundation/ZZFoundation.framework/Headers"
 LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
-OTHER_LDFLAGS = $(inherited) -framework "Kiwi" -framework "XCTest" -framework "ZZFoundation"
+OTHER_LDFLAGS = $(inherited) -framework "Aspects" -framework "Kiwi" -framework "XCTest" -framework "ZZFoundation"
 PODS_BUILD_DIR = ${BUILD_DIR}
 PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
 PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
 PODS_ROOT = ${SRCROOT}/Pods
+PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
 USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES

+ 5 - 3
Example/Pods/Target Support Files/Pods-ZZFoundation_Tests/Pods-ZZFoundation_Tests.release.xcconfig

@@ -1,10 +1,12 @@
-FRAMEWORK_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks" "${PODS_CONFIGURATION_BUILD_DIR}/Kiwi" "${PODS_CONFIGURATION_BUILD_DIR}/ZZFoundation"
+CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
+FRAMEWORK_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks" "${PODS_CONFIGURATION_BUILD_DIR}/Aspects" "${PODS_CONFIGURATION_BUILD_DIR}/Kiwi" "${PODS_CONFIGURATION_BUILD_DIR}/ZZFoundation"
 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Kiwi/Kiwi.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/ZZFoundation/ZZFoundation.framework/Headers"
+HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Aspects/Aspects.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Kiwi/Kiwi.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/ZZFoundation/ZZFoundation.framework/Headers"
 LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
-OTHER_LDFLAGS = $(inherited) -framework "Kiwi" -framework "XCTest" -framework "ZZFoundation"
+OTHER_LDFLAGS = $(inherited) -framework "Aspects" -framework "Kiwi" -framework "XCTest" -framework "ZZFoundation"
 PODS_BUILD_DIR = ${BUILD_DIR}
 PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
 PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
 PODS_ROOT = ${SRCROOT}/Pods
+PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
 USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES

+ 1 - 1
Example/Pods/Target Support Files/ZZFoundation/ZZFoundation-Info.plist

@@ -15,7 +15,7 @@
   <key>CFBundlePackageType</key>
   <string>FMWK</string>
   <key>CFBundleShortVersionString</key>
-  <string>0.1.2</string>
+  <string>0.1.4</string>
   <key>CFBundleSignature</key>
   <string>????</string>
   <key>CFBundleVersion</key>

+ 5 - 3
Example/Pods/Target Support Files/ZZFoundation/ZZFoundation-umbrella.h

@@ -10,13 +10,17 @@
 #endif
 #endif
 
+#import "ZZClass.h"
+#import "ZZFileManager.h"
+#import "ZZFoundation_BaseTool.h"
+#import "ZZWeakify.h"
 #import "NSArray+ZZEx.h"
 #import "NSMutableArray+ZZEx.h"
+#import "ZZFoundation_Set.h"
 #import "NSDate+ZZChineseCalendar.h"
 #import "NSDate+ZZEx.h"
 #import "NSDate+ZZTimeStamp.h"
 #import "ZZFoundation_Date.h"
-#import "NSFileManager+ZZEx.h"
 #import "NSDateFormatter+ZZEx.h"
 #import "NSObjec+PropertiesVarMethod.h"
 #import "ZZSwizzle.h"
@@ -26,9 +30,7 @@
 #import "NSString+ZZRegex.h"
 #import "ZZSecurity.h"
 #import "ZZFoundation_String.h"
-#import "ZZClass.h"
 #import "ZZFoundation.h"
-#import "ZZWeakify.h"
 
 FOUNDATION_EXPORT double ZZFoundationVersionNumber;
 FOUNDATION_EXPORT const unsigned char ZZFoundationVersionString[];

+ 3 - 0
Example/Pods/Target Support Files/ZZFoundation/ZZFoundation.debug.xcconfig

@@ -1,9 +1,12 @@
+CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
 CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/ZZFoundation
+FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Aspects"
 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
 PODS_BUILD_DIR = ${BUILD_DIR}
 PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
 PODS_ROOT = ${SRCROOT}
 PODS_TARGET_SRCROOT = ${PODS_ROOT}/../..
+PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
 PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
 SKIP_INSTALL = YES
 USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES

+ 3 - 0
Example/Pods/Target Support Files/ZZFoundation/ZZFoundation.release.xcconfig

@@ -1,9 +1,12 @@
+CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
 CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/ZZFoundation
+FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Aspects"
 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
 PODS_BUILD_DIR = ${BUILD_DIR}
 PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
 PODS_ROOT = ${SRCROOT}
 PODS_TARGET_SRCROOT = ${PODS_ROOT}/../..
+PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
 PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
 SKIP_INSTALL = YES
 USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES

+ 4 - 0
Example/ZZFoundation.xcodeproj/project.pbxproj

@@ -312,10 +312,12 @@
 			);
 			inputPaths = (
 				"${PODS_ROOT}/Target Support Files/Pods-ZZFoundation_Example/Pods-ZZFoundation_Example-frameworks.sh",
+				"${BUILT_PRODUCTS_DIR}/Aspects/Aspects.framework",
 				"${BUILT_PRODUCTS_DIR}/ZZFoundation/ZZFoundation.framework",
 			);
 			name = "[CP] Embed Pods Frameworks";
 			outputPaths = (
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Aspects.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ZZFoundation.framework",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -374,11 +376,13 @@
 			);
 			inputPaths = (
 				"${PODS_ROOT}/Target Support Files/Pods-ZZFoundation_Tests/Pods-ZZFoundation_Tests-frameworks.sh",
+				"${BUILT_PRODUCTS_DIR}/Aspects/Aspects.framework",
 				"${BUILT_PRODUCTS_DIR}/ZZFoundation/ZZFoundation.framework",
 				"${BUILT_PRODUCTS_DIR}/Kiwi/Kiwi.framework",
 			);
 			name = "[CP] Embed Pods Frameworks";
 			outputPaths = (
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Aspects.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ZZFoundation.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Kiwi.framework",
 			);

+ 2 - 2
ZZFoundation.podspec

@@ -8,7 +8,7 @@
 
 Pod::Spec.new do |s|
   s.name             = 'ZZFoundation'
-  s.version          = '0.1.3'
+  s.version          = '0.1.4'
   s.summary          = '基础版本.'
 
 # This description is used to generate tags and improve search results.
@@ -38,5 +38,5 @@ TODO: Add long description of the pod here.
 
   # s.public_header_files = 'Pod/Classes/**/*.h'
   # s.frameworks = 'UIKit', 'MapKit'
-  # s.dependency 'AFNetworking', '~> 2.3'
+  s.dependency 'Aspects', '~> 1.4.1'
 end

+ 4 - 4
ZZFoundation/Classes/FileManager/NSFileManager+ZZEx.h

@@ -1,15 +1,15 @@
 //
-//  NSFileManager+ZZEx.h
-//  Kiwi
+//  ZZFileManager.h
+//  Aspects
 //
-//  Created by Max on 2020/12/29.
+//  Created by Max on 2021/1/26.
 //
 
 #import <Foundation/Foundation.h>
 
 NS_ASSUME_NONNULL_BEGIN
 
-@interface NSFileManager (ZZEx)
+@interface ZZFileManager : NSObject
 /// 创建文件夹
 /// @param path 完整的文件夹路径
 /// @return 返回创建结果

+ 5 - 5
ZZFoundation/Classes/FileManager/NSFileManager+ZZEx.m

@@ -1,13 +1,13 @@
 //
-//  NSFileManager+ZZEx.m
-//  Kiwi
+//  ZZFileManager.m
+//  Aspects
 //
-//  Created by Max on 2020/12/29.
+//  Created by Max on 2021/1/26.
 //
 
-#import "NSFileManager+ZZEx.h"
+#import "ZZFileManager.h"
 
-@implementation NSFileManager (ZZEx)
+@implementation ZZFileManager
 #pragma mark -- 创建
 +(BOOL)ZZCreatDir:(NSString *)path{
     if (path.length==0) {

+ 15 - 0
ZZFoundation/Classes/BaseTool/ZZFoundation_BaseTool.h

@@ -0,0 +1,15 @@
+//
+//  ZZFoundation_BaseTool.h
+//  Pods
+//
+//  Created by Max on 2021/1/26.
+//
+
+#ifndef ZZFoundation_BaseTool_h
+#define ZZFoundation_BaseTool_h
+
+#import "ZZClass.h"
+#import "ZZWeakify.h"
+#import "ZZFileManager.h"
+
+#endif /* ZZFoundation_BaseTool_h */

+ 14 - 0
ZZFoundation/Classes/Collection/ZZFoundation_Set.h

@@ -0,0 +1,14 @@
+//
+//  ZZFoundation_Set.h
+//  Pods
+//
+//  Created by Max on 2021/1/26.
+//
+
+#ifndef ZZFoundation_Set_h
+#define ZZFoundation_Set_h
+
+#import "NSArray+ZZEx.h"
+#import "NSMutableArray+ZZEx.h"
+
+#endif /* ZZFoundation_Set_h */

+ 4 - 2
ZZFoundation/Classes/ZZFoundation.h

@@ -7,9 +7,11 @@
 
 #ifndef ZZFoundation_h
 #define ZZFoundation_h
-#import "ZZClass.h"
-#import "ZZWeakify.h"
 
+#import "ZZFoundation_BaseTool.h"
 #import "ZZFoundation_String.h"
+#import "ZZFoundation_Set.h"
 #import "ZZFoundation_Date.h"
+#import "ZZSwizzle.h"
+
 #endif /* ZZFoundation_h */