设为首页 加入收藏

TOP

Objective-C对象模型及应用(二)
2014-11-23 19:25:41 来源: 作者: 【 】 浏览:33
Tags:Objective-C 对象 模型 应用
egistered for an attribute of an object the isa pointer of the observed object is modified, pointing to an intermediate class rather than at the true class. As a result the value of the isa pointer does not necessarily reflect the actual class of the instance.

You should never rely on the isa pointer to determine class membership. Instead, you should use the class method to determine the class of an object instance.

类似的,使用isa swizzling的技术的还有系统提供的Key-Value Coding(KVC)。 (谢谢大家指出错误,KVC并没有使用到isa swizzling)

Method Swizzling API说明

Objective-C提供了以下API来动态替换类方法或实例方法的实现:

  • class_replaceMethod 替换类方法的定义
  • method_exchangeImplementations 交换2个方法的实现
  • method_setImplementation 设置1个方法的实现

    这3个方法有一些细微的差别,给大家介绍如下:

    • class_replaceMethod在苹果的文档(如下图所示)中能看到,它有两种不同的行为。当类中没有想替换的原方法时,该方法会调用class_addMethod来为该类增加一个新方法,也因为如此,class_replaceMethod在调用时需要传入types参数,而method_exchangeImplementationsmethod_setImplementation却不需要。

      \

      • method_exchangeImplementations 的内部实现其实是调用了2次method_setImplementation方法,从苹果的文档中能清晰地了解到(如下图所示)

        \

        从以上的区别我们可以总结出这3个API的使用场景:

        • class_replaceMethod, 当需要替换的方法可能有不存在的情况时,可以考虑使用该方法。
        • method_exchangeImplementations,当需要交换2个方法的实现时使用。
        • method_setImplementation 最简单的用法,当仅仅需要为一个方法设置其实现方式时使用。

          使用示例

          我们在开发猿题库客户端的笔记功能时,需要使用系统的UIImagePickerController。但是,我们发现,在iOS6.0.2系统下,系统提供的UIImagePickerController在iPad横屏下有转屏的Bug,造成其方向错误。具体的Bug详情可以见这里。

          为了修复该Bug,我们需要替换UIImagePickerController的如下2个方法

          1
          2
          
          - (BOOL)shouldAutorotate;
          - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation;
          

          我们先实现了一个名为ImagePickerReplaceMethodsHolder的类,用于定义替换后的方法和实现。如下所示:

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          
          // ImagePickerReplaceMethodsHolder.h
          @interface ImagePickerReplaceMethodsHolder : NSObject
          - (BOOL)shouldAutorotate;
          - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation;
          @end
          // ImagePickerReplaceMethodsHolder.m
          @implementation ImagePickerReplaceMethodsHolder
          - (BOOL)shouldAutorotate {
              return NO;
          }
          - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
              return UIInterfaceOrientationPortrait;
          }
          @end
          

          然后,我们在调用处,判断当前的iOS版本,对于[iOS6.0, iOS6.1)之间的版本,我们将UIImagePickerController的有问题的方法替换。具体代码如下:

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          
          #define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
          #define SYSTEM_VERSION_LESS_THAN(v)                 ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
          + (void)load {
              static dispatch_once_t onceToken;
              dispatch_once(&onceToken, ^{
                  [self hackForImagePicker];
              });
          }
          + (void)hackForImagePicker {
              // fix bug of image picker under iOS 6.0
              // http://stackoverflow.com/questions/12522491/crash-on-presenting-uiimagepickercontroller-under-ios-6-0
              if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"6.0")
                  && SYSTEM_VERSION_LESS_THAN(@"6.1")) {
                  Method oldMethod1 = class_getInstanceMethod([UIImagePickerController class], @selector(shouldAutorotate));
                  Method newMethod1 = class_getInstanceMethod([ImagePickerReplaceMethodsHolder class], @selector(shouldAutorotate));
                  method_setImplementation(oldMethod1, method_getImplementation(newMethod1));
                  Method
          首页 上一页 1 2 3 下一页 尾页 2/3/3
          】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
          分享到: 
          上一篇c语言scanf()停止接受输入及scanf.. 下一篇C语言中容易被忽略的细节(第三篇..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: