Runtimeアクセスプライベート変数とメソッドおよびKVOアクセス

5075 ワード

一、Class
以前の記事では、すべてのオブジェクトにisaポインタが対応するクラスClassを指し、Classはobjc_class構造体、構造体:
  • インスタンス変数リストobjc_ivar_list
  • メソッドリストobjc_method_List対応runtime取得方法:
  • Ivar *class_copyIvarList(Class cls, unsigned int *outCount)
    Method *class_copyMethodList(Class cls, unsigned int *outCount)  
    

    まずTestクラスを作成します.
    //
    //  Test.h
    //  RuntimeKVC
    //
    //  Created by z on 2019/5/24.
    //  Copyright © 2019  com.jzsec. All rights reserved.
    //
    
    #import 
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface Test : NSObject
    {
        @public
        NSString *name;
        
        /*  , @protected */
        @private
        NSString *major;
    }
    
    @property (nonatomic, strong) Test *childTest;
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    //
    //  Test.m
    //  RuntimeKVC
    //
    //  Created by z on 2019/5/24.
    //  Copyright © 2019  com.jzsec. All rights reserved.
    //
    
    #import "Test.h"
    
    @interface Test ()
    {
        /*  , j @private */
        int age;
    }
    
    /*   */
    @property (nonatomic, copy) NSString *job;
    
    /*  , j @private */
    - (void)test;
    
    @end
    
    @implementation Test
    
    -(void)test
    {
        NSLog(@" ");
    }
    
    @end
    

    二、Runtimeアクセス
    runtime暴力アクセスプライベート属性、プライベート変数、およびプライベートメソッド
    // 
            unsigned int count = 0;
            Ivar *members = class_copyIvarList([Test class], &count);
            //   
            for (int i=0; i
    /*   */
            // 
            unsigned int countM = 0;
            Method *methods = class_copyMethodList([Test class], &countM);
            for (int i=0; i

    印刷結果:
    2019-08-08 18:01:44.593507+0800 RuntimeKVC[23807:412395] name:name type:@"NSString"
    2019-08-08 18:01:44.593616+0800 RuntimeKVC[23807:412395] name= 
    2019-08-08 18:01:44.593635+0800 RuntimeKVC[23807:412395] name:major type:@"NSString"
    2019-08-08 18:01:44.593676+0800 RuntimeKVC[23807:412395] major= 
    2019-08-08 18:01:44.593691+0800 RuntimeKVC[23807:412395] name:age type:i
    2019-08-08 18:01:44.593745+0800 RuntimeKVC[23807:412395] age=30
    2019-08-08 18:01:44.593761+0800 RuntimeKVC[23807:412395] name:_childTest type:@"Test"
    2019-08-08 18:01:44.593784+0800 RuntimeKVC[23807:412395] name:_job type:@"NSString"
    2019-08-08 18:01:44.593803+0800 RuntimeKVC[23807:412395] job= 
    2019-08-08 18:01:44.593884+0800 RuntimeKVC[23807:412395] method:newProperty
    2019-08-08 18:01:44.593961+0800 RuntimeKVC[23807:412395] method:setNewProperty:
    2019-08-08 18:01:44.593990+0800 RuntimeKVC[23807:412395] method:setChildTest:
    2019-08-08 18:01:44.594044+0800 RuntimeKVC[23807:412395] method:childTest
    2019-08-08 18:01:44.594087+0800 RuntimeKVC[23807:412395] method:test
    2019-08-08 18:01:44.605142+0800 RuntimeKVC[23807:412395]  
    2019-08-08 18:01:44.605186+0800 RuntimeKVC[23807:412395] method:.cxx_destruct
    2019-08-08 18:01:44.605276+0800 RuntimeKVC[23807:412395] method:job
    2019-08-08 18:01:44.605300+0800 RuntimeKVC[23807:412395] method:setJob:
    

    三、KVOアクセス
    システムのクラス内のNSObject(NSKeyValue Coding)では、keyを使用して属性の値を読み取り、設定できます.
    - (void)setValue:(nullable id)value forKey:(NSString *)key;
    - (nullable id)valueForKey:(NSString *)key;
    //nullable : ;nonnull : 
    

    keyで対応する属性または変数を検索する場合:
  • まずオブジェクトのクラスにkeyに対応するアクセサメソッドが存在するかどうかを検索する.
  • キー名と同じ名前で「」付きで検索接頭辞のメンバー変数;
  • key名と同じ属性;
  • 以上がない場合はsetValue:forUndefinedKey:メソッドを呼び出します.
  • /* KVO  */
            [test setValue:@"testName" forKey:@"name"];
            NSString *tname = [test valueForKey:@"name"];
            [test setValue:@"18" forKey:@"age"];
            NSString *tage = [test valueForKey:@"age"];
            [test setValue:@"mathmetics" forKey:@"major"];
            NSString *tmajor = [test valueForKey:@"major"];
            NSLog(@"name:%@ age:%@ major:%@", tname, tage, tmajor);
    
            Test *child = [Test new];
            test.childTest = child;
            child->name = @" ";
            NSString *cname = [test valueForKeyPath:@"childTest.name"];
            NSLog(@"test.childTest.name:%@", cname);
            [test setValue:@" ×" forKeyPath:@"childTest.name"];
            NSString *cname1 = [test valueForKeyPath:@"childTest.name"];
            NSLog(@"test.childTest.name:%@", cname1);
    

    印刷結果:
    2019-08-08 18:01:44.605938+0800 RuntimeKVC[23807:412395] name:testName age:18 major:mathmetics
    2019-08-08 18:01:44.606054+0800 RuntimeKVC[23807:412395] test.childTest.name: 
    2019-08-08 18:01:44.606084+0800 RuntimeKVC[23807:412395] test.childTest.name: ×