如何在Core Data中将CMTime作为Transformable属性存储?
解决Core Data Transformable存储CMTime的问题
我之前也折腾过用Core Data存CMTime这个C结构体,刚好能给你分享下可行的方案,核心是要做自定义值转换器+手动包装C对象,具体步骤如下:
1. 创建自定义NSValueTransformer子类
因为CMTime是C结构体,没法直接被默认的Transformable处理,我们需要写一个转换器来完成「CMTime ↔ NSDictionary」的转换(NSDictionary是Core Data能直接序列化的类型):
#import <CoreMedia/CoreMedia.h> #import <Foundation/Foundation.h> @interface CMTimeTransformer : NSValueTransformer @end @implementation CMTimeTransformer // 支持反向转换(从存储的字典转回CMTime) + (BOOL)allowsReverseTransformation { return YES; } // 转换后输出的类型是NSDictionary + (Class)transformedValueClass { return [NSDictionary class]; } // 将包装了CMTime的NSValue转成可存储的NSDictionary - (id)transformedValue:(id)value { if (!value || ![value isKindOfClass:[NSValue class]]) { return nil; } CMTime time = [value CMTimeValue]; // 用CoreMedia的API把CMTime转成CFDictionary,再桥接成NSDictionary CFDictionaryRef timeDict = CMTimeCopyAsDictionary(time, kCFAllocatorDefault); return (__bridge_transfer NSDictionary *)timeDict; } // 从存储的NSDictionary转回包装了CMTime的NSValue - (id)reverseTransformedValue:(id)value { if (!value || ![value isKindOfClass:[NSDictionary class]]) { // 处理非法值,返回默认的kCMTimeZero return [NSValue valueWithCMTime:kCMTimeZero]; } CMTime time = CMTimeMakeFromDictionary((__bridge CFDictionaryRef)value); return [NSValue valueWithCMTime:time]; } @end
2. 改造NSManagedObject子类的属性
Core Data的Transformable属性默认是id类型,但我们要直接用CMTime,所以需要手动实现getter和setter,把CMTime包装成NSValue(因为NSValue是id类型,能被转换器处理):
假设你的实体叫MediaEntity,对应的属性是playbackTime:
@interface MediaEntity : NSManagedObject @property (nonatomic, assign) CMTime playbackTime; @end @implementation MediaEntity // 保留@dynamic让Core Data管理底层存储 @dynamic playbackTime; - (CMTime)playbackTime { // 从Core Data取出包装后的NSValue,再转成CMTime NSValue *storedValue = [self primitiveValueForKey:@"playbackTime"]; return storedValue ? [storedValue CMTimeValue] : kCMTimeZero; } - (void)setPlaybackTime:(CMTime)playbackTime { // 把CMTime包装成NSValue再交给Core Data存储 NSValue *valueToStore = [NSValue valueWithCMTime:playbackTime]; [self setPrimitiveValue:valueToStore forKey:@"playbackTime"]; } @end
3. 注册转换器并配置Core Data模型
有两种方式让Core Data知道我们的自定义转换器:
- 代码注册:在App启动时(比如
AppDelegate的didFinishLaunchingWithOptions里)添加:[NSValueTransformer setValueTransformer:[CMTimeTransformer new] forName:@"CMTimeTransformer"]; - 可视化配置:打开Core Data模型文件,选中
playbackTime属性,在右侧的Data Model Inspector里,找到「Value Transformer」字段,输入CMTimeTransformer即可。
这样整个流程就通了:当你给playbackTime赋值CMTime时,setter把它包装成NSValue,Core Data调用转换器转成NSDictionary存储;读取时,转换器把NSDictionary转回NSValue,getter再提取出CMTime。
另外要注意处理边界情况,比如CMTime是invalid的情况,避免转换时崩溃,上面的代码里已经做了基础的空值判断~
内容的提问来源于stack exchange,提问作者Duck
相关产品推荐
相关产品推荐

