diff --git a/ConciseKit.h b/ConciseKit.h index cbe3e87..4df4788 100644 --- a/ConciseKit.h +++ b/ConciseKit.h @@ -13,8 +13,10 @@ + (NSString *)documentPath; + (NSString *)appPath; -+ (BOOL)swizzleMethod:(SEL)originalSelector with:(SEL)anotherSelector inClass:(Class)klass; -+ (BOOL)swizzleClassMethod:(SEL)originalSelector with:(SEL)anotherSelector inClass:(Class)klass; ++ (BOOL)swizzleMethod:(SEL)originalSelector with:(SEL)anotherSelector in:(Class)klass; ++ (BOOL)swizzleMethod:(SEL)originalSelector in:(Class)klass with:(SEL)anotherSelector in:(Class)anotherKlass; ++ (BOOL)swizzleClassMethod:(SEL)originalSelector with:(SEL)anotherSelector in:(Class)klass; ++ (BOOL)swizzleClassMethod:(SEL)originalSelector in:(Class)klass with:(SEL)anotherSelector in:(Class)anotherKlass; @end diff --git a/ConciseKit.m b/ConciseKit.m index 0850946..4fa9c46 100644 --- a/ConciseKit.m +++ b/ConciseKit.m @@ -23,38 +23,47 @@ + (NSString *)appPath { return [[NSBundle mainBundle] bundlePath]; } -+ (BOOL)swizzleMethod:(SEL)originalSelector with:(SEL)anotherSelector inClass:(Class)klass { ++ (BOOL)swizzleMethod:(SEL)originalSelector with:(SEL)anotherSelector in:(Class)klass { + return [self swizzleMethod:originalSelector in:klass with:anotherSelector in:klass]; +} + ++ (BOOL)swizzleMethod:(SEL)originalSelector in:(Class)klass with:(SEL)anotherSelector in:(Class)anotherKlass { Method originalMethod = class_getInstanceMethod(klass, originalSelector); - Method anotherMethod = class_getInstanceMethod(klass, anotherSelector); + Method anotherMethod = class_getInstanceMethod(anotherKlass, anotherSelector); if(!originalMethod || !anotherMethod) { return NO; } IMP originalMethodImplementation = class_getMethodImplementation(klass, originalSelector); - IMP anotherMethodImplementation = class_getMethodImplementation(klass, anotherSelector); + IMP anotherMethodImplementation = class_getMethodImplementation(anotherKlass, anotherSelector); if(class_addMethod(klass, originalSelector, originalMethodImplementation, method_getTypeEncoding(originalMethod))) { originalMethod = class_getInstanceMethod(klass, originalSelector); } - if(class_addMethod(klass, anotherSelector, anotherMethodImplementation, method_getTypeEncoding(anotherMethod))) { - anotherMethod = class_getInstanceMethod(klass, anotherSelector); + if(class_addMethod(anotherKlass, anotherSelector, anotherMethodImplementation, method_getTypeEncoding(anotherMethod))) { + anotherMethod = class_getInstanceMethod(anotherKlass, anotherSelector); } method_exchangeImplementations(originalMethod, anotherMethod); return YES; } -+ (BOOL)swizzleClassMethod:(SEL)originalSelector with:(SEL)anotherSelector inClass:(Class)klass { ++ (BOOL)swizzleClassMethod:(SEL)originalSelector with:(SEL)anotherSelector in:(Class)klass { + return [self swizzleClassMethod:originalSelector in:klass with:anotherSelector in:klass]; +} + ++ (BOOL)swizzleClassMethod:(SEL)originalSelector in:(Class)klass with:(SEL)anotherSelector in:(Class)anotherKlass { Method originalMethod = class_getClassMethod(klass, originalSelector); - Method anotherMethod = class_getClassMethod(klass, anotherSelector); + Method anotherMethod = class_getClassMethod(anotherKlass, anotherSelector); if(!originalMethod || !anotherMethod) { return NO; } - IMP originalMethodImplementation = class_getMethodImplementation(klass, originalSelector); - IMP anotherMethodImplementation = class_getMethodImplementation(klass, anotherSelector); Class metaClass = objc_getMetaClass(class_getName(klass)); + Class anotherMetaClass = objc_getMetaClass(class_getName(anotherKlass)); + IMP originalMethodImplementation = class_getMethodImplementation(metaClass, originalSelector); + IMP anotherMethodImplementation = class_getMethodImplementation(anotherMetaClass, anotherSelector); if(class_addMethod(metaClass, originalSelector, originalMethodImplementation, method_getTypeEncoding(originalMethod))) { originalMethod = class_getClassMethod(klass, originalSelector); } - if(class_addMethod(metaClass, anotherSelector, anotherMethodImplementation, method_getTypeEncoding(anotherMethod))) { - anotherMethod = class_getClassMethod(klass, anotherSelector); + if(class_addMethod(anotherMetaClass, anotherSelector, anotherMethodImplementation, method_getTypeEncoding(anotherMethod))) { + anotherMethod = class_getClassMethod(anotherKlass, anotherSelector); } method_exchangeImplementations(originalMethod, anotherMethod); return YES; diff --git a/ConciseKitSpecs/Spec/ConciseKitSpec.m b/ConciseKitSpecs/Spec/ConciseKitSpec.m index 54e9413..d4b9941 100644 --- a/ConciseKitSpecs/Spec/ConciseKitSpec.m +++ b/ConciseKitSpecs/Spec/ConciseKitSpec.m @@ -5,6 +5,7 @@ #import "SpecHelper.h" #import "ConciseKit.h" #import "Foo.h" +#import DESCRIBE($) { describe(@"path", ^{ @@ -34,32 +35,98 @@ }); describe(@"method swizzling", ^{ - describe(@"+swizzleMethod:with:inClass:", ^{ - it(@"swizzles instances methods", ^{ - Foo *obj = [[Foo alloc] init]; - assertThat([obj foo], equalTo(@"-foo")); - assertThat([obj bar], equalTo(@"-bar")); - [$ swizzleMethod:@selector(foo) with:@selector(bar) inClass:[Foo class]]; - assertThat([obj foo], equalTo(@"-bar")); - assertThat([obj bar], equalTo(@"-foo")); - [$ swizzleMethod:@selector(foo) with:@selector(bar) inClass:[Foo class]]; - assertThat([obj foo], equalTo(@"-foo")); - assertThat([obj bar], equalTo(@"-bar")); - [obj release]; + describe(@"+swizzleMethod:with:in:", ^{ + it(@"swizzles instance methods", ^{ + Foo *foo = [[Foo alloc] init]; + assertThat([foo foo], equalTo(@"-foo")); + assertThat([foo bar], equalTo(@"-bar")); + [$ swizzleMethod:@selector(foo) with:@selector(bar) in:[Foo class]]; + assertThat([foo foo], equalTo(@"-bar")); + assertThat([foo bar], equalTo(@"-foo")); + [$ swizzleMethod:@selector(foo) with:@selector(bar) in:[Foo class]]; + assertThat([foo foo], equalTo(@"-foo")); + assertThat([foo bar], equalTo(@"-bar")); + [foo release]; + }); + + context(@"swizzling inherited methods", ^{ + it(@"adds the inherited methods to the subclass and then swizzles, preserving the original method in superclass", ^{ + Foo *foo = [[Foo alloc] init]; + SubFoo *subFoo = [[SubFoo alloc] init]; + assertThat([foo foo], equalTo(@"-foo")); + assertThat([subFoo foo], equalTo(@"-foo")); + assertThat([subFoo bar], equalTo(@"-SubFoo::bar")); + [$ swizzleMethod:@selector(foo) with:@selector(bar) in:[SubFoo class]]; + assertThat([foo foo], equalTo(@"-foo")); + assertThat([subFoo foo], equalTo(@"-SubFoo::bar")); + assertThat([subFoo bar], equalTo(@"-foo")); + [$ swizzleMethod:@selector(foo) with:@selector(bar) in:[SubFoo class]]; + assertThat([foo foo], equalTo(@"-foo")); + assertThat([subFoo foo], equalTo(@"-foo")); + assertThat([subFoo bar], equalTo(@"-SubFoo::bar")); + [foo release]; + [subFoo release]; + }); }); }); - describe(@"+swizzleClassMethod:with:inClass:", ^{ + describe(@"+swizzleMethod:in:with:in:", ^{ + it(@"swizzles instance methods", ^{ + Foo *foo = [[Foo alloc] init]; + Bar *bar = [[Bar alloc] init]; + assertThat([foo foo], equalTo(@"-foo")); + assertThat([bar bar], equalTo(@"-Bar::bar")); + [$ swizzleMethod:@selector(foo) in:[Foo class] with:@selector(bar) in:[Bar class]]; + assertThat([foo foo], equalTo(@"-Bar::bar")); + assertThat([bar bar], equalTo(@"-foo")); + [$ swizzleMethod:@selector(foo) in:[Foo class] with:@selector(bar) in:[Bar class]]; + assertThat([foo foo], equalTo(@"-foo")); + assertThat([bar bar], equalTo(@"-Bar::bar")); + [foo release]; + [bar release]; + }); + }); + + describe(@"+swizzleClassMethod:with:in:", ^{ it(@"swizzles class methods", ^{ assertThat([Foo foo], equalTo(@"+foo")); assertThat([Foo bar], equalTo(@"+bar")); - [$ swizzleClassMethod:@selector(foo) with:@selector(bar) inClass:[Foo class]]; + [$ swizzleClassMethod:@selector(foo) with:@selector(bar) in:[Foo class]]; assertThat([Foo foo], equalTo(@"+bar")); assertThat([Foo bar], equalTo(@"+foo")); - [$ swizzleClassMethod:@selector(foo) with:@selector(bar) inClass:[Foo class]]; + [$ swizzleClassMethod:@selector(foo) with:@selector(bar) in:[Foo class]]; assertThat([Foo foo], equalTo(@"+foo")); assertThat([Foo bar], equalTo(@"+bar")); }); + + context(@"swizzling inherited class methods", ^{ + it(@"adds the inherited class methods to the subclass and then swizzles, preserving the original method in superclass", ^{ + assertThat([Foo foo], equalTo(@"+foo")); + assertThat([SubFoo foo], equalTo(@"+foo")); + assertThat([SubFoo bar], equalTo(@"+SubFoo::bar")); + [$ swizzleClassMethod:@selector(foo) with:@selector(bar) in:[SubFoo class]]; + assertThat([Foo foo], equalTo(@"+foo")); + assertThat([SubFoo foo], equalTo(@"+SubFoo::bar")); + assertThat([SubFoo bar], equalTo(@"+foo")); + [$ swizzleClassMethod:@selector(foo) with:@selector(bar) in:[SubFoo class]]; + assertThat([Foo foo], equalTo(@"+foo")); + assertThat([SubFoo foo], equalTo(@"+foo")); + assertThat([SubFoo bar], equalTo(@"+SubFoo::bar")); + }); + }); + }); + + describe(@"+swizzleClassMethod:in:with:in:", ^{ + it(@"swizzles class methods", ^{ + assertThat([Foo foo], equalTo(@"+foo")); + assertThat([Bar bar], equalTo(@"+Bar::bar")); + [$ swizzleClassMethod:@selector(foo) in:[Foo class] with:@selector(bar) in:[Bar class]]; + assertThat([Foo foo], equalTo(@"+Bar::bar")); + assertThat([Bar bar], equalTo(@"+foo")); + [$ swizzleClassMethod:@selector(foo) in:[Foo class] with:@selector(bar) in:[Bar class]]; + assertThat([Foo foo], equalTo(@"+foo")); + assertThat([Bar bar], equalTo(@"+Bar::bar")); + }); }); }); } diff --git a/ConciseKitSpecs/Spec/Fixtures/Foo.h b/ConciseKitSpecs/Spec/Fixtures/Foo.h index 232df2f..88deb72 100644 --- a/ConciseKitSpecs/Spec/Fixtures/Foo.h +++ b/ConciseKitSpecs/Spec/Fixtures/Foo.h @@ -9,4 +9,12 @@ + (NSString *)bar; - (NSString *)foo; - (NSString *)bar; +@end + +@interface SubFoo : Foo {} +@end + +@interface Bar : NSObject {} ++ (NSString *)bar; +- (NSString *)bar; @end \ No newline at end of file diff --git a/ConciseKitSpecs/Spec/Fixtures/Foo.m b/ConciseKitSpecs/Spec/Fixtures/Foo.m index 95339fd..3d43c5c 100644 --- a/ConciseKitSpecs/Spec/Fixtures/Foo.m +++ b/ConciseKitSpecs/Spec/Fixtures/Foo.m @@ -9,4 +9,14 @@ + (NSString *)foo { return @"+foo"; } + (NSString *)bar { return @"+bar"; } - (NSString *)foo { return @"-foo"; } - (NSString *)bar { return @"-bar"; } +@end + +@implementation SubFoo ++ (NSString *)bar { return @"+SubFoo::bar"; } +- (NSString *)bar { return @"-SubFoo::bar"; } +@end + +@implementation Bar ++ (NSString *)bar { return @"+Bar::bar"; } +- (NSString *)bar { return @"-Bar::bar"; } @end \ No newline at end of file diff --git a/README.markdown b/README.markdown index 159818a..bc24fa9 100644 --- a/README.markdown +++ b/README.markdown @@ -6,15 +6,18 @@ A set of Objective-C additions and macros that lets you to write code more quick ### Method Swizzling - [$ swizzleMethod:@selector(foo) with:@selector(bar) inClass:[Foo class]]; - [$ swizzleClassMethod:@selector(foo) with:@selector(bar) inClass:[Foo class]]; + [$ swizzleMethod:@selector(foo) with:@selector(bar) in:[Foo class]]; + [$ swizzleMethod:@selector(foo) in:[Foo class] with:@selector(bar) in:[Bar class]]; + + [$ swizzleClassMethod:@selector(foo) with:@selector(bar) in:[Foo class]]; + [$ swizzleClassMethod:@selector(foo) in:[Foo class] with:@selector(bar) in:[Bar class]]; ### Path [$ homePath]; => path to user's home directory [$ desktopPath]; => path to user's desktop directory [$ documentPath]; => path to user's document directory - [$ appPath]; => ptah to app directory + [$ appPath]; => path to app directory ## Macros