diff --git a/README.md b/README.md index 5011d74..8df6160 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ #文章讲解 -[标哥的技术博客](http://www.henishuo.com/runtime-model-dictionary-convert/) +[标哥的技术博客](http://www.henishuo.com/category/runtime/) #关注我 diff --git a/RuntimeDemo.xcodeproj/project.pbxproj b/RuntimeDemo.xcodeproj/project.pbxproj index 6292d9a..e5386e0 100644 --- a/RuntimeDemo.xcodeproj/project.pbxproj +++ b/RuntimeDemo.xcodeproj/project.pbxproj @@ -25,6 +25,15 @@ 698828201C3383F8002363D5 /* HDFArchiveModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 6988281F1C3383F8002363D5 /* HDFArchiveModel.m */; }; 698828211C3383F8002363D5 /* HDFArchiveModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 6988281F1C3383F8002363D5 /* HDFArchiveModel.m */; }; 698828221C3383F8002363D5 /* HDFArchiveModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 6988281F1C3383F8002363D5 /* HDFArchiveModel.m */; }; + 6988282B1C34CB9F002363D5 /* HYBCat.m in Sources */ = {isa = PBXBuildFile; fileRef = 6988282A1C34CB9F002363D5 /* HYBCat.m */; }; + 6988282C1C34CB9F002363D5 /* HYBCat.m in Sources */ = {isa = PBXBuildFile; fileRef = 6988282A1C34CB9F002363D5 /* HYBCat.m */; }; + 6988282D1C34CB9F002363D5 /* HYBCat.m in Sources */ = {isa = PBXBuildFile; fileRef = 6988282A1C34CB9F002363D5 /* HYBCat.m */; }; + 698828301C34CBAB002363D5 /* HYBDog.m in Sources */ = {isa = PBXBuildFile; fileRef = 6988282F1C34CBAB002363D5 /* HYBDog.m */; }; + 698828311C34CBAB002363D5 /* HYBDog.m in Sources */ = {isa = PBXBuildFile; fileRef = 6988282F1C34CBAB002363D5 /* HYBDog.m */; }; + 698828321C34CBAB002363D5 /* HYBDog.m in Sources */ = {isa = PBXBuildFile; fileRef = 6988282F1C34CBAB002363D5 /* HYBDog.m */; }; + 698828351C34D476002363D5 /* HYBPig.m in Sources */ = {isa = PBXBuildFile; fileRef = 698828341C34D476002363D5 /* HYBPig.m */; }; + 698828361C34D476002363D5 /* HYBPig.m in Sources */ = {isa = PBXBuildFile; fileRef = 698828341C34D476002363D5 /* HYBPig.m */; }; + 698828371C34D476002363D5 /* HYBPig.m in Sources */ = {isa = PBXBuildFile; fileRef = 698828341C34D476002363D5 /* HYBPig.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -70,6 +79,12 @@ 6980598C1C30D6070021085B /* HYBTestModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HYBTestModel.m; sourceTree = ""; }; 6988281E1C3383F8002363D5 /* HDFArchiveModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HDFArchiveModel.h; sourceTree = ""; }; 6988281F1C3383F8002363D5 /* HDFArchiveModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HDFArchiveModel.m; sourceTree = ""; }; + 698828291C34CB9F002363D5 /* HYBCat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HYBCat.h; sourceTree = ""; }; + 6988282A1C34CB9F002363D5 /* HYBCat.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HYBCat.m; sourceTree = ""; }; + 6988282E1C34CBAB002363D5 /* HYBDog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HYBDog.h; sourceTree = ""; }; + 6988282F1C34CBAB002363D5 /* HYBDog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HYBDog.m; sourceTree = ""; }; + 698828331C34D476002363D5 /* HYBPig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HYBPig.h; sourceTree = ""; }; + 698828341C34D476002363D5 /* HYBPig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HYBPig.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -132,6 +147,7 @@ 69654F581C2CDE6600FFB5AC /* RuntimeDemo */ = { isa = PBXGroup; children = ( + 698828281C34CB6A002363D5 /* ForwardMessage */, 6988281D1C3383B4002363D5 /* Archive */, 6980598A1C30D5E90021085B /* Dict-Model */, 69654F5C1C2CDE6600FFB5AC /* AppDelegate.h */, @@ -193,6 +209,19 @@ name = Archive; sourceTree = ""; }; + 698828281C34CB6A002363D5 /* ForwardMessage */ = { + isa = PBXGroup; + children = ( + 698828291C34CB9F002363D5 /* HYBCat.h */, + 6988282A1C34CB9F002363D5 /* HYBCat.m */, + 6988282E1C34CBAB002363D5 /* HYBDog.h */, + 6988282F1C34CBAB002363D5 /* HYBDog.m */, + 698828331C34D476002363D5 /* HYBPig.h */, + 698828341C34D476002363D5 /* HYBPig.m */, + ); + name = ForwardMessage; + sourceTree = ""; + }; A4EC37D5D490197569607E30 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -382,11 +411,14 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 698828301C34CBAB002363D5 /* HYBDog.m in Sources */, + 6988282B1C34CB9F002363D5 /* HYBCat.m in Sources */, 69654F611C2CDE6600FFB5AC /* ViewController.m in Sources */, 69654F5E1C2CDE6600FFB5AC /* AppDelegate.m in Sources */, 69654F5B1C2CDE6600FFB5AC /* main.m in Sources */, 698828201C3383F8002363D5 /* HDFArchiveModel.m in Sources */, 6980598D1C30D6070021085B /* HYBTestModel.m in Sources */, + 698828351C34D476002363D5 /* HYBPig.m in Sources */, 69654F931C30214500FFB5AC /* UIControl+HYBBlock.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -396,8 +428,11 @@ buildActionMask = 2147483647; files = ( 69654F741C2CDE6600FFB5AC /* RuntimeDemoTests.m in Sources */, + 6988282C1C34CB9F002363D5 /* HYBCat.m in Sources */, 698828211C3383F8002363D5 /* HDFArchiveModel.m in Sources */, 69654F941C30214500FFB5AC /* UIControl+HYBBlock.m in Sources */, + 698828361C34D476002363D5 /* HYBPig.m in Sources */, + 698828311C34CBAB002363D5 /* HYBDog.m in Sources */, 6980598E1C30D6070021085B /* HYBTestModel.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -407,8 +442,11 @@ buildActionMask = 2147483647; files = ( 69654F7F1C2CDE6600FFB5AC /* RuntimeDemoUITests.m in Sources */, + 6988282D1C34CB9F002363D5 /* HYBCat.m in Sources */, 698828221C3383F8002363D5 /* HDFArchiveModel.m in Sources */, 69654F951C30214500FFB5AC /* UIControl+HYBBlock.m in Sources */, + 698828371C34D476002363D5 /* HYBPig.m in Sources */, + 698828321C34CBAB002363D5 /* HYBDog.m in Sources */, 6980598F1C30D6070021085B /* HYBTestModel.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/RuntimeDemo.xcworkspace/xcuserdata/huangyibiao.xcuserdatad/UserInterfaceState.xcuserstate b/RuntimeDemo.xcworkspace/xcuserdata/huangyibiao.xcuserdatad/UserInterfaceState.xcuserstate index 450ef62..cb10bb1 100644 Binary files a/RuntimeDemo.xcworkspace/xcuserdata/huangyibiao.xcuserdatad/UserInterfaceState.xcuserstate and b/RuntimeDemo.xcworkspace/xcuserdata/huangyibiao.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/RuntimeDemo/HYBCat.h b/RuntimeDemo/HYBCat.h new file mode 100644 index 0000000..b572ff4 --- /dev/null +++ b/RuntimeDemo/HYBCat.h @@ -0,0 +1,17 @@ +// +// HYBCat.h +// RuntimeDemo +// +// Created by huangyibiao on 15/12/31. +// Copyright © 2015年 huangyibiao. All rights reserved. +// + +#import + +@interface HYBCat : NSObject + + + ++ (void)test; + +@end diff --git a/RuntimeDemo/HYBCat.m b/RuntimeDemo/HYBCat.m new file mode 100644 index 0000000..0809bfd --- /dev/null +++ b/RuntimeDemo/HYBCat.m @@ -0,0 +1,68 @@ +// +// HYBCat.m +// RuntimeDemo +// +// Created by huangyibiao on 15/12/31. +// Copyright © 2015年 huangyibiao. All rights reserved. +// + +#import "HYBCat.h" +#import "HYBDog.h" +#import "HYBPig.h" +#import + +@implementation HYBCat + +// 第一步:在没有找到方法时,会先调用此方法,可用于动态添加方法 +// 我们不动态添加 ++ (BOOL)resolveInstanceMethod:(SEL)sel { + return NO; +} + +// 第二步:上一步返回NO,就会进入这一步,用于指定备选响应此SEL的对象 +// 千万不能返回self,否则就会死循环 +// 自己没有实现这个方法才会进入这一流程,因此成为死循环 +- (id)forwardingTargetForSelector:(SEL)aSelector { + return nil; +} + +// 第三步:指定方法签名,若返回nil,则不会进入下一步,而是无法处理消息 +- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { + if ([NSStringFromSelector(aSelector) isEqualToString:@"eat"]) { + return [NSMethodSignature signatureWithObjCTypes:"v@:"]; + } + + return [super methodSignatureForSelector:aSelector]; +} + +// 当我们实现了此方法后,-doesNotRecognizeSelector:不会再被调用 +// 如果要测试找不到方法,可以注释掉这一个方法 +- (void)forwardInvocation:(NSInvocation *)anInvocation { + + // 我们还可以改变方法选择器 + [anInvocation setSelector:@selector(jump)]; + // 改变方法选择器后,还需要指定是哪个对象的方法 + [anInvocation invokeWithTarget:self]; +} + +- (void)doesNotRecognizeSelector:(SEL)aSelector { + NSLog(@"无法处理消息:%@", NSStringFromSelector(aSelector)); +} + +- (void)jump { + NSLog(@"由eat方法改成jump方法"); +} + ++ (void)test { + HYBDog *dog = [[HYBDog alloc] init]; + [dog eat]; + + HYBPig *pig = [[HYBPig alloc] init]; +// [pig performSelector:@selector(eat) withObject:nil afterDelay:0]; + ((void (*)(id, SEL))objc_msgSend)((id)pig, @selector(eat)); + + HYBCat *cat = [[HYBCat alloc] init]; + [cat performSelector:@selector(eat) withObject:nil afterDelay:0]; +} + +@end diff --git a/RuntimeDemo/HYBDog.h b/RuntimeDemo/HYBDog.h new file mode 100644 index 0000000..b4e3f00 --- /dev/null +++ b/RuntimeDemo/HYBDog.h @@ -0,0 +1,16 @@ +// +// HYBDog.h +// RuntimeDemo +// +// Created by huangyibiao on 15/12/31. +// Copyright © 2015年 huangyibiao. All rights reserved. +// + +#import + +@interface HYBDog : NSObject + +// 我们只声明,而不实现 +- (void)eat; + +@end diff --git a/RuntimeDemo/HYBDog.m b/RuntimeDemo/HYBDog.m new file mode 100644 index 0000000..e72b737 --- /dev/null +++ b/RuntimeDemo/HYBDog.m @@ -0,0 +1,33 @@ +// +// HYBDog.m +// RuntimeDemo +// +// Created by huangyibiao on 15/12/31. +// Copyright © 2015年 huangyibiao. All rights reserved. +// + +#import "HYBDog.h" +#import + + +@implementation HYBDog + +// 第一步:实现此方法,在调用对象的某方法找不到时,会先调用此方法,允许 +// 我们动态添加方法实现 ++ (BOOL)resolveInstanceMethod:(SEL)sel { + // 我们这里没有给dog声明有eat方法,因此,我们可以动态添加eat方法 + if ([NSStringFromSelector(sel) isEqualToString:@"eat"]) { + class_addMethod(self, sel, (IMP)eat, "v@:"); + return YES; + } + + return [super resolveInstanceMethod:sel]; +} + +// 这个方法是我们动态添加的哦 +// +void eat(id self, SEL cmd) { + NSLog(@"%@ is eating", self); +} + +@end diff --git a/RuntimeDemo/HYBPig.h b/RuntimeDemo/HYBPig.h new file mode 100644 index 0000000..0e9ea40 --- /dev/null +++ b/RuntimeDemo/HYBPig.h @@ -0,0 +1,13 @@ +// +// HYBPig.h +// RuntimeDemo +// +// Created by huangyibiao on 15/12/31. +// Copyright © 2015年 huangyibiao. All rights reserved. +// + +#import + +@interface HYBPig : NSObject + +@end diff --git a/RuntimeDemo/HYBPig.m b/RuntimeDemo/HYBPig.m new file mode 100644 index 0000000..963267f --- /dev/null +++ b/RuntimeDemo/HYBPig.m @@ -0,0 +1,40 @@ +// +// HYBPig.m +// RuntimeDemo +// +// Created by huangyibiao on 15/12/31. +// Copyright © 2015年 huangyibiao. All rights reserved. +// + +#import "HYBPig.h" +#import "HYBDog.h" + +@implementation HYBPig + +// 第一步,我们不动态添加方法,返回NO ++ (BOOL)resolveInstanceMethod:(SEL)sel { + return NO; +} + +// 第二步,备选提供响应aSelector的对象,我们不备选,因此设置为nil,就会进入第三步 +- (id)forwardingTargetForSelector:(SEL)aSelector { + return nil; +} + +// 第三步,先返回方法选择器。如果返回nil,则表示无法处理消息 +- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { + if ([NSStringFromSelector(aSelector) isEqualToString:@"eat"]) { + return [NSMethodSignature signatureWithObjCTypes:"v@:"]; + } + + return [super methodSignatureForSelector:aSelector]; +} + +// 第三步,只有返回了方法签名,都会进入这一步,这一步用户调用方法 +// 改变调用对象等 +- (void)forwardInvocation:(NSInvocation *)anInvocation { + // 我们改变调用对象为dog + [anInvocation invokeWithTarget:[[HYBDog alloc] init]]; +} + +@end diff --git a/RuntimeDemo/ViewController.m b/RuntimeDemo/ViewController.m index 682e82f..a08264e 100644 --- a/RuntimeDemo/ViewController.m +++ b/RuntimeDemo/ViewController.m @@ -11,6 +11,7 @@ #import #import "HYBTestModel.h" #import "HDFArchiveModel.h" +#import "HYBCat.h" @interface ViewController () @@ -25,7 +26,8 @@ - (void)viewDidLoad { // Do any additional setup after loading the view, typically from a nib. // [HYBTestModel test]; - [HDFArchiveModel test]; +// [HDFArchiveModel test]; + [HYBCat test]; } - (void)didReceiveMemoryWarning {