开发者

Key/value observing not firing for property defined as: @property (readwrite, retain) __attribute__((NSObject)) CGImageRef thumbnailImage

I have a class with a property definition like so:

// Interface
@property (retain) __attribute__((NSObject)) CGImageRef thumbnailImage;

// Implementation
@synthesize thumbnailImage;

The problem is that self.thumbnailImage = newCGImageRef; does no开发者_如何学编程t cause it to fire a key/value observation event and observeValueForKeyPath:... is never called.

I tested the code with another property (BOOL) of the same class and it works just fine for that one. Shouldn't this also work for the property above?

Note: I tried setting the property manually ([self setValue:newValue forKey:@"thumbnailImage"], which resulted in the error below:

setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key thumbnailImage.


__attribute__((NSObject)) tells the compiler to treat structure pointers as an object therefore this allows you to retain/release the object (often used for blocks). This attribute has no effect on the fact that CFImageRef is a struct pointer and KVC does not automatically wrap struct pointers though it will wrap structs. To solve your issue you will need to intercept KVC on undefined keys to set and return the correct object, or just use UIImage instead.

KVC Documentation:

Automatic wrapping and unwrapping is not confined to NSPoint, NSRange, NSRect, and NSSize—structure types (that is, types whose Objective-C type encoding strings start with {) can be wrapped in an NSValue object.

TestCF_KVC.h

#import <Foundation/Foundation.h>

typedef struct
{
    int x, y, z;
} AStruct;

@interface TestCF_KVC : NSObject {}

@property (nonatomic, retain) NSString *text;
@property (nonatomic, assign) AStruct aStruct;
@property (nonatomic, retain) __attribute__((NSObject)) CFStringRef cftext;

-(void)test;

@end

TestCF_KVC.m

#import "TestCF_KVC.h"

@implementation TestCF_KVC

@synthesize text, aStruct, cftext;

-(void)setValue:(id)value forUndefinedKey:(NSString *)key
{
    NSLog(@"undefined key set for %@", key);
    if([key isEqualToString:@"cftext"])
    {
        self.cftext = (CFStringRef)value;
    }
    else
    {
        [super setValue:value forUndefinedKey:key];
    }
}

-(id)valueForUndefinedKey:(NSString *)key
{
    NSLog(@"undefined key get for %@", key);
    if([key isEqualToString:@"cftext"])
    {
        return (NSString*)self.cftext;
    }

    return [super valueForUndefinedKey:key];
}

-(void)test
{
    NSString *txt = @"text worked";
    AStruct astr = { .x=1, .y=5, .z=10 };
    CFStringRef cftxt = (CFStringRef)@"cftext worked";

    //Test a normal NSString for KVC
    [self setValue:txt forKey:@"text"];
    txt = [self valueForKey:@"text"];
    NSLog(@"text[%s]: %@", @encode(NSString), [self valueForKey:@"text"]);

    //Test a struct for KVC
    NSValue *value = [NSValue value:&astr withObjCType:@encode(AStruct)];
    [self setValue:value forKey:@"aStruct"];
    [[self valueForKey:@"aStruct"] getValue:&astr];
    NSLog(@"aStruct[%s]: %d %d %d", @encode(AStruct), aStruct.x, aStruct.y, aStruct.z);

    //Test a Core Foundation type for KVC
    [self setValue:(NSString*)cftxt forKey:@"cftext"];
    cftxt = (CFStringRef)[self valueForKey:@"cftext"];
    NSLog(@"cftext[%s]: %@", @encode(CFStringRef), (NSString*)cftxt);
}

@end

Log Output From Calling -test:

text[{NSString=#}]: text worked
aStruct[{?=iii}]: 1 5 10
undefined key set for cftext
undefined key get for cftext
cftext[^{__CFString=}]: cftext worked
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜