13、用“方法调配技术” 调试 “黑盒方法”


     Objective-C 对象收到消息之后,调用何种方法需要在运行期才能解析处理啊。给定选择子名称相对饮给的方法,可以在运行期改变。(线功能可在本类的所有实例中生效,而不是仅限于覆写了相关方法的那些子类实例)此方案经常成为“方法调配”
     类的方法列表会把选择子的名称映射到相关的方法实现上,使得“动态消息派发系统”能够据此找到应该调用的方法。这些方法均以函数指针形式来表示,这种指针叫IMP,其原型如下
     id (* IMP)(id SEL, ...)
     NSString 类可以响应 lowercaseString(小写字母),uppercaseString(大写字母)/capitalizedString 等选择子。这张映射表中的每个选择子都映射到不同的IMP之上。
     图  object_20191120_001.png
     P53
     Objective-C运行期系统提供了几个方法能都操作这张表。开发者可以向其中新增选择子,也可以改变选择子所对应的方法实现,还可以交换两个选择子映射到的指针。
     图  object_20191120_002.png
     上述修改无需编写子类,只是修改了“方发表”的布局,就会放映到程序中所有的NSString实例上。
     
     互换两个方法实现
     void method_exchangeImplementations(Method m1, Method m2);
     
     此函数的两个参数表示待交互的两个方法实现,而方法实现则可通过下列函数获得
     
     Method class_getInstanceMethod(Class aClass, SEL aSelector)
     
     此函数根据给定的选择从类中取出与之想关的方法。执行下列代码,即可交换前面提到的lowerecaseString 与 uppercaseString 方法实现
     
     Method originalMethod = class_getInstanceMethod([NSString class], @selector(lowercaseString));
     
     Method swappedMethod = class_getInstanceMethod([NSString class], @selector(uppercaseString));
     method_exchangeImplementations(originalMethod, swappedMethod);
     
     从现在开始,如果在NSString 实例上调用 lowercaseString,那么执行的将是 uppercaseString 的原有实现
     这样直接交换方法的实现,意义并不大。但是,可以通过这一手段为即有的方法实现增添新功能。
     例: 在调用 lowercaseString 时记录某些信息,这是就可以通过交换方法实现来达成次目标。我们新便写一个方法,在此方法中实现所需的附加功能,并调用原有实现。
        新方法可以添加至NSString 的“分类”(category)中:
     @interface NSString (LJLMyAdditions)
     -(NSString *)ljl_myLowercaseString;
     @end
     
     将原有的 lowercaseString(小写字母) 与 ljl_myLowercaseString 方法交换。新方法的实现代码可以这样写
     @implementation NSString (LJLMyadditions)
     -(NSString *)ljl_myLowercaseString{
        NSString * lowercase = [self lowercaseString];
        NSLog(@"%@ => %@",self, lowercase);
        return lowercase;
     }
     @end
     
     看上去像是递归调用死循环,但是因为这个方法是要和 lowercaseString 方法互换的,所以在运行期,ljl_myLowercaseString 选择子实际上对应于原有的 lowercaseString 方法实现。最后,通过下列代码来交换着两个方法实现:
     
     Method originalMethod = class_getInstanceMethod(NSString class, @selector(lowercaseString));
     Method swappedMethod = class_getInstanceMethod(NSString class, @selector(ljl_myLowercaseString));
     method_exchangeImplementations(originalMethod, swappedMethod);
     
    再执行 lowercaseString 就会输出一行记录消息
     
     一般通过此方案给不公开的方法(黑盒方法)增加日志记录功能,有助于调试。
     
     重点:
     1、在运行期,可以向勒种新增或替换选择子所对应的方法实现。
     2、使用另一份实现来替换原有的方法实现,这道工序叫做“方法调配”,开发者常用此技术向原有实现中添加新功能
     3、一般来说,只有调试程序的时候才需要在运行期修改方法实现,这种做法不宜滥用。

参考:Effective  objective-C2.0
    

发布了83 篇原创文章 · 获赞 12 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/shengdaVolleyball/article/details/103186842