7

問題


興味深い問題に遭遇しましたが、それに関するドキュメントを見つけることができませんでした... で宣言propertiesされたprotocolが、それに準拠する特定のクラスで実装されずprotocol、実行時例外が発生することがあります。dynamic property奇妙な状況下で定義が最適化されていますか? 宣言して作ったものと一緒に使えprotocolsない?これについての洞察は大歓迎です。propertiesdynamic

以下に詳細を示します。

与えられたprotocol:

@protocol MyProtocol <NSObject>
    @property (nonatomic, strong) id someProperty;
@end

protocolそして、そのようなものを実装するクラス:

@interface MyClass <MyProtocol>
@end

@implementation MyClass
@dynamic someProperty;
@end

電話しても情報が得られない場合があることに気付きました

class_getProperty(myClass, propertyName);

の。properties_ これは一部のクラスでprotocolのみ発生し、散発的に発生するようです。

最新の Xcode 4 を実行しており、iOS 6 SDK にリンクしています。デフォルトではありませんが(xcode-select経由)、プレリリースのXcode 5を同じマシンにインストールしています。


このコードを実行すると:

@protocol MyProtocol <NSObject>

@property (nonatomic, strong) id someData;

@end

@interface MyObject : NSObject <MyProtocol>

@end

@implementation MyObject

@dynamic someData;

@end

そしてあなたは走る

const char *name = [@"someData" UTF8String];
objc_property_t property = class_getProperty([MyObject class], name);
const char *attributes = property_getAttributes(property);

存在しない場合propertyでも、メタデータを取得します。propertyつまり、属性を取得するためにプロパティを合成する必要はありません。ランタイムはまだそれを認識しています。自分で試してみてください。問題は、これが起こらない場合があることです。propertyランタイムが属性を認識しない原因となる条件を知りたいです。

一時的な修正


私の一時的な修正は、すべてのproperty定義をコピーprotocolして .h ファイルに貼り付けることです。

@interface MyClass <MyProtocol>
    @property (nonatomic, strong) id someProperty;
@end

@implementation MyClass
@dynamic someProperty;
@end

理想からは程遠いですが、これは問題なく動作します。ただし、コードが正しく機能しており、問題が別の場所にあることを示唆しています。

必要に応じて、詳細や背景をお知らせいただければ幸いです。

4

3 に答える 3

0

多くのデバッグとテストを行った結果、これはバグであると結論付けました。反証や提案がある場合は、遠慮なく投稿してください。バグはこれです:

が で定義されていて、クラスが前述の に準拠している場合、が としてフラグ付けされている場合、ランタイムは属性を認識しません (たとえば、class_getProperty が失敗します) 。propertyprotocolprotocolproperty'spropertydynamic

覚えておいてください、実装dynamicは提供されません。警告を抑制するだけですが、ランタイムを介して属性を取得できる必要があります。property

これらのタイプの問題を解決/デバッグするために、いくつかの便利なコード スニペットを追加したいと考えました。

- (NSArray *)propertyNamesForClass:(Class)aClass includeInherited:(BOOL)shouldIncludeInherited;
{
    NSMutableArray *names = [NSMutableArray array];
    uint propertyCount = 0;
    objc_property_t *properties = class_copyPropertyList(aClass, &propertyCount);
    for (uint i = 0; i < propertyCount; i++) {
        [names addObject:[NSString stringWithUTF8String:property_getName(properties[i])]];
    }

    if (shouldIncludeInherited) {
        Class superClass = aClass;
        while ((superClass = class_getSuperclass(superClass))) {
            uint superPropertyCount = 0;
            objc_property_t *superProperties = class_copyPropertyList(superClass, &superPropertyCount);
            for (uint i = 0; i < superPropertyCount; i++) {
                [names addObject:[NSString stringWithUTF8String:property_getName(superProperties[i])]];
            }
        }
    }

    NSArray *sortedNames = [names sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
    return sortedNames;
}

- (NSArray *)protocolNamesForClass:(Class)aClass includeInherited:(BOOL)shouldIncludeInherited;
{
    NSMutableArray *names = [NSMutableArray array];
    uint protocolCount = 0;
    __unsafe_unretained Protocol **protocolArray = class_copyProtocolList(aClass, &protocolCount);
    for (uint i = 0; i < protocolCount; i++) {
        [names addObject:NSStringFromProtocol(protocolArray[i])];
    }

    if (shouldIncludeInherited) {
        Class superClass = aClass;
        while ((superClass = class_getSuperclass(superClass))) {
            uint superProtocolCount = 0;
            __unsafe_unretained Protocol **superProtocolArray = class_copyProtocolList(superClass, &superProtocolCount);
            for (uint j = 0; j < superProtocolCount; j++) {
              [names addObject:NSStringFromProtocol(superProtocolArray[j])];
            }
        }
    }

    NSArray *sortedNames = [names sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
    return sortedNames;
}

- (NSArray *)propertyNamesForProtocol:(Protocol *)aProtocol
{
    NSMutableArray *names = [NSMutableArray array];
    uint protocolPropertyCount = 0;
    objc_property_t *properties = protocol_copyPropertyList(aProtocol, &protocolPropertyCount);
    for (uint j = 0; j < protocolPropertyCount; j++) {
        [names addObject:[NSString stringWithUTF8String:property_getName(properties[j])]];
    }

    NSArray *sortedNames = [names sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
    return sortedNames;
}
于 2013-07-11T18:36:18.957 に答える