Наблюдение, что ключ / значение не срабатывают для свойства, определенного как: @property (readwrite, retain) __attribute __ ((NSObject)) CGImageRef thumbnailImage - PullRequest
3 голосов
/ 09 сентября 2011

У меня есть класс с определением свойства, например:

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

// Implementation
@synthesize thumbnailImage;

Проблема в том, что self.thumbnailImage = newCGImageRef; не приводит к запуску события наблюдения ключ / значение, и observeValueForKeyPath:... никогда не вызывается.

Я протестировал код с другим свойством (BOOL) того же класса, и он прекрасно работает для этого. Разве это не должно работать на собственность выше?

Примечание: я попытался установить свойство вручную ([self setValue:newValue forKey:@"thumbnailImage"], что привело к ошибке ниже:

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

1 Ответ

4 голосов
/ 09 сентября 2011

__attribute__((NSObject)) говорит компилятору обрабатывать указатели структуры как объект, поэтому это позволяет вам сохранять / освобождать объект (часто используемый для блоков). Этот атрибут не влияет на тот факт, что CFImageRef является указателем на структуру, а KVC не выполняет автоматическую упаковку указателей на структуры, хотя он и переносит структуры. Чтобы решить вашу проблему, вам нужно будет перехватить KVC на неопределенных ключах, чтобы установить и вернуть правильный объект, или просто использовать UIImage.

KVC Документация:

Автоматическая упаковка и распаковка не ограничиваются NSPoint, NSRange, NSRect и NSSize - структурные типы (то есть типы, чей Objective-C строки кодирования типа, начинающиеся с {), могут быть обернуты в NSValue объект.

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

Вывод журнала из вызовов -test:

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