class_addPropertyメソッドのobjc_property_attribute_tパラメータの順序が重要

3022 ワード

今日はruntime関連のものを作って、穴を踏んで、記録しました.
まず、このコードを見てください.
+ (void)addStrPropertyForTargetClass:(Class)targetClass Name:(NSString *)propertyName{
    objc_property_attribute_t type = { "T", [[NSString stringWithFormat:@"@\"%@\"",NSStringFromClass([NSString class])] UTF8String] }; //type
    objc_property_attribute_t ownership0 = { "C", "" }; // C = copy
    objc_property_attribute_t ownership = { "N", "" }; //N = nonatomic
    objc_property_attribute_t backingivar  = { "V", [[NSString stringWithFormat:@"_%@", propertyName] UTF8String] };  //variable name
    objc_property_attribute_t attrs[] = { type, ownership0, ownership, backingivar };
    if (class_addProperty(targetClass, [propertyName UTF8String], attrs, 4)) {
        // get set 
        [targetClass addObjectProperty:propertyName];
        DDLogDebug(@" Property ");
    }
}

上記のコードは、実行時にクラスに新しいNSStringオブジェクトを追加することができます.このオブジェクトのいくつかの主な特性は、主にコード内のobjc_に依存します.property_attribute_t定義.
動的構成の必要性からobjc_property_attribute_objc_のため、t変数は柔軟に構成されます.property_attribute_tは二値構造体なのでDictionaryで保存するのに適しています.そこで私はDictionaryを使ってobjc_をすべて保存しました.property_attribute_t変数の文字列情報.
その後Dictionaryを巡り、attributeデータを取得してattrs配列に追加します.
問題はこの時に発生しました.その後、この新しいpropertyのtypeを取得する必要があるとき、意外にも空いていました.
次に、次のコードですべてのプロパティを印刷します.
@autoreleasepool {
        unsigned int outCount, i;
        objc_property_t *properties = class_copyPropertyList([TestClass class], &outCount);
        for (i = 0; i < outCount; i++) {
            objc_property_t property = properties[i];
            fprintf(stdout, "mytest %s %s
", property_getName(property), property_getAttributes(property)); } }

結果:
mytest strNew V_strNew,T@"NSString",C,N
mytest strName T@"NSString",C,N,V_shopid

その中のstrNameは元のProperty変数で、strNewは新しく追加されました.strNewとstrNameの後の属性には微妙な違いがあります.順序が違います.これが問題の原因ですか.試してみると、私は本当に新しいコードにattributeを追加する順序を変えて、strNameのattributeの順序と一致して、テストして、意外にもよかったです.
この順序は勝手に設定されていないことを説明し、githubのこのコードCocoaScript/MOProtocolDescriptionに続く.m at master・ccgus/CocoaScriptでは、特にType encoding must be first、Backing ivar must be lastを指摘するいくつかの説明が見つかりました.
2017年5月13日午後4時39分今日、この用途はどこにあるのかと聞かれた人に会いました.誰かが聞いた以上、JSPachに使われていると言ってください.JSPachで独自の方法で追加された属性は反射をサポートしていないのを覚えていますが、JSの方法で追加されたようです.つまり、OCの最下位を歩いて属性を追加していないので、MJExtension、JsonModelなどの第三者JSON処理ライブラリは、OCの反射技術でクラスやオブジェクトのすべての属性を遍歴しているため、jsで追加された属性を処理できません.
関連するオープンソースライブラリ:wonderffee/DFDynamicPropertyにメモリが漏洩している可能性があります.慎重に使用してください.

げんり


classを使ったaddPropertyは、既存のクラスに新しいpropertyを追加し、動的に追加されたプロパティにオーバー反射を使用することができます.JSPAChのパッチ適用に適している場合classを呼び出さない理由addIvarは、既存のクラスのメモリレイアウトを変更するため、インスタンス変数を追加します.一般的にobjc_class_を呼び出すには、classを動的に作成します.addIvarはIvarを作成し、最後にobjc_を通過します.registerClassPairはclassを登録します.一般的にパッチを適用する必要はありません.

参照先:


ios動的に属性を追加するいくつかの方法-shengyumojianのコラム-ブログチャンネル-CSDN.NET