iOSでのruntimeの使用をまとめます

6001 ワード

iOSの友达はruntimeを知っていたり、聞いたりしています.これはjavaの反射メカニズムに似ていますが、機能はjavaの反射よりはるかに優れています.runtimeでは、クラスに属性、メンバー変数、メソッド、および読み書きアクセスを動的に追加できます.
一、runtimeの概要
RunTime略称運転時.OCはランタイムメカニズム、すなわちランタイムのいくつかのメカニズムであり、その中で最も主要なのはメッセージメカニズムである.
C言語の場合、関数の呼び出しはコンパイル時にどの関数を呼び出すかを決定します.
OCの関数については,動的呼び出しプロセスに属し,コンパイル時にどの関数を本当に呼び出すかを決定することはできず,実際に実行される場合にのみ関数の名前に基づいている.
対応する関数を見つけて呼び出します.
事実証明:
    コンパイルフェーズでは、OCは、この関数が実装されていない場合でも、宣言さえすればエラーを報告しない任意の関数を呼び出すことができます.
    コンパイル段階では,C言語が実装されていない関数を呼び出すとエラーが報告される.
二、runtime作用
1.メッセージの送信
メソッド呼び出しの本質は,オブジェクトにメッセージを送信させることである.objc_msgSend,は、オブジェクトのみがメッセージを送信ことができるため、objcで始まる.
メッセージ・メカニズムを使用する前提で、#import
をインポートする必要があります.
メッセージ・メカニズムの簡単な使用
メッセージメカニズムの原理:オブジェクトはメソッド番号SELに基づいてテーブルをマッピングして対応するメソッドを検索して実現する

   //   person  
  Person *p = [[Person alloc] init];

  //       
  [p eat];
  // SEL:    ,                 
  [p performSelector:@selector(eat)];

  //   :       
  objc_msgSend(p, @selector(eat));

  //         :  
  //                    
  [Person eat];
  //           
  [[Person class] eat];

  [personClass performSelector:@selector(eat)];
  //         ,                
  //   :        
  objc_msgSend([Person class], @selector(eat));

2.交換方法
開発使用シーン:システムが持参した方法の機能が足りず、システムが持参した方法にいくつかの機能を拡張し、既存の機能を維持する.
方式一:システムのクラスを継承し、書き換える方法.
方式2:runtimeを用いて、交換方法.

@implementation ViewController


- (void)viewDidLoad {
  [super viewDidLoad];
  // Do any additional setup after loading the view, typically from a nib.
  //   : imageNamed      ,                  。
  //    :     ,                 + (UIImage *)xmg_imageNamed:(NSString *)imageName;
  //    :  imageNamed xmg_imageNamed   ,    xmg_imageNamed,    xmg_imageNamed   。
  UIImage *image = [UIImage imageNamed:@"123"];

     imageNamed:
       :    PH_imageNamed

     :         imageNamed PH_imageNamed  
     imageNamed      PH_imageNamed


   imageNamed    ,            
       imageNamed   ,         


}

@end


@implementation UIImage (Image)
//             
+ (void)load
{
  //       ,          
  // class_getMethodImplementation:      
  // class_getInstanceMethod:    
  // class_getClassMethod:     
  // IMP:    

  // imageNamed
  // Class:       
  // SEL:      ,  SEL          

  Method imageNameMethod = class_getClassMethod([UIImage class], @selector(imageNamed:));

  Method PH_imageNameMethod = class_getClassMethod([UIImage class], @selector(PH_imageNamed:));

  //       
  method_exchangeImplementations(imageNameMethod, PH_imageNameMethod);
}

 

}

//             imageNamed,             ,         super.

//           
+ (UIImage *)PH_imageNamed:(NSString *)imageName
{
  //     
  UIImage *image = [UIImage PH_imageNamed:imageName];
  // 2.    
  if (image == nil) {
    NSLog(@"    ");
  }

  return image;
}


@end

3.動的追加方法
使用シーンの開発:クラスメソッドが非常に多い場合、クラスをメモリにロードする際にもリソースがかかります.各メソッドにマッピングテーブルを生成する必要があります.動的にクラスに追加したり、メソッドを追加したりして解決できます.
単純な使用

@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];
  // Do any additional setup after loading the view, typically from a nib.

  Person *p = [[Person alloc] init];

  //   person,    eat  ,    performSelector  ,     。
  //            
  [p performSelector:@selector(eat)];

}


@end

@implementation Person
// void(*)()
//             ,
            ,self,_cmd,    
 self:     
 _cmd:       
void eat(id self,SEL sel)
{
  NSLog(@"%@ %@",self,NSStringFromSelector(sel));
}

//              ,         ,              .
//         ,                    





+ (BOOL)resolveInstanceMethod:(SEL)sel
{

  if (sel == @selector(eat)) {
    //     eat  

    //      :        
    //      :         
    //      :         (    )
    //      :     ,(   +    ) v:void @:  ->self :  SEL->_cmd
    class_addMethod(self, @selector(eat), eat, "v@:");

  }

  return [super resolveInstanceMethod:sel];
}
@end

4.分類に属性を追加
原理:クラスに属性を宣言するが、本質はこのクラスに関連付けを追加することであり、この値のメモリ領域をクラスメモリ領域に直接追加するわけではない.

@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];
  // Do any additional setup after loading the view, typically from a nib.

  //    NSObject       name

  NSObject *objc = [[NSObject alloc] init];
  objc.name = @"abc";
  NSLog(@"%@",objc.name);
}
@end


//      key
static const char *key = "name";

- (void)setName:(NSString *)name
{
  //     ,   
  //          ,    
  // object:         
  // key:   ,  key         ,void * == id
  // value:    
  // policy:  

  objc_setAssociatedObject(self, @"name", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSString *)name
{

  return objc_getAssociatedObject(self, @"name");
}

以上iOSのruntimeの使用概要ですが、この文章は主に原理と使い方のまとめで、runtimeの機能はとても強くて、友达がもっと勉強して研究しなければなりません.本文が皆さんに役に立つことを願っています.