2009-10-21 6 views
10

Tôi có ứng dụng Dữ liệu cốt lõi với mô hình dữ liệu khá đơn giản. Tôi muốn có thể lưu trữ các thể hiện của NSImage trong cửa hàng liên tục dưới dạng các đối tượng Nmap bitmap của PNG, để tiết kiệm không gian.Tại sao thuộc tính Dữ liệu cốt lõi có thể biến đổi của tôi không sử dụng NSValueTransformer tùy chỉnh của tôi?

Để kết thúc này, tôi đã viết một NSValueTransformer đơn giản để chuyển đổi một NSImage thành NSData ở định dạng bitmap PNG. Tôi đăng ký biến giá trị với mã này trong đại biểu App của tôi:

+ (void)initialize 
{ 
    [NSValueTransformer setValueTransformer:[[PNGDataValueTransformer alloc] init] forName:@"PNGDataValueTransformer"]; 
} 

Trong mô hình dữ liệu của tôi, tôi đã thiết lập các thuộc tính hình ảnh là năng biến, và quy định PNGDataValueTransformer như tên giá trị biến.

Tuy nhiên, biến áp giá trị tùy chỉnh của tôi không được sử dụng. Tôi biết điều này vì tôi đã đặt thông điệp tường trình trong các phương thức -transformedValue:-reverseTransformedValue của trình biến đổi giá trị không được ghi lại và dữ liệu đang được lưu vào đĩa chỉ là một NSImage được lưu trữ chứ không phải đối tượng NSData PNG mà nó cần.

Tại sao tính năng này không hoạt động?

Đây là mã của biến giá trị của tôi:

@implementation PNGDataValueTransformer 

+ (Class)transformedValueClass 
{ 
    return [NSImage class]; 
} 

+ (BOOL)allowsReverseTransformation 
{ 
    return YES; 
} 

- (id)transformedValue:(id)value 
{ 
    if (value == nil) return nil; 
    if(NSIsControllerMarker(value)) 
     return value; 
    //check if the value is NSData 
    if(![value isKindOfClass:[NSData class]]) 
    { 
     [NSException raise:NSInternalInconsistencyException format:@"Value (%@) is not an NSData instance", [value class]]; 
    } 
    return [[[NSImage alloc] initWithData:value] autorelease]; 
} 

- (id)reverseTransformedValue:(id)value; 
{ 
    if (value == nil) return nil; 
    if(NSIsControllerMarker(value)) 
     return value; 
    //check if the value is an NSImage 
    if(![value isKindOfClass:[NSImage class]]) 
    { 
     [NSException raise:NSInternalInconsistencyException format:@"Value (%@) is not an NSImage instance", [value class]]; 
    } 
    // convert the NSImage into a raster representation. 
    NSBitmapImageRep* bitmap = [NSBitmapImageRep imageRepWithData: [(NSImage*) value TIFFRepresentation]]; 
    // convert the bitmap raster representation into a PNG data stream 
    NSDictionary* pngProperties = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO] forKey:NSImageInterlaced]; 
    // return the png encoded data 
    NSData* pngData    = [bitmap representationUsingType:NSPNGFileType properties:pngProperties]; 
    return pngData; 
} 

@end 

Trả lời

0

Nếu không có gì trong mã của bạn ở nơi khác explicity sử dụng lớp PNGDataValueTransformer thì + phương pháp khởi tạo cho lớp đó sẽ không bao giờ được gọi. Chỉ định tên trong mô hình dữ liệu cốt lõi của bạn sẽ không kích hoạt nó - nó sẽ chỉ đơn giản là cố gắng tìm kiếm một biến áp giá trị cho tên đó, mà sẽ trở về nil, vì không có trường hợp biến áp chưa được đăng ký dưới tên đó.

Nếu điều này thực sự xảy ra trong trường hợp của bạn, chỉ cần thêm lệnh gọi [PNGDataValueTransformer khởi tạo] ở đâu đó trong mã của bạn trước khi mô hình dữ liệu của bạn được truy cập, ví dụ: trong phương thức khởi tạo + của bất kỳ lớp nào, nó đang sử dụng mô hình dữ liệu này. Điều đó sẽ kích hoạt cá thể biến thể giá trị được tạo và đăng ký sao cho Dữ liệu cốt lõi có thể truy cập nó khi cần.

+0

Hi Brian, các '+ initialize' phương pháp là ở đại biểu ứng dụng của tôi, không phải là biến giá trị và tôi chắc chắn có thể xác minh rằng nó đang được gọi. Nếu tôi đặt một điểm ngắt trong phương thức '-init' của NSValueTransformer, nó chắc chắn được khởi tạo. Nếu tôi đặt thuộc tính là loại "nhị phân" và áp dụng biến áp giá trị của tôi cho từng ràng buộc trong IB, nó hoạt động tốt. Tôi chỉ không hiểu tại sao biến tùy chỉnh không được sử dụng khi tôi chỉ định kiểu thuộc tính là Biến đổi. –

25

Nếu tôi không nhầm, biến áp giá trị của bạn có hướng ngược lại. Tôi làm điều tương tự trong đơn đăng ký của tôi, sử dụng mã như sau:

+ (Class)transformedValueClass 
{ 
return [NSData class]; 
} 

+ (BOOL)allowsReverseTransformation 
{ 
return YES; 
} 

- (id)transformedValue:(id)value 
{ 
if (value == nil) 
    return nil; 

// I pass in raw data when generating the image, save that directly to the database 
if ([value isKindOfClass:[NSData class]]) 
    return value; 

return UIImagePNGRepresentation((UIImage *)value); 
} 

- (id)reverseTransformedValue:(id)value 
{ 
return [UIImage imageWithData:(NSData *)value]; 
} 

Trong trường hợp này dành cho iPhone, bạn có thể hoán đổi mã NSImage tại các vị trí thích hợp. Tôi chưa thử nghiệm cài đặt Mac của mình.

Tất cả những gì tôi đã làm để bật tính năng này là đặt thuộc tính hình ảnh của tôi có thể biến đổi trong mô hình dữ liệu và chỉ định tên của máy biến áp. Tôi không cần phải tự đăng ký biến áp giá trị, như bạn làm trong phương thức + khởi tạo của bạn.

+0

Cảm ơn Brad. Tôi đã thử điều này và nó đã không làm cho bất kỳ sự khác biệt, biến áp giá trị của tôi chỉ là bỏ qua. –

2

Dường như việc đăng ký máy biến áp không ảnh hưởng đến thời gian sử dụng dữ liệu cốt lõi. Tôi đã chơi với mã mẫu PhotoLocations và xóa đăng ký biến áp không có hiệu lực. Miễn là ValueTransformerName của bạn là tên của lớp của bạn và việc triển khai trình biến đổi của bạn được bao gồm cùng với mục tiêu, nó sẽ hoạt động.

Nếu không có mã thực hiện trong máy biến áp, thì mã trong máy biến áp không liên quan. Vấn đề phải ở đâu đó trong ngăn xếp dữ liệu cốt lõi, hoặc trong khai báo của máy biến áp.

+0

Tương tự ở đây! Bạn đã tìm thấy một giải pháp? – webmastx

0

Kiểm tra mã ví dụ here.

Điều này có làm những gì bạn muốn không?

@implementation UIImageToDataTransformer 


+ (BOOL)allowsReverseTransformation { 
    return YES; 
} 

+ (Class)transformedValueClass { 
    return [NSData class]; 
} 


- (id)transformedValue:(id)value { 
    NSData *data = UIImagePNGRepresentation(value); 
    return data; 
} 


- (id)reverseTransformedValue:(id)value { 
    UIImage *uiImage = [[UIImage alloc] initWithData:value]; 
    return [uiImage autorelease]; 
} 
1

Bạn cần phải đăng ký một cách rõ ràng biến áp của bạn trong thời gian chạy.

Nơi tốt để thực hiện việc này là ghi đè phương thức khởi tạo lớp trong lớp con thực thể NSManagedObject của bạn. Như đã đề cập trước đó, lỗi Core Data đã được biết đến. Dưới đây là các mã quan trọng từ mẫu mã vị trí của Apple, nó được kiểm nghiệm và hoạt động: http://developer.apple.com/library/ios/#samplecode/Locations/Introduction/Intro.html

+ (void)initialize { 
    if (self == [Event class]) { 
     UIImageToDataTransformer *transformer = [[UIImageToDataTransformer alloc] init]; 
     [NSValueTransformer setValueTransformer:transformer forName:@"UIImageToDataTransformer"]; 
    } 
} 
+0

Vâng, tôi biết điều này và tôi đang làm điều đó. –

+0

Trong trường hợp của tôi, đó chính xác là vấn đề. Bạn cũng có thể kiểm tra xem tên biến áp có khớp với tên bạn đã khai báo trong mô hình dữ liệu hay không và nếu bạn không có các đối tượng nghịch đảo của các phương thức: transformValue và reverseTransformedValue. – Lukasz